diff --git a/.ansible-lint b/.ansible-lint new file mode 100644 index 0000000..abcf25d --- /dev/null +++ b/.ansible-lint @@ -0,0 +1,3 @@ +skip_list: + - '306' + - '305' diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..c2372bd --- /dev/null +++ b/.travis.yml @@ -0,0 +1,21 @@ +language: python +python: + - '3.6' +sudo: required + +install: + - pip3 install ansible 'molecule[ec2]<3.0' ansible-lint boto boto3 + +script: + - ansible --version + - molecule --version + - molecule test -s aws-ec2 + +notifications: + webhooks: https://galaxy.ansible.com/api/v1/notifications/ + +env: + global: + - EC2_REGION: eu-west-1 + - secure: W4toFSCW5T+rfl56A8Hc2HSp7VDt76/aHB+PiSsL4RdOVWVLz3x5nxVxNbGzK1YtOF+S+/PPu5E+vx71slAWtzpqwd0+e2N08OfEJ27+t6fnzlXcd6SZrQTKeA6BVUNrbUhQ2yhuQsPqNMJF6CI7cG8NbBlz0XZh/lE5rlFqnAdcQhsmWIxuufNZ8zLLrYJlx2AB0iJ7LMc14iGKq6zSLXkKCiN399R8xIm1EQWY5U0Q27QcPv1jI0Qx2UVjouwnMzvHit1Ev+pH0/3Is4gQPB6iRyhqtnac0CSipudyqK0pJRXWnj/bedypAqN78oeEwwp9g4cVTdcdENnXISNIihW1+4euhc78R6ocxmqvmjjVSYYdrPHdr2NKtGV53i5BIfGbaHYe7nQZMJNVkoJgUG6jrTIonBIMw6JdM8vFqjqK7uEC/MuQXo42RU1S/eYntB7R0hcCL4jRg5k1SVnA6cfUN2VqGKtZbFl1Mp5acBC5npBFhkRMH426T/lH05DSziZjZOqkeB/q98UoeIMyPgee26Cz5VcO2fBc6Xoprk4ko0Gj/o0ebqF7ryO8OSXK5tKKc+bAtYE+9NcrhKIB8Pt33pcVfUDKkdpmjFAYm4MRHhzKuNPRvoKq6PH74vkcDWn93Y3K8M6T7PL5MnO7UjxN8LfsxbhEQ06p8ORbcwE= + - secure: gQWrRmAlzii5aCYOaUzmFVj55GTlh7DQZVEHArR+szM/G9JO4L/ZppLvwEhNyUbucXgqFLkJcFk9BnfISENw0KWI/wrHR1Pd+rPj2USY6L/o+4OdKaBOkZ8byXQ84504oT1kLOMkMomFsjDMNdxqEp6UKvjAEHrr0Pz+xVgKX9qV472jLKJe16VtYvmCN2xGsl/2sBghd08Pl1WJ+P1Vh/FWFcPlma/tLGpKHxTnXClvH8i+OIcYygcxenu1g4FB40wbr1V4w9LdtzjRp6Ss2ct/7SfDMfx3FtXHUxcQpsB23JqXp4ZVzxaoVml/LF4ke9ekS93Pd1lKTRGu6XeIMTQV4SqwJ+PLc4wqRtACA5zeBkiIbqE1r+r4tLCtbr5Ix14SRUWuoQ+KMSEpatPHKcD2EiM9xWg8H6lS50XNjjpqsBBDXPbwZw2yyHTaecDxxK9hHTuTurk389LV7p5iTvqIL3itkCwQWtERoPsRdu9zPjmoqdWfNLN70wtztO4b0P/supWA43E4TbS4qSckCSqoNYKyYPmeo6/9jjMEzJ87fT4btBrprq0J9OdQjv/H1a8JLicSKf/ed3Z6CXJHuhvzwzkCU1n8ZtlyWre+A2FzOlj8PePbUM2D6PGrYRKSTedAr6TIHf9JB3m5vGKiK/VQnqYp4Ck9hV4m7aktSzE= diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..08a8f67 --- /dev/null +++ b/.yamllint @@ -0,0 +1,36 @@ +--- +# Based on ansible-lint config +extends: default + +ignore: | + files/redirs/filebeat/filebeat.yml + +rules: + braces: + max-spaces-inside: 1 + level: error + brackets: + max-spaces-inside: 1 + level: error + colons: + max-spaces-after: -1 + level: error + commas: + max-spaces-after: -1 + level: error + comments: disable + comments-indentation: disable + document-start: disable + empty-lines: + max: 3 + level: error + hyphens: + level: error + indentation: disable + key-duplicates: enable + line-length: disable + new-line-at-end-of-file: disable + new-lines: + type: unix + trailing-spaces: disable + truthy: disable diff --git a/README.md b/README.md new file mode 100644 index 0000000..a257b1c --- /dev/null +++ b/README.md @@ -0,0 +1,63 @@ +# Ansible Role: redelk_redir + +Role that helps setting up redirectors for RedELK project. + +## Requirements + +None. + +## Role Variables + +Available variables are listed below, along with default values (see `defaults/main.yml`): + # Common packages for RedHat and Debian + common_pkgs: + - tmux + - rsync + + # pkgs for rhel + rhel_pkgs: + - "{{ 'python3-policycoreutils' if (ansible_distribution_major_version | int >= 8) else 'policycoreutils-python' }}" + - rsyslog + + debian_pkgs: + - apt-transport-https + - python3-apt + + # Configure or not the firewall on your systems + no_firewalling: true + + locale: en_US.UTF-8 + + firewall: + redir_ports: + - 80/tcp + - 443/tcp + + # Your timezone + timezone: Europe/Berlin + +## Dependencies + + - src: robertdebock.epel + - src: geerlingguy.filebeat + - src: https://github.com/DrMeosch/ansible-role-python3 + scm: git + version: master + name: drmeosch.python3 + +## Use with Ansible + +```yaml +- hosts: all + + roles: + - redelk_redir +``` + +## License + +MIT / BSD + +## Author Information + +This role was created in 2020 by DrMeosch. diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..afe6abe --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,31 @@ +--- +common_pkgs: + - tmux + - rsync + +# pkgs for rhel +rhel_pkgs: + - "{{ 'python3-policycoreutils' if (ansible_distribution_major_version | int >= 8) else 'policycoreutils-python' }}" + - rsyslog + +debian_pkgs: + - apt-transport-https + - python3-apt + +# Configure or not the firewall on your systems +no_firewalling: true + +locale: en_US.UTF-8 + +firewall: + redir_ports: + - 80/tcp + - 443/tcp + +# Your timezone +timezone: Europe/Berlin + +# default var for molecule testing +# should be overwritten in your playbook +attackscenario: default +elkserver_hosts: 127.0.0.1 diff --git a/files/redirs/VERSION b/files/redirs/VERSION new file mode 100644 index 0000000..91cfec0 --- /dev/null +++ b/files/redirs/VERSION @@ -0,0 +1 @@ +RedELK version 2 - BETA TESTING diff --git a/files/redirs/filebeat/filebeat.yml b/files/redirs/filebeat/filebeat.yml new file mode 100644 index 0000000..fbd458c --- /dev/null +++ b/files/redirs/filebeat/filebeat.yml @@ -0,0 +1,41 @@ +filebeat.prospectors: +- type: log + enabled: true + fields_under_root: true + paths: + - /var/log/haproxy.log + fields: + infralogtype: redirtraffic + redirprogram: haproxy +- type: log + enabled: true + fields_under_root: true + paths: + - /var/log/apache2/access-redelk.log + fields: + infralogtype: redirtraffic + redirprogram: apache +- type: log + enabled: true + fields_under_root: true + paths: + - /var/log/nginx/access-redelk.log + fields: + infralogtype: redirtraffic + redirprogram: nginx + +filebeat.config.modules: + path: ${path.config}/modules.d/*.yml + reload.enabled: false + +setup.template.settings: + index.number_of_shards: 3 + +name: "@@HOSTNAME@@" +fields_under_root: true +fields: + attackscenario: @@ATTACKSCENARIO@@ + +output.logstash: + hosts: ["@@HOSTANDPORT@@"] + ssl.certificate_authorities: ["/etc/filebeat/redelkCA.crt"] diff --git a/files/redirs/filebeat/redelkCA.crt b/files/redirs/filebeat/redelkCA.crt new file mode 100644 index 0000000..4f0a87a --- /dev/null +++ b/files/redirs/filebeat/redelkCA.crt @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE3zCCA8egAwIBAgIJAKfEyIy3ViWmMA0GCSqGSIb3DQEBCwUAMIGlMQswCQYD +VQQGEwJOTDEWMBQGA1UECAwNTm9vcmQtSG9sbGFuZDESMBAGA1UEBwwJQW1zdGVy +ZGFtMRYwFAYDVQQKDA1PdXRmbGFuayBCLlYuMQ8wDQYDVQQLDAZJVC1PUFMxFDAS +BgNVBAMMC291dGZsYW5rLm5sMSswKQYJKoZIhvcNAQkBFhx0b3RhbGx5bm90YXZp +cnVzQG91dGZsYW5rLm5sMB4XDTIwMDcyNDA4MzYyNFoXDTMwMDcyMjA4MzYyNFow +gaUxCzAJBgNVBAYTAk5MMRYwFAYDVQQIDA1Ob29yZC1Ib2xsYW5kMRIwEAYDVQQH +DAlBbXN0ZXJkYW0xFjAUBgNVBAoMDU91dGZsYW5rIEIuVi4xDzANBgNVBAsMBklU +LU9QUzEUMBIGA1UEAwwLb3V0ZmxhbmsubmwxKzApBgkqhkiG9w0BCQEWHHRvdGFs +bHlub3RhdmlydXNAb3V0ZmxhbmsubmwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDDehuKEIT9VKI+qEZnIY+qso8aegAXjRzPgBUOtKEdxuLeCFPOU7vv +EtBslmnuQ5HlO2Vn4LgEYS9Z/VeHpwcF9vxc4puQThRR6HtaCQ2pCULMphIvORCd +q7plmJyDPlpBDOuZXOIMbd4D0nh9mM5/eoEbob+Ej02/k4Ud1sGTrRdftcpuQBTI +VlzE26+Es2hk2CRz/7JwFlf6/xCgUM+R4XB05njPmj9Qhcu8YGP767FwiP9gQuXj +kMN3Lcr31mBqq5zXf7osb1lKkaZ3Da4aUJAFOMK2Kx7sEVOiTQ+lIRFgvCe4S9bR +VuF/3xrOMW8QecwtdhYoE1wDGhU23RhNAgMBAAGjggEOMIIBCjAdBgNVHQ4EFgQU +VMB9MrJTQmud2wpXo/WVdIbOlaUwgdoGA1UdIwSB0jCBz4AUVMB9MrJTQmud2wpX +o/WVdIbOlaWhgaukgagwgaUxCzAJBgNVBAYTAk5MMRYwFAYDVQQIDA1Ob29yZC1I +b2xsYW5kMRIwEAYDVQQHDAlBbXN0ZXJkYW0xFjAUBgNVBAoMDU91dGZsYW5rIEIu +Vi4xDzANBgNVBAsMBklULU9QUzEUMBIGA1UEAwwLb3V0ZmxhbmsubmwxKzApBgkq +hkiG9w0BCQEWHHRvdGFsbHlub3RhdmlydXNAb3V0ZmxhbmsubmyCCQCnxMiMt1Yl +pjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQC326pEIVjbn+4oZzl1 +3PU/oP7x+HIsXWBkTN8SkdhXzhBcD6zOASY/AJCoFwIpzsQP+N7mBviftVEzB+Pm +ZYtC0WeYZPrJ0aQV2rrNsC4CbAhPXUAncTt4HrQv1bKPXnH2ksi0jqI4Bcab8KU4 +hiXp8m9uaQapYQVxAbB/Yth4W7k0M0jS0A/hjFP7ysI2xat9GDe7JQWLno+anovK +9nmzJ5A+/JyJlLM/A6DpAGHCQEi8nqLq4KNbDe1rxIOePKsbCvJFpQ/xOgeCRVhq +syyQPgolUdhM3XDttDjcfDpt35oNZ6oRkqxFZhGEC6Ex9Unp4IZYZE7v0yCnDUoA +yGpm +-----END CERTIFICATE----- diff --git a/files/redirs/install-redir.sh b/files/redirs/install-redir.sh new file mode 100755 index 0000000..cb72845 --- /dev/null +++ b/files/redirs/install-redir.sh @@ -0,0 +1,190 @@ +#!/bin/sh +# +# Part of RedELK +# Script to install RedELK on redirector +# +# Author: Outflank B.V. / Marc Smeets +# + +LOGFILE="redelk-install.log" +INSTALLER="RedELK redirector installer" +TIMEZONE="Europe/Amsterdam" +ELKVERSION="6.8.2" + +#set default locale +export LC_ALL="en_US.UTF-8" +printf 'LANG=en_US.UTF-8\nLC_ALL=en_US.UTF-8\n' > /etc/default/locale >> $LOGFILE 2>&1 +locale-gen >> $LOGFILE 2>&1 + +echoerror() { + printf "`date +'%b %e %R'` $INSTALLER - ${RC} * ERROR ${EC}: $@\n" >> $LOGFILE 2>&1 +} + +preinstallcheck() { + echo "Starting pre installation checks" + + # Checking if OS is Debian / APT based + if [ ! -f /etc/debian_version ]; then + echo "[X] This system does not seem to be Debian/APT-based. RedELK installer only supports Debian/APT based systems." + echoerror "System is not Debian/APT based. Not supported. Quitting." + exit 1 + fi + + if [ -n "$(dpkg -s filebeat 2>/dev/null| grep Status)" ]; then + INSTALLEDVERSION=`dpkg -s filebeat |grep Version|awk '{print $2}'` >> $LOGFILE 2>&1 + if [ "$INSTALLEDVERSION" != "$ELKVERSION" ]; then + echo "[X] Filebeat: installed version $INSTALLEDVERSION, required version $ELKVERSION. Please fix manually." + echoerror "Filebeat version mismatch. Please fix manually." + exit 1 + else + echo "[!] Filebeat: required version is installed ($INSTALLEDVERSION). Should be good. Stopping service now before continuing installation." + service filebeat stop + ERROR=$? + if [ $ERROR -ne 0 ]; then + echoerror "Could not stop filebeat (Error Code: $ERROR)." + fi + fi + fi +} + +echo "This script will install and configure necessary components for RedELK on redirectors" +printf "`date +'%b %e %R'` $INSTALLER - Starting installer\n" > $LOGFILE 2>&1 + +if ! [ $# -eq 3 ] ; then + echo "[X] ERROR Incorrect amount of parameters" + echo "[X] require 1st parameter: identifier of this machine to set in filebeat config." + echo "[X] require 2nd parameter: attackscenario name." + echo "[X] require 3rd parameter: IP/DNS:port where to ship logs to (enter 5044 if you are using default logstash port)." + echoerror "Incorrect amount of parameters" + exit 1 +fi + +preinstallcheck + +echo "Setting timezone" +timedatectl set-timezone $TIMEZONE >> $LOGFILE 2>&1 +ERROR=$? +if [ $ERROR -ne 0 ]; then + echoerror "Could not set timezone (Error Code: $ERROR)." +fi + +echo "Restarting rsyslog deamon for new timezone to take effect" +service rsyslog restart >> $LOGFILE 2>&1 +ERROR=$? +if [ $ERROR -ne 0 ]; then + echoerror "Could not restart rsyslog deamon (Error Code: $ERROR)." +fi + +echo "Adding GPG key of Elastic" +wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add - >> $LOGFILE 2>&1 +ERROR=$? +if [ $ERROR -ne 0 ]; then + echoerror "Could not add GPG key (Error Code: $ERROR)." +fi + +echo "Installing apt-transport-https" +apt-get install -y apt-transport-https >> $LOGFILE 2>&1 +ERROR=$? +if [ $ERROR -ne 0 ]; then + echoerror "Could not install apt-transport-https (Error Code: $ERROR)." +fi + +echo "Adding Elastic APT repository" +if [ ! -f /etc/apt/sources.list.d/elastic-6.x.list ]; then + echo "deb https://artifacts.elastic.co/packages/6.x/apt stable main" | tee -a /etc/apt/sources.list.d/elastic-6.x.list >> $LOGFILE 2>&1 +fi +ERROR=$? +if [ $ERROR -ne 0 ]; then + echoerror "Could not add APT repository (Error Code: $ERROR)." +fi + +echo "Updating APT" +apt-get update >> $LOGFILE 2>&1 +ERROR=$? +if [ $ERROR -ne 0 ]; then + echoerror "Could not update APT (Error Code: $ERROR)." +fi + +echo "Installing filebeat ..." +apt-get install -y filebeat=$ELKVERSION >> $LOGFILE 2>&1 +ERROR=$? +if [ $ERROR -ne 0 ]; then + echoerror "Could not install filebeat (Error Code: $ERROR)." +fi + +echo "Setting filebeat to auto start after reboot" +systemctl enable filebeat >> $LOGFILE 2>&1 +ERROR=$? +if [ $ERROR -ne 0 ]; then + echoerror "Could not change auto boot settings (Error Code: $ERROR)." +fi + +echo "Making backup of original filebeat config" +mv /etc/filebeat/filebeat.yml /etc/filebeat/filebeat.yml.ori >> $LOGFILE 2>&1 +ERROR=$? +if [ $ERROR -ne 0 ]; then + echoerror "Could not make backup (Error Code: $ERROR)." +fi + +echo "Copying new config file" +cp ./filebeat/filebeat.yml /etc/filebeat/ >> $LOGFILE 2>&1 +ERROR=$? +if [ $ERROR -ne 0 ]; then + echoerror "Could not copy filebeat config (Error Code: $ERROR)." +fi + +echo "Copying ca file ..." +cp ./filebeat/redelkCA.crt /etc/filebeat/ >> $LOGFILE 2>&1 +ERROR=$? +if [ $ERROR -ne 0 ]; then + echoerror "Could not copy ca file (Error Code: $ERROR)." +fi + +echo "Altering hostname field in filebeat config" +sed -i s/'@@HOSTNAME@@'/$1/g /etc/filebeat/filebeat.yml >> $LOGFILE 2>&1 +ERROR=$? +if [ $ERROR -ne 0 ]; then + echoerror "Could not change hostname field in filebeat config (Error Code: $ERROR)." +fi + +echo "Altering attackscenario field in filebeat config " +sed -i s/'@@ATTACKSCENARIO@@'/$2/g /etc/filebeat/filebeat.yml >> $LOGFILE 2>&1 +ERROR=$? +if [ $ERROR -ne 0 ]; then + echoerror "Could not change attackscenario field in filebeat config (Error Code: $ERROR)." +fi + +echo "Altering log destination field in filebeat config " +sed -i s/'@@HOSTANDPORT@@'/$3/g /etc/filebeat/filebeat.yml >> $LOGFILE 2>&1 +ERROR=$? +if [ $ERROR -ne 0 ]; then + echoerror "Could not change log destination field in filebeat config (Error Code: $ERROR)." +fi + +echo "Altering logrotate settings for HAProxy - rotate weekly instead of daily" +if [ -f /etc/logrotate.d/haproxy ]; then + sed -i s/'daily'/'weekly'/g /etc/logrotate.d/haproxy >> $LOGFILE 2>&1 + ERROR=$? + if [ $ERROR -ne 0 ]; then + echoerror "Could not change logrotate settings for HAProxy (Error Code: $ERROR). " + fi +fi + +echo "Starting filebeat" +service filebeat start >> $LOGFILE 2>&1 +ERROR=$? +if [ $ERROR -ne 0 ]; then + echoerror "Could not start filebeat (Error Code: $ERROR)." +fi + +grep -i error $LOGFILE 2>&1 +ERROR=$? +if [ $ERROR -eq 0 ]; then + echo "[X] There were errors while running this installer. Manually check the log file $LOGFILE. Exiting now." + exit +fi + +echo "" +echo "" +echo "Done with setup of RedELK on redirector." +echo "" diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..301824b --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,14 @@ +--- +- name: timezone changed + # restart crond and syslog + service: + name: "{{ item }}" + state: restarted + loop: + - "{{ 'crond' if ansible_os_family == 'RedHat' else 'cron' }}" + - rsyslog + +- name: restart filebeat + service: + name: filebeat + state: restarted diff --git a/meta/main.yml b/meta/main.yml new file mode 100644 index 0000000..dca168d --- /dev/null +++ b/meta/main.yml @@ -0,0 +1,59 @@ +galaxy_info: + author: DrMeosch + description: Setup of redirectors + + # If the issue tracker for your role is not on github, uncomment the + # next line and provide a value + # issue_tracker_url: http://example.com/issue/tracker + + # Choose a valid license ID from https://spdx.org - some suggested licenses: + # - BSD-3-Clause (default) + # - MIT + # - GPL-2.0-or-later + # - GPL-3.0-only + # - Apache-2.0 + # - CC-BY-4.0 + license: MIT,BSD + + min_ansible_version: 2.8 + + # If this a Container Enabled role, provide the minimum Ansible Container version. + # min_ansible_container_version: + + # + # Provide a list of supported platforms, and for each platform a list of versions. + # If you don't wish to enumerate all versions for a particular platform, use 'all'. + # To view available platforms and versions (or releases), visit: + # https://galaxy.ansible.com/api/v1/platforms/ + # + platforms: + - name: Ubuntu + versions: + - 20.04 + - 18.04 + - 16.06 + + - name: RHEL + versions: + - 7 + - 8 + + - name: Amazon AMI + versions: + - 2 + + galaxy_tags: [] + # List tags for your role here, one per line. A tag is a keyword that describes + # and categorizes the role. Users find roles by searching for tags. Be sure to + # remove the '[]' above, if you add tags to this list. + # + # NOTE: A tag is limited to a single word comprised of alphanumeric characters. + # Maximum 20 tags per role. + +dependencies: + - src: robertdebock.epel + - src: geerlingguy.filebeat + - src: https://github.com/DrMeosch/ansible-role-python3 + scm: git + version: master + name: drmeosch.python3 diff --git a/molecule/.default/INSTALL.rst b/molecule/.default/INSTALL.rst new file mode 100644 index 0000000..d926ca2 --- /dev/null +++ b/molecule/.default/INSTALL.rst @@ -0,0 +1,22 @@ +******* +Docker driver installation guide +******* + +Requirements +============ + +* Docker Engine + +Install +======= + +Please refer to the `Virtual environment`_ documentation for installation best +practices. If not using a virtual environment, please consider passing the +widely recommended `'--user' flag`_ when invoking ``pip``. + +.. _Virtual environment: https://virtualenv.pypa.io/en/latest/ +.. _'--user' flag: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site + +.. code-block:: bash + + $ python3 -m pip install 'molecule[docker]' diff --git a/molecule/.default/converge.yml b/molecule/.default/converge.yml new file mode 100644 index 0000000..d392284 --- /dev/null +++ b/molecule/.default/converge.yml @@ -0,0 +1,7 @@ +--- +- name: Converge + hosts: all + tasks: + - name: "Include redelk.redir" + include_role: + name: "redelk.redir" diff --git a/molecule/.default/molecule.yml b/molecule/.default/molecule.yml new file mode 100644 index 0000000..6ec6a83 --- /dev/null +++ b/molecule/.default/molecule.yml @@ -0,0 +1,49 @@ +--- +dependency: + name: galaxy + options: + ignore-certs: True + ignore-errors: True + role-file: molecule/default/requirements.yml + force: false +driver: + name: docker +platforms: + - name: EL7 + image: "geerlingguy/docker-${MOLECULE_DISTRO:-centos7}-ansible:latest" + command: ${MOLECULE_DOCKER_COMMAND:-""} + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + privileged: true + pre_build_image: true + - name: EL8 + image: "geerlingguy/docker-${MOLECULE_DISTRO:-centos8}-ansible:latest" + command: ${MOLECULE_DOCKER_COMMAND:-""} + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + privileged: true + pre_build_image: true + - name: Bionic + image: "geerlingguy/docker-${MOLECULE_DISTRO:-ubuntu1804}-ansible:latest" + command: ${MOLECULE_DOCKER_COMMAND:-""} + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + privileged: true + pre_build_image: true + - name: AMZ2 + image: "geerlingguy/docker-${MOLECULE_DISTRO:-amazonlinux2}-ansible:latest" + command: ${MOLECULE_DOCKER_COMMAND:-""} + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + privileged: true + pre_build_image: true +provisioner: + name: ansible + env: + LANG: en_US.UTF-8 + LANGUAGE: en_US:en + LC_ALL: en_US.UTF-8 + playbooks: + converge: ${MOLECULE_PLAYBOOK:-converge.yml} +verifier: + name: ansible diff --git a/molecule/.default/prepare.yml b/molecule/.default/prepare.yml new file mode 100644 index 0000000..490e702 --- /dev/null +++ b/molecule/.default/prepare.yml @@ -0,0 +1,22 @@ +- name: Prepare + hosts: all + tasks: + - name: Prepare system (Debian) + apt: + name: + - gpg-agent + - tzdata + - cron + update_cache: true + cache_valid_time: 600 + when: ansible_os_family == 'Debian' + + - name: Prepare system (RedHat) + yum: + name: + - cronie + when: ansible_os_family == 'RedHat' + + - name: setup python3 + include_role: + name: "drmeosch.python3" diff --git a/molecule/.default/requirements.yml b/molecule/.default/requirements.yml new file mode 100644 index 0000000..fd6d4de --- /dev/null +++ b/molecule/.default/requirements.yml @@ -0,0 +1,12 @@ +--- +- src: robertdebock.epel + +- src: https://github.com/DrMeosch/ansible-role-python3 + scm: git + version: master + name: drmeosch.python3 + +- src: https://github.com/DrMeosch/ansible-role-docker.git + scm: git + version: add-amazon + name: geerlingguy.docker-amazon diff --git a/molecule/.default/verify.yml b/molecule/.default/verify.yml new file mode 100644 index 0000000..a82dd6f --- /dev/null +++ b/molecule/.default/verify.yml @@ -0,0 +1,9 @@ +--- +# This is an example playbook to execute Ansible tests. + +- name: Verify + hosts: all + tasks: + - name: Example assertion + assert: + that: true diff --git a/molecule/aws-ec2/converge.yml b/molecule/aws-ec2/converge.yml new file mode 100644 index 0000000..e9dcba4 --- /dev/null +++ b/molecule/aws-ec2/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: redirectors + become: true + tasks: + - name: "Include redelk.redir role" + include_role: + name: "redelk.redir" diff --git a/molecule/aws-ec2/create.yml b/molecule/aws-ec2/create.yml new file mode 100644 index 0000000..057875c --- /dev/null +++ b/molecule/aws-ec2/create.yml @@ -0,0 +1,145 @@ +--- +- name: Create + hosts: localhost + connection: local + gather_facts: false + no_log: "{{ molecule_no_log }}" + vars: + ssh_user: "ec2-user" + ssh_port: 22 + + security_group_name: molecule + security_group_description: Security group for testing Molecule + security_group_rules: + - proto: tcp + from_port: "{{ ssh_port }}" + to_port: "{{ ssh_port }}" + cidr_ip: '0.0.0.0/0' + - proto: icmp + from_port: 8 + to_port: -1 + cidr_ip: '0.0.0.0/0' + security_group_rules_egress: + - proto: -1 + from_port: 0 + to_port: 0 + cidr_ip: '0.0.0.0/0' + + keypair_name: molecule_key + keypair_path: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}/ssh_key" + tasks: + - name: Create security group + ec2_group: + name: "{{ security_group_name }}" + description: "{{ security_group_name }}" + rules: "{{ security_group_rules }}" + rules_egress: "{{ security_group_rules_egress }}" + + - name: Test for presence of local keypair + stat: + path: "{{ keypair_path }}" + register: keypair_local + + - name: Delete remote keypair + ec2_key: + name: "{{ keypair_name }}" + state: absent + when: not keypair_local.stat.exists + + - name: Create keypair + ec2_key: + name: "{{ keypair_name }}" + register: keypair + + - name: Persist the keypair + copy: + dest: "{{ keypair_path }}" + content: "{{ keypair.key.private_key }}" + mode: 0600 + when: keypair.changed + + - name: Get the ec2 ami(s) by owner and name, if image not set + ec2_ami_facts: + owners: "{{ item.image_owner }}" + filters: + name: "{{ item.image_name }}" + loop: "{{ molecule_yml.platforms }}" + when: item.image is not defined + register: ami_facts + + - name: Create molecule instance(s) + ec2: + key_name: "{{ keypair_name }}" + image: "{{ item.image + if item.image is defined + else (ami_facts.results[index].images | sort(attribute='creation_date', reverse=True))[0].image_id }}" + instance_type: "{{ item.instance_type }}" + vpc_subnet_id: "{{ item.vpc_subnet_id }}" + group: "{{ security_group_name }}" + instance_tags: "{{ item.instance_tags | combine({'instance': item.name}) + if item.instance_tags is defined + else {'instance': item.name} }}" + wait: true + assign_public_ip: true + volumes: "{{ item.volumes | default(omit) }}" + spot_price: "{{ item.spot_price | default(omit) }}" + instance_initiated_shutdown_behavior: terminate + exact_count: 1 + count_tag: + instance: "{{ item.name }}" + register: server + loop: "{{ molecule_yml.platforms }}" + loop_control: + index_var: index + async: 7200 + poll: 0 + + - name: Wait for instance(s) creation to complete + async_status: + jid: "{{ item.ansible_job_id }}" + register: ec2_jobs + until: ec2_jobs.finished + retries: 300 + with_items: "{{ server.results }}" + + # Mandatory configuration for Molecule to function. + - name: print + debug: + var: ec2_jobs.results + + - name: Populate instance config dict + set_fact: + instance_conf_dict: { + 'instance': "{{ item.instances[0].tags.instance }}", + 'address': "{{ item.instances[0].public_ip }}", + 'user': "{{ 'ubuntu' if 'ubuntu' in item.item.item.groups else ('centos' if 'centos' in item.item.item.groups else ssh_user) }}", + 'port': "{{ ssh_port }}", + 'identity_file': "{{ keypair_path }}", + 'instance_ids': "{{ item.instance_ids }}", } + with_items: "{{ ec2_jobs.results }}" + register: instance_config_dict + when: server.changed | bool + + - name: Convert instance config dict to a list + set_fact: + instance_conf: "{{ instance_config_dict.results | map(attribute='ansible_facts.instance_conf_dict') | list }}" + when: server.changed | bool + + - name: Dump instance config + copy: + content: "{{ instance_conf | to_json | from_json | molecule_to_yaml | molecule_header }}" + dest: "{{ molecule_instance_config }}" + when: server.changed | bool + + - name: Wait for SSH + wait_for: + port: "{{ ssh_port }}" + host: "{{ item.address }}" + search_regex: SSH + delay: 10 + timeout: 320 + with_items: "{{ lookup('file', molecule_instance_config) | molecule_from_yaml }}" + + - name: Wait for boot process to finish + pause: + minutes: 2 diff --git a/molecule/aws-ec2/destroy.yml b/molecule/aws-ec2/destroy.yml new file mode 100644 index 0000000..5b7a756 --- /dev/null +++ b/molecule/aws-ec2/destroy.yml @@ -0,0 +1,47 @@ +--- +- name: Destroy + hosts: localhost + connection: local + gather_facts: false + no_log: "{{ molecule_no_log }}" + tasks: + - block: + - name: Populate instance config + set_fact: + instance_conf: "{{ lookup('file', molecule_instance_config) | molecule_from_yaml }}" + skip_instances: false + rescue: + - name: Populate instance config when file missing + set_fact: + instance_conf: {} + skip_instances: true + + - name: Destroy molecule instance(s) + ec2: + state: absent + instance_ids: "{{ item.instance_ids }}" + register: server + with_items: "{{ instance_conf }}" + when: not skip_instances + async: 7200 + poll: 0 + + - name: Wait for instance(s) deletion to complete + async_status: + jid: "{{ item.ansible_job_id }}" + register: ec2_jobs + until: ec2_jobs.finished + retries: 300 + with_items: "{{ server.results }}" + + # Mandatory configuration for Molecule to function. + + - name: Populate instance config + set_fact: + instance_conf: {} + + - name: Dump instance config + copy: + content: "{{ instance_conf | to_json | from_json | molecule_to_yaml | molecule_header }}" + dest: "{{ molecule_instance_config }}" + when: server.changed | bool diff --git a/molecule/aws-ec2/molecule.yml b/molecule/aws-ec2/molecule.yml new file mode 100644 index 0000000..5120596 --- /dev/null +++ b/molecule/aws-ec2/molecule.yml @@ -0,0 +1,57 @@ +--- +dependency: + name: galaxy + options: + ignore-certs: true + ignore-errors: true + role-file: molecule/aws-ec2/requirements.yml + force: false +driver: + name: ec2 +lint: + name: yamllint + options: + config-file: .yamllint + enabled: false +platforms: + - name: bionic + image: ami-0d359437d1756caa8 + instance_type: t2.micro + vpc_subnet_id: subnet-02ebf5900b497df1e + spot_price: 0.005 + groups: + - ubuntu + - redirectors + - name: amz.2 + image: ami-076431be05aaf8080 + instance_type: t2.micro + vpc_subnet_id: subnet-02ebf5900b497df1e + spot_price: 0.005 + groups: + - ec2_user + - redirector + - name: el8 + image: ami-032025b3afcbb6b34 + instance_type: t2.micro + vpc_subnet_id: subnet-02ebf5900b497df1e + groups: + - redirectors + - centos + - name: el7 + image: ami-095e1a4d3d632d215 + instance_type: t2.micro + vpc_subnet_id: subnet-02ebf5900b497df1e + groups: + - redirectors + - centos +provisioner: + name: ansible + inventory: + links: + hosts: ../../tests/inventory/hosts + group_vars: ../../tests/inventory/group_vars/ + host_vars: ../../tests/inventory/host_vars/ + playbooks: + converge: ${MOLECULE_PLAYBOOK:-converge.yml} + lint: + name: ansible-lint diff --git a/molecule/aws-ec2/prepare.yml b/molecule/aws-ec2/prepare.yml new file mode 100644 index 0000000..2701e05 --- /dev/null +++ b/molecule/aws-ec2/prepare.yml @@ -0,0 +1,25 @@ +- name: Prepare + hosts: redirectors + become: true + tasks: + - name: Prepare system (Debian) + apt: + name: + - gpg-agent + - tzdata + - cron + - bash + - bash-completion + update_cache: true + cache_valid_time: 600 + when: ansible_os_family == 'Debian' + + - name: Prepare system (RedHat) + yum: + name: + - cronie + when: ansible_os_family == 'RedHat' + + - name: setup python3 + include_role: + name: "drmeosch.python3" diff --git a/molecule/aws-ec2/requirements.yml b/molecule/aws-ec2/requirements.yml new file mode 100644 index 0000000..b6d05bd --- /dev/null +++ b/molecule/aws-ec2/requirements.yml @@ -0,0 +1,8 @@ +--- +- src: robertdebock.epel +- src: geerlingguy.filebeat + +- src: https://github.com/DrMeosch/ansible-role-python3 + scm: git + version: master + name: drmeosch.python3 diff --git a/tasks/filebeat.yml b/tasks/filebeat.yml new file mode 100644 index 0000000..d9b5d92 --- /dev/null +++ b/tasks/filebeat.yml @@ -0,0 +1,53 @@ +--- +- name: set cwd for molecule testing + set_fact: + cwd: "" + when: cwd is not defined + +- name: check if template filebeat is in place + # need for molecule testing + shell: cat /etc/filebeat/filebeat.yml + register: fb + tags: + - molecule-idempotence-notest + changed_when: false + +- name: copying filebeat configuration file + copy: + backup: true + # force: true + dest: "/etc/filebeat/filebeat.yml" + src: "{{ cwd }}redirs/filebeat/filebeat.yml" + notify: restart filebeat + when: (fb is defined and fb.stdout.find("redirtraffic") != -1) + +- name: change name in filebeat.yml + lineinfile: + path: "/etc/filebeat/filebeat.yml" + line: 'name: "{{ inventory_hostname }}"' + regexp: '^name:\s' + state: present + notify: restart filebeat + +- name: change attackscenario in filebeat.yml + lineinfile: + regexp: '^\s\sattackscenario:\s' + line: ' attackscenario: {{ attackscenario }}' + path: "/etc/filebeat/filebeat.yml" + state: present + notify: restart filebeat + +- name: change host of elkserver in filebeat.yml + lineinfile: + regexp: '^\s\shosts:\s' + line: ' hosts: ["{{ elkserver_hosts }}"]' + path: "/etc/filebeat/filebeat.yml" + state: present + notify: restart filebeat + +- name: copy ca file for filebeat + copy: + src: "{{ cwd }}redirs/filebeat/redelkCA.crt" + dest: "/etc/filebeat/redelkCA.crt" + backup: true + notify: restart filebeat diff --git a/tasks/firewall.yml b/tasks/firewall.yml new file mode 100644 index 0000000..34c3bba --- /dev/null +++ b/tasks/firewall.yml @@ -0,0 +1,28 @@ +--- +- name: Configure firewall + block: + - name: install firewalld package + package: + name: firewalld + + - name: enable and start firewalld if needed + service: + name: firewalld + state: started + enabled: true + + - name: open ports on redirector + firewalld: + port: "{{ item }}" + state: enabled + immediate: true + permanent: true + loop: "{{ firewall.redir_ports }}" + when: + - inventory_hostname in groups['redirectors'] + when: > + (not no_firewalling | bool) + and + (ansible_distribution != "Amazon" + or + (ansible_distribution == "Amazon" and ansible_distribution_version == "2")) diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..fd36039 --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,40 @@ +--- +# Setup/install tasks. +- include_tasks: setup-RedHat.yml + when: ansible_os_family == 'RedHat' + +- include_tasks: setup-Debian.yml + when: ansible_os_family == 'Debian' + +- name: Install common packages + package: + name: "{{ pkgs }}" + state: present + +- name: include filebeat role + vars: + filebeat_create_config: false + filebeat_version: 6.x + include_role: + name: geerlingguy.filebeat + apply: + tags: + - molecule-idempotence-notest + +- name: Configure timezone + timezone: + name: "{{ timezone }}" + notify: timezone changed + +- name: set {{ locale }} as default locale + command: "localectl set-locale LANG=\"{{ locale }}\"" + when: ansible_env.LANG != locale + ignore_errors: true + tags: + - molecule-idempotence-notest + +# Configure firewall +- import_tasks: firewall.yml + +# Configure redirector +- import_tasks: filebeat.yml diff --git a/tasks/setup-Debian.yml b/tasks/setup-Debian.yml new file mode 100644 index 0000000..1c3a192 --- /dev/null +++ b/tasks/setup-Debian.yml @@ -0,0 +1,4 @@ +--- +- name: Prepare list of pkgs for all systems + set_fact: + pkgs: "{{ common_pkgs + debian_pkgs }}" diff --git a/tasks/setup-RedHat.yml b/tasks/setup-RedHat.yml new file mode 100644 index 0000000..013136b --- /dev/null +++ b/tasks/setup-RedHat.yml @@ -0,0 +1,33 @@ +--- +- name: Setup epel repository for non-Amazon boxes + include_role: + name: robertdebock.epel + when: ansible_distribution != "Amazon" + +- name: Setting up Amazon Linux 2 to use extra repositories + block: + - name: Check if epel repo is enabled + shell: "amazon-linux-extras list | grep epel" + register: epel_hint + changed_when: false + + - name: Enable epel repo + shell: "amazon-linux-extras enable epel" + when: epel_hint.stdout.find("enabled") == -1 + + - name: Check if nginx repo is enabled + shell: "amazon-linux-extras list | grep nginx" + register: nginx_hint + changed_when: false + + - name: Enable nginx repo + shell: "amazon-linux-extras enable nginx1" + when: nginx_hint.stdout.find("enabled") == -1 + + when: + - ansible_distribution == "Amazon" + - ansible_distribution_version == "2" + +- name: prepare list of pkgs + set_fact: + pkgs: "{{ common_pkgs + rhel_pkgs }}" diff --git a/tests/inventory/hosts b/tests/inventory/hosts new file mode 100644 index 0000000..9a3c9a6 --- /dev/null +++ b/tests/inventory/hosts @@ -0,0 +1,26 @@ +# Place you redirectors here alone with attackscenario var +[redirectors] + +# Your c2 servers running cobalt strike +[c2cobaltstrike] + +# Your c2 servers running poshc2 +[c2poshc2] + +# Your elkserver +[elkserver] + + +# Normally you dont wanna edit anything after this line +[c2servers] +[c2servers:children] +c2cobaltstrike +c2poshc2 + +[redirectors:vars] + +[c2cobaltstrike:vars] + +[c2poshc2:vars] + +[elkserver:vars] diff --git a/vars/main.yml b/vars/main.yml new file mode 100644 index 0000000..160e9c3 --- /dev/null +++ b/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for redelk \ No newline at end of file