From 397ddb0e2b1e2213e473a5e5427132ef7dc2d8a0 Mon Sep 17 00:00:00 2001 From: Patrik Kernstock Date: Sat, 8 Aug 2020 20:32:53 +0100 Subject: [PATCH] Initial commit --- README.md | 14 +++ data/Dockerfiles/parsedmarc-init/Dockerfile | 8 ++ data/Dockerfiles/parsedmarc-init/start.sh | 62 +++++++++++ data/Dockerfiles/parsedmarc/Dockerfile | 11 ++ data/Dockerfiles/parsedmarc/start.sh | 3 + data/conf/nginx/site.conf | 37 +++++++ data/conf/parsedmarc/config.ini | 27 +++++ data/data/elasticsearch/.gitkeep | 0 data/data/geoipupdate/.gitkeep | 0 docker-compose.yml | 113 ++++++++++++++++++++ 10 files changed, 275 insertions(+) create mode 100644 README.md create mode 100644 data/Dockerfiles/parsedmarc-init/Dockerfile create mode 100644 data/Dockerfiles/parsedmarc-init/start.sh create mode 100644 data/Dockerfiles/parsedmarc/Dockerfile create mode 100644 data/Dockerfiles/parsedmarc/start.sh create mode 100644 data/conf/nginx/site.conf create mode 100644 data/conf/parsedmarc/config.ini create mode 100644 data/data/elasticsearch/.gitkeep create mode 100644 data/data/geoipupdate/.gitkeep create mode 100644 docker-compose.yml diff --git a/README.md b/README.md new file mode 100644 index 0000000..a1b8eba --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# parsedmarc-dockerized +**NOT FOR PRODUCTIVE USE** + +To setup: +``` +$ cd /opt/ +$ git clone https://github.com/patschi/parsedmarc-dockerzied.git +# Edit docker-compose.yml and change environment variables below for geoipupdate from maxmind. +# Edit data/conf/parsedmarc/config.ini for parsedmarc itself (and change test to False when tested!) +$ docker-compose pull +$ docker-compose up -d --build +``` + +Then the whole stack is being built, created, started and the corresponding dashboard automatically imported into Kibana. After a while you can access the Kibana dashboard with parsed information by [parsedmarc](https://github.com/domainaware/checkdmarc) under the reverse proxy with an automatically self-signed certificate at `https://IP:9999`. \ No newline at end of file diff --git a/data/Dockerfiles/parsedmarc-init/Dockerfile b/data/Dockerfiles/parsedmarc-init/Dockerfile new file mode 100644 index 0000000..3b69d14 --- /dev/null +++ b/data/Dockerfiles/parsedmarc-init/Dockerfile @@ -0,0 +1,8 @@ +FROM alpine:latest + +ADD start.sh /start.sh + +RUN apk add --no-cache curl openssl jq bash \ + && chmod +x /start.sh + +ENTRYPOINT [ "/start.sh" ] diff --git a/data/Dockerfiles/parsedmarc-init/start.sh b/data/Dockerfiles/parsedmarc-init/start.sh new file mode 100644 index 0000000..eda5c9c --- /dev/null +++ b/data/Dockerfiles/parsedmarc-init/start.sh @@ -0,0 +1,62 @@ +#!/bin/bash +set -x + +echo "## ELASTICSEARCH" +echo "Setting permissions..." +chmod g+rwx -R /usr/share/elasticsearch/data/ +chgrp 0 -R /usr/share/elasticsearch/data/ + +echo "## NGINX" +echo "Checking nginx certs..." +cd /etc/nginx/ssl/ +if [ ! -f "/etc/nginx/ssl/kibana.crt" ] || [ ! -f "/etc/nginx/ssl/kibana.key" ]; then + echo "No certs found. Generating..." + openssl req -x509 -nodes -days 365 -newkey rsa:3072 -keyout kibana.key -out kibana.crt \ + -subj "/CN=parsedmarc" -addext "subjectAltName=DNS:parsedmarc" + echo "Certs generated." +fi + +echo "## KIBANA" +if [ ! -f /etc/parsedmarc/kibana_export.ndjson ]; then + # trigger empty file to trigger below update logic. + touch /etc/parsedmarc/kibana_export.ndjson +fi +echo "Downloading dashboard from GitHub..." +rm /etc/parsedmarc/kibana_export.ndjson.tmp +curl https://raw.githubusercontent.com/domainaware/parsedmarc/master/kibana/export.ndjson \ + -o /etc/parsedmarc/kibana_export.ndjson.tmp +if [ ${?} -ne 0 ]; then + echo "Downloading kibana export failed." +else + fileNew=$(wc -c "/etc/parsedmarc/kibana_export.ndjson.tmp") # always use quoted var + fileOld=$(wc -c "/etc/parsedmarc/kibana_export.ndjson") + + if [ $fileNew -eq $fileOld ]; then + echo "File size is the same. Not proceeding." + else + echo "File size is different... updating..." + + while ! curl -s -f -I http://kibana:5601 >/dev/null; do + echo "Kibana not responding... waiting 5 secs..." + sleep 5 + done + + echo "Kibana responded. Waiting 10s, then proceeding with dashboard update..." + sleep 10 + rm /etc/parsedmarc/kibana_export.ndjson + mv /etc/parsedmarc/kibana_export.ndjson.tmp /etc/parsedmarc/kibana_export.ndjson + RES=$(curl -X POST http://kibana:5601/api/saved_objects/_import?overwrite=true \ + -H "kbn-xsrf: true" --form file=@/etc/parsedmarc/kibana_export.ndjson) + echo "Result: $RES" + if [ ${?} -ne 0 ]; then + echo "[!!!] Import might have failed. Manual check recommended." + fi + echo "Importing done." + fi +fi + +sleep 3 +# Create empty file to let other containers know that we're ready. +touch /ready +sleep infinity # or while true; do sleep 86400; done +exit 0 diff --git a/data/Dockerfiles/parsedmarc/Dockerfile b/data/Dockerfiles/parsedmarc/Dockerfile new file mode 100644 index 0000000..e3949c5 --- /dev/null +++ b/data/Dockerfiles/parsedmarc/Dockerfile @@ -0,0 +1,11 @@ +FROM pypy:3-slim + +ADD start.sh /start.sh +RUN apt-get update \ + && apt-get install -y libxslt-dev libz-dev libxml2-dev gcc libemail-outlook-message-perl \ + && pip install -U parsedmarc \ + && apt-get purge --yes gcc && apt autoremove --yes && apt-get clean \ + && rm -Rf /var/lib/{apt,dpkg}/ && rm -Rf /root/.cache/ \ + && chmod +x /start.sh + +ENTRYPOINT [ "/start.sh" ] diff --git a/data/Dockerfiles/parsedmarc/start.sh b/data/Dockerfiles/parsedmarc/start.sh new file mode 100644 index 0000000..3bdd74f --- /dev/null +++ b/data/Dockerfiles/parsedmarc/start.sh @@ -0,0 +1,3 @@ +#!/bin/sh +# Start parsedmarc +parsedmarc -c /etc/parsedmarc/config.ini diff --git a/data/conf/nginx/site.conf b/data/conf/nginx/site.conf new file mode 100644 index 0000000..f6fe264 --- /dev/null +++ b/data/conf/nginx/site.conf @@ -0,0 +1,37 @@ +server { + listen 443 ssl http2; + + server_name _ default_server; + ssl_certificate /etc/nginx/ssl/kibana.crt; + ssl_certificate_key /etc/nginx/ssl/kibana.key; + + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:15m; + ssl_session_tickets off; + + # modern configuration. tweak to your needs. + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers off; + + add_header X-Frame-Options SAMEORIGIN; + add_header X-Content-Type-Options nosniff; + + # Uncomment this next line if you are using a signed, trusted cert + #add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"; + + #auth_basic "Login required"; + #auth_basic_user_file /etc/nginx/htpasswd; + + location / { + proxy_pass http://kibana:5601; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} + +server { + listen 80; + return 301 https://$host$request_uri; +} diff --git a/data/conf/parsedmarc/config.ini b/data/conf/parsedmarc/config.ini new file mode 100644 index 0000000..a9a7705 --- /dev/null +++ b/data/conf/parsedmarc/config.ini @@ -0,0 +1,27 @@ +# See docs at: domainaware.github.io/parsedmarc/#configuration-file +### ADJUST YOUR SETTINGS +[general] +save_aggregate = True +save_forensic = True + +[imap] +# IMAP login +host = imap.example.com +port = 993 +user = dmarcresports@example.com +password = $uperSecure + +# advanced +watch = True +ssl = True + +archive_folder = Processed +delete = False + +# advanced advanced +test = True + +### NO EDIT REQURIED DOWN BELOW +[elasticsearch] +hosts = elasticsearch:9200 +ssl = False diff --git a/data/data/elasticsearch/.gitkeep b/data/data/elasticsearch/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/data/geoipupdate/.gitkeep b/data/data/geoipupdate/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..6fb37b4 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,113 @@ +version: '2.4' + +services: + parsedmarc-init: + build: + context: ./data/Dockerfiles/parsedmarc-init/ + image: parsedmarc-init + restart: always + volumes: + - ./data/conf/parsedmarc/:/etc/parsedmarc/:rw + - ./data/conf/nginx/ssl/:/etc/nginx/ssl/:rw + - ./data/data/elasticsearch:/usr/share/elasticsearch/data/:rw + networks: + - parsedmarc-network + healthcheck: + test: [ "CMD", "test", "-f", "/ready" ] + interval: 10s + timeout: 5s + retries: 9999 + start_period: 10s + + parsedmarc: + build: + context: ./data/Dockerfiles/parsedmarc/ + image: parsedmarc + volumes: + - ./data/conf/parsedmarc/:/etc/parsedmarc/ + - ./data/data/geoipupdate/:/usr/share/GeoIP:z,ro + restart: always + networks: + - parsedmarc-network + depends_on: + elasticsearch: + condition: service_healthy + + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.8.1 + environment: + - cluster.name=parsedmarc + - discovery.type=single-node + - bootstrap.memory_lock=true + - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + ulimits: + memlock: + soft: -1 + hard: -1 + volumes: + - ./data/data/elasticsearch:/usr/share/elasticsearch/data/ + restart: always + networks: + - parsedmarc-network + expose: # only expose docker-internally + - 9200 + healthcheck: + test: [ "CMD", "curl","-s" ,"-f", "http://localhost:9200/_cat/health" ] + interval: 1m + timeout: 10s + retries: 3 + start_period: 30s + depends_on: + parsedmarc-init: + condition: service_started + + kibana: + image: docker.elastic.co/kibana/kibana-oss:7.8.1 + environment: + - elasticsearch.hosts=http://elasticsearch:9200 + expose: # only expose docker-internally + - 5601 + restart: always + networks: + - parsedmarc-network + depends_on: + elasticsearch: + condition: service_healthy + healthcheck: + test: [ "CMD", "curl","-s" ,"-f", "http://localhost:5601/" ] + interval: 1m + timeout: 10s + retries: 3 + start_period: 30s + + geoipupdate: + image: maxmindinc/geoipupdate + environment: + - GEOIPUPDATE_ACCOUNT_ID=TO_BE_SET + - GEOIPUPDATE_LICENSE_KEY=TO_BE_SET + - GEOIPUPDATE_EDITION_IDS=TO_BE_SET + - GEOIPUPDATE_FREQUENCY=24 + - GEOIPUPDATE_PRESERVE_FILE_TIMES=1 + restart: always + volumes: + - ./data/data/geoipupdate/:/usr/share/GeoIP:z,rw + + nginx: + image: nginx:alpine + restart: always + ports: + - "9999:443" + volumes: + - ./data/conf/nginx/site.conf:/etc/nginx/conf.d/default.conf:ro + - ./data/conf/nginx/ssl/:/etc/nginx/ssl/:ro + networks: + - parsedmarc-network + depends_on: + kibana: + condition: service_healthy + parsedmarc-init: + condition: service_healthy + +networks: + parsedmarc-network: + driver: bridge