diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..86c0a58 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,55 @@ +version: '3.9' + +services: + high-logstash: + image: opensearchproject/logstash-oss-with-opensearch-output-plugin:latest + command: logstash -f /pipeline.conf + volumes: + - "./pipelines/rabbitmq-stdout.conf:/pipeline.conf:ro" + networks: + - high + depends_on: + - high-transfer + + high-transfer: + image: rabbitmq:latest + volumes: + - "./rabbitmq/load-definitions.conf:/etc/rabbitmq/conf.d/20-load-definitions.conf:ro" + - "./rabbitmq/high-definitions.json:/etc/rabbitmq/definitions.json:ro" + networks: + - transfer + - high + + low-transfer: + image: rabbitmq:latest + volumes: + - "./rabbitmq/load-definitions.conf:/etc/rabbitmq/conf.d/20-load-definitions.conf:ro" + - "./rabbitmq/low-definitions.json:/etc/rabbitmq/definitions.json:ro" + - "./rabbitmq/low-plugins:/etc/rabbitmq/enabled_plugins:ro" + networks: + - transfer + - low + depends_on: + - high-transfer + + low-logstash: + image: opensearchproject/logstash-oss-with-opensearch-output-plugin:latest + command: logstash -f /pipeline.conf + volumes: + - "./pipelines/snmptrap-rabbitmq.conf:/pipeline.conf:ro" + networks: + - low + depends_on: + - low-transfer + + low-snmp-sender: + build: snmp-sender + networks: + - low + depends_on: + - low-logstash + +networks: + high: + transfer: + low: diff --git a/pipelines/rabbitmq-stdout.conf b/pipelines/rabbitmq-stdout.conf new file mode 100644 index 0000000..1825f79 --- /dev/null +++ b/pipelines/rabbitmq-stdout.conf @@ -0,0 +1,13 @@ +input { + rabbitmq { + host => "high-transfer" + queue => "to-logstash" + user => "logstash" + password => "logstash" + durable => true + } +} + +output { + stdout {} +} \ No newline at end of file diff --git a/pipelines/snmptrap-rabbitmq.conf b/pipelines/snmptrap-rabbitmq.conf new file mode 100644 index 0000000..84cbfbe --- /dev/null +++ b/pipelines/snmptrap-rabbitmq.conf @@ -0,0 +1,16 @@ +input { + snmptrap { + community => "public" + port => 162 + } +} + +output { + rabbitmq { + host => "low-transfer" + exchange => "logstash" + exchange_type => "fanout" + user => "logstash" + password => "logstash" + } +} \ No newline at end of file diff --git a/pipelines/syslog-rabbitmq.conf b/pipelines/syslog-rabbitmq.conf new file mode 100644 index 0000000..935c5b0 --- /dev/null +++ b/pipelines/syslog-rabbitmq.conf @@ -0,0 +1,13 @@ +input { + syslog {} +} + +output { + stdout {} + + rabbitmq { + host => "low-transfer" + exchange => "to-high" + exchange_type => "direct" + } +} \ No newline at end of file diff --git a/rabbitmq/high-definitions.json b/rabbitmq/high-definitions.json new file mode 100644 index 0000000..580b636 --- /dev/null +++ b/rabbitmq/high-definitions.json @@ -0,0 +1,96 @@ +{ + "bindings": [ + { + "vhost": "/", + "source": "from-low", + "destination": "to-logstash", + "destination_type": "queue", + "routing_key": "", + "arguments": {} + } + ], + "exchanges": [ + { + "name": "from-low", + "vhost": "/", + "type": "fanout", + "durable": true, + "auto_delete": false, + "internal": false, + "arguments": {} + } + ], + "global_parameters": [], + "parameters": [], + "permissions": [ + { + "configure": ".*", + "read": ".*", + "user": "guest", + "vhost": "/", + "write": ".*" + }, + { + "configure": "^to-logstash$", + "read": "^to-logstash$", + "user": "logstash", + "vhost": "/", + "write": "^$" + }, + { + "configure": "^$", + "read": "^$", + "write": "^from-low$", + "user": "shovel", + "vhost": "/" + } + ], + "policies": [], + "queues": [ + { + "name": "to-logstash", + "vhost": "/", + "durable": true, + "auto_delete": false, + "arguments": {} + } + ], + "rabbit_version": "3.11.0", + "rabbitmq_version": "3.11.0", + "topic_permissions": [], + "users": [ + { + "hashing_algorithm": "rabbit_password_hashing_sha256", + "limits": {}, + "name": "logstash", + "password_hash": "4U3iLR6025zaf1loUjUYZBqAqczafRLf5cTVy5jnSF1F1deW", + "tags": [] + }, + { + "hashing_algorithm": "rabbit_password_hashing_sha256", + "limits": {}, + "name": "shovel", + "password_hash": "Rd+zj6GaVUkJPevYVMYYrfPYRReUnYxtlsyDtvQN29VNK2va", + "tags": [] + }, + { + "hashing_algorithm": "rabbit_password_hashing_sha256", + "limits": {}, + "name": "guest", + "password_hash": "jr8pwUpOa/7R8s/DWI7lYIH7H21e5UhBFjGniiRxwyL4GvQ2", + "tags": [ + "administrator" + ] + } + ], + "vhosts": [ + { + "limits": [], + "metadata": { + "description": "Default virtual host", + "tags": [] + }, + "name": "/" + } + ] +} diff --git a/rabbitmq/load-definitions.conf b/rabbitmq/load-definitions.conf new file mode 100644 index 0000000..63de3c6 --- /dev/null +++ b/rabbitmq/load-definitions.conf @@ -0,0 +1,3 @@ +definitions.skip_if_unchanged = true +definitions.import_backend = local_filesystem +definitions.local.path = /etc/rabbitmq/definitions.json \ No newline at end of file diff --git a/rabbitmq/low-definitions.json b/rabbitmq/low-definitions.json new file mode 100644 index 0000000..850f150 --- /dev/null +++ b/rabbitmq/low-definitions.json @@ -0,0 +1,110 @@ +{ + "bindings": [ + { + "vhost": "/", + "source": "logstash", + "destination": "to-high", + "destination_type": "queue", + "routing_key": "", + "arguments": {} + } + ], + "exchanges": [ + { + "name": "logstash", + "vhost": "/", + "type": "fanout", + "durable": true, + "auto_delete": false, + "internal": false, + "arguments": {} + } + ], + "global_parameters": [], + "parameters": [ + { + "value": { + "src-uri": "amqp://shovel:shovel@localhost", + "src-queue": "to-high", + "dest-uri": "amqp://shovel:shovel@high-transfer", + "dest-exchange": "from-low", + "ack-mode": "on-confirm", + "delete-after": "never" + }, + "vhost": "/", + "component": "shovel", + "name": "shovel-low-high" + } + ], + "permissions": [ + { + "configure": ".*", + "read": ".*", + "user": "guest", + "vhost": "/", + "write": ".*" + }, + { + "configure": "^logstash$", + "read": "^$", + "user": "logstash", + "vhost": "/", + "write": "^logstash$" + }, + { + "configure": "^$", + "read": "^to-high$", + "write": "^$", + "user": "shovel", + "vhost": "/" + } + ], + "policies": [], + "queues": [ + { + "name": "to-high", + "vhost": "/", + "durable": true, + "auto_delete": false, + "arguments": {} + } + ], + "rabbit_version": "3.11.0", + "rabbitmq_version": "3.11.0", + "topic_permissions": [], + "users": [ + { + "hashing_algorithm": "rabbit_password_hashing_sha256", + "limits": {}, + "name": "logstash", + "password_hash": "xgcwpKociAT+8XH28TN8kSGyJCzdRQ7yGx07EC59uqVJDGRo", + "tags": [] + }, + { + "hashing_algorithm": "rabbit_password_hashing_sha256", + "limits": {}, + "name": "shovel", + "password_hash": "lVd8P66d7wg2DI88eFbIFry2C6uoHciL5GhacyR2LLd7YrSM", + "tags": [] + }, + { + "hashing_algorithm": "rabbit_password_hashing_sha256", + "limits": {}, + "name": "guest", + "password_hash": "V+I16wJVwnhij+/3MW7AXFkSwh41KRRRewc1rT1I2x6HEIqU", + "tags": [ + "administrator" + ] + } + ], + "vhosts": [ + { + "limits": [], + "metadata": { + "description": "Default virtual host", + "tags": [] + }, + "name": "/" + } + ] +} diff --git a/rabbitmq/low-plugins b/rabbitmq/low-plugins new file mode 100644 index 0000000..2b44bcd --- /dev/null +++ b/rabbitmq/low-plugins @@ -0,0 +1 @@ +[rabbitmq_management, rabbitmq_shovel]. \ No newline at end of file diff --git a/rabbitmq/password-hasher b/rabbitmq/password-hasher new file mode 100755 index 0000000..93b96dd --- /dev/null +++ b/rabbitmq/password-hasher @@ -0,0 +1,45 @@ +#!/bin/python + +import os +import argparse +from hashlib import sha256 +from base64 import b64encode, b64decode +from binascii import hexlify + +def generate_hash(password, salt=None): + if salt is None: + salt = os.urandom(4) + + salted = salt + password.encode('utf-8') + hashed = salt + sha256(salted).digest() + return b64encode(hashed).decode('utf-8') + +def test_hash(hashed, password, expected_salt=None): + hash_bytes = b64decode(hashed) + salt = hash_bytes[0:4] + + if expected_salt is not None and salt != expected_salt: + return f'Hash {hexlify(hash_bytes)} with salt {hexlify(salt)} does not match expected salt {hexlify(expected_salt)}' + + if generate_hash(password, salt) == hashed: + return f'Password matches hash' + else: + return f'Password does not match hash' + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Tool for hashing user passwords that can be added in RabbitMQ config files.') + parser.add_argument('password', type=str, help='The password to hash or test against') + parser.add_argument('-s', '--salt', dest='salt', type=str, help='Use a given salt instead of generatinga random one. If used with the --test argument, it verifies that the hash used this salt') + parser.add_argument('-t', '--test', metavar='HASH', dest='test', type=str, help='Instead of hashing a password, check if a password matches a hash') + args = parser.parse_args() + + if args.salt: + salt = bytes.fromhex(args.salt) + else: + salt = None + + if args.test: + print(test_hash(args.test, args.password, salt)) + else: + print(generate_hash(args.password, salt)) diff --git a/snmp-sender/Dockerfile b/snmp-sender/Dockerfile new file mode 100644 index 0000000..08cc371 --- /dev/null +++ b/snmp-sender/Dockerfile @@ -0,0 +1,8 @@ +FROM debian:latest + +RUN apt-get update +RUN apt-get install --yes snmp + +COPY main.sh /main.sh + +CMD "/main.sh" diff --git a/snmp-sender/main.sh b/snmp-sender/main.sh new file mode 100755 index 0000000..9dcf6f3 --- /dev/null +++ b/snmp-sender/main.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +while true; do + echo "Sending trap" + + snmptrap -c public -v 2c low-logstash "" 1.3.6.1.2.1.1.5.0 + + sleep 1 +done