From 48fec8d7f1bc1da2691553444229717135bdbdb6 Mon Sep 17 00:00:00 2001 From: "dave@tiredofit.ca" Date: Fri, 5 Aug 2022 08:07:15 -0700 Subject: [PATCH] Release 7.7.0 - See CHANGELOG.md --- CHANGELOG.md | 8 + Dockerfile | 22 +- README.md | 61 +++++- install/assets/defaults/00-container | 3 + install/assets/defaults/07-firewall | 21 ++ install/assets/functions/00-container | 2 +- install/etc/cont-init.d/04-scheduling | 2 +- install/etc/cont-init.d/07-firewall | 190 ++++++++++++++++++ .../etc/services.available/03-monitoring/run | 8 + .../etc/services.available/07-firewall/run | 22 ++ zabbix_templates/zabbix_fail2ban.json | 143 +++++++++++++ 11 files changed, 477 insertions(+), 5 deletions(-) create mode 100755 install/assets/defaults/07-firewall create mode 100755 install/etc/cont-init.d/07-firewall create mode 100755 install/etc/services.available/07-firewall/run create mode 100644 zabbix_templates/zabbix_fail2ban.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ee7e7f..42b892d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 7.7.0 2022-08-05 + + ### Added + - Firewall Support - Now have the capability of either loading an iptables.rules file or using environment variables to set individual IPTables rules inside the container + - Fail2Ban Support - Along with above, embed fail2ban within the container rather than having it maintained downstream in many images. Drop your jails and filters in /etc/fail2ban/filters.d and /etc/fail2ban/jails.d + - Go 1.19.0 build chain + + ## 7.6.27 2022-07-27 ### Added diff --git a/Dockerfile b/Dockerfile index 396baf4..65485af 100644 --- a/Dockerfile +++ b/Dockerfile @@ -60,13 +60,16 @@ RUN case "$(cat /etc/os-release | grep VERSION_ID | cut -d = -f 2 | cut -d . -f apk upgrade && \ ### Add core utils apk add -t .base-rundeps \ + acl \ bash \ bc \ ${busybox_extras} \ curl \ ${doas_package} \ + fail2ban \ fts \ grep \ + iptables \ iputils \ jq \ less \ @@ -119,7 +122,7 @@ RUN case "$(cat /etc/os-release | grep VERSION_ID | cut -d = -f 2 | cut -d . -f ## Quiet down sudo echo "Set disable_coredump false" > /etc/sudo.conf && \ \ -### Build Doas + ### Build Doas if [ "$build_doas" = "true" ] ; then \ mkdir -p /usr/src/doas ; \ curl -sSL https://github.com/Duncaen/OpenDoas/archive/${DOAS_VERSION}.tar.gz | tar xfz - --strip 1 -C /usr/src/doas ; \ @@ -155,7 +158,7 @@ RUN case "$(cat /etc/os-release | grep VERSION_ID | cut -d = -f 2 | cut -d . -f chown --quiet -R zabbix:root /var/log/zabbix && \ chmod -R 770 /var/lib/zabbix/run && \ \ -### Zabbix compilation + #### Zabbix compilation mkdir -p /usr/src/zabbix && \ curl -sSL https://github.com/zabbix/zabbix/archive/${ZABBIX_VERSION}.tar.gz | tar xfz - --strip 1 -C /usr/src/zabbix && \ cd /usr/src/zabbix && \ @@ -258,6 +261,20 @@ RUN case "$(cat /etc/os-release | grep VERSION_ID | cut -d = -f 2 | cut -d . -f #go build -v -ldflags '-s -w' -o promtail ./clients/cmd/promtail && \ #mv promtail /usr/sbin && \ \ + ### Fail2ban Configuration + addgroup -g 65550 fail2ban && \ + addgroup zabbix fail2ban && \ + rm -rf /var/run/fail2ban && \ + mkdir -p /var/run/fail2ban && \ + chown -R root:fail2ban /var/run/fail2ban && \ + setfacl -d -m g:fail2ban:rwx /var/run/fail2ban && \ + find /etc/fail2ban/action.d/ -type f -not -name 'iptables*.conf' -delete && \ + rm -rf /etc/fail2ban/filter.d && \ + mkdir -p /etc/fail2ban/filter.d && \ + rm -rf /etc/fail2ban/fail2ban.d && \ + rm -rf /etc/fail2ban/jail.d/* && \ + rm -rf /etc/fail2ban/paths* && \ + \ ### Clean up mkdir -p /etc/logrotate.d && \ mkdir -p /etc/doas.d && \ @@ -266,6 +283,7 @@ RUN case "$(cat /etc/os-release | grep VERSION_ID | cut -d = -f 2 | cut -d . -f .golang-build-deps \ .zabbix-build-deps \ && \ + rm -rf /etc/*.apk.new && \ rm -rf /etc/logrotate.d/* && \ rm -rf /etc/doas.conf /etc/doas.d/* && \ rm -rf /root/.cache && \ diff --git a/README.md b/README.md index 39a76ff..63d8fce 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,8 @@ Dockerfile to build an [alpine](https://www.alpinelinux.org/) linux container im * [zabbix-agent](https://zabbix.org) (Classic and Modern) for individual container monitoring. * Scheduling via cron with other helpful tools (bash, curl, less, logrotate, nano, vim) for easier management. * Messaging ability via MSMTP enabled to send mail from container to external SMTP server. -* Logshipping capabilities +* Firewall included with capabilities of monitoring logs to block remote hosts via [Fail2ban](https://github.com/fail2ban/fail2ban) +* Logshipping capabilities to remote log analysis servers via [Fluent-Bit](https://github.com/fluent/fluent-bit) * Ability to update User ID and Group ID permissions dynamically. ## Maintainer @@ -117,8 +118,11 @@ The following directories are used for configuration and can be mapped for persi | `/etc/fluent-bit/conf.d/` | Fluent-Bit custom configuration directory | | `/etc/fluent-bit/parsers.d/` | Fluent-Bit custom parsers directory | | `/etc/zabbix/zabbix_agentd.conf.d/` | Zabbix Agent configuration directory | +| `/etc/fail2ban/filter.d` | Custom Fail2ban Filter configuration | +| `/etc/fail2ban/jail.d` | Custom Fail2ban Jail configuration | | `/var/log` | Container, Cron, Zabbix, other log files | | `/assets/cron` | Drop custom crontabs here | +| `/assets/iptables` | Drop custom IPTables rules here | ### Environment Variables @@ -327,6 +331,60 @@ Drop files in `/etc/fluent-bit/conf.d` to setup your inputs and outputs. The env | `FLUENTBIT_STORAGE_PATH` | Absolute file system path to store filesystem data buffers | `/tmp/fluentbit/storage` | | `FLUENTBIT_STORAGE_SYNC` | Synchronization mode to store data in filesystem `normal` or `full` | `normal` | +#### Firewall Options + +Included when proper capabilities are set on image is the capability to set up detailed block / allow rules via a firewall on container start. Presently only `iptables` is supported. +You must use run your containers with the following capabilities added: `NET_ADMIN`, `NET_RAW` + +| Parameter | Description | Default | +| ---------------------------- | ----------------------------------------------------------- | ------------------- | +| `CONTAINER_ENABLE_FIREWALL` | Enable Firewall Functionality | `FALSE` | +| `CONTAINER_FIREWALL_BACKEND` | What Firewall backend to use `iptables` | `iptables` | +| `FIREWALL_RULE_00` | Firewall rule to execute | | +| `FIREWALL_RULE_01` | Next firewall rule to execute | | + +One can use the `FIREWALL_RULE_XX` environment variables to pass rules to the firewall. In this example I am going to block someone from being able to access a port except if from a specific IP address: + +````bash +FIREWALL_RULE_00=-I INPUT -p tcp -m tcp -s 101.69.69.101 --dport 389 -j ACCEPT +FIREWALL_RULE_01=-I INPUT -p tcp -m tcp -s 0.0.0.0/0 --dport 389 -j DROP +```` + +##### IPTables Options + +Instead of relying on environment variables one can put a `iptables-restore` compatible ruleset below and it will be imported on container start. + +| `IPTABLES_RULES_PATH` | Path for IPTables Rules | `/assets/iptables/` | +| `IPTABLES_RULES_FILE` | IPTables Rules File to restore if exists on container start | `iptables.rules` | + + +##### Fail2Ban Options + +The container also has the capability should `CONTAINER_ENABLE_FIREWALL=TRUE` be enabled to launch Fail2ban, a process which watches logs for patterns and then blocks the remote host from connecting for a period of time. +Drop your custom jail configs as *.conf files in `/etc/fail2ban/jail.d/` and filters in `/etc/fail2ban/filter.d` for them to be parsed at startup. Note the startup delay environment variable to avoid the process failing if no log files exist from a fresh install. + +| Parameter | Description | Default | +| --------------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------- | +| `CONTAINER_ENABLE_FAIL2BAN` | Enable Firewall Functionality | `FALSE` | +| `FAIL2BAN_BACKEND` | Backend | `AUTO` | +| `FAIL2BAN_CONFIG_PATH` | Fail2ban Configuration Path | `/etc/fail2ban/` | +| `FAIL2BAN_DB_FILE` | Persistent Database File | `fail2ban.sqlite3` | +| `FAIL2BAN_DB_PATH` | Persistent Database Path | `/data/fail2ban/` | +| `FAIL2BAN_DB_PURGE_AGE` | Purge entries after how many seconds | `86400` | +| `FAIL2BAN_DB_TYPE` | DB Type `NONE`, `MEMORY`, `FILE` | `MEMORY` | +| `FAIL2BAN_IGNORE_IP` | Ignore these IPs or Ranges space seperated | `127.0.0.1/8 ::1 172.16.0.0/12 192.168.0.0/24` | +| `FAIL2BAN_IGNORE_SELF` | Ignroe Self `TRUE` `FALSE` | `TRUE` | +| `FAIL2BAN_LOG_PATH` | Fail2ban Log Path | `/var/log/fail2ban/` | +| `FAIL2BAN_LOG_FILE` | Fail2ban Log File | `fail2ban.log` | +| `FAIL2BAN_LOG_LEVEL` | Log Level `CRITICAL` `ERROR` `WARNING` `NOTICE` `INFO` `DEBUG` | `INFO` | +| `FAIL2BAN_LOG_TYPE` | Log to `FILE` or `CONSOLE` | `FILE` | +| `FAIL2BAN_MAX_RETRY` | Max times to find pattern in log over `FAIL2BAN_TIME_FIND` | `5` | +| `FAIL2BAN_STARTUP_DELAY` | Startup Delay to give a chance for monitored logs to exist or have data in seconds | `15` | +| `FAIL2BAN_TIME_BAN` | Length of time to ban in default | `10m` | +| `FAIL2BAN_TIME_FIND` | Window to base pattern matches against | `10m` | +| `FAIL2BAN_USE_DNS` | USE DNS for lookups `yes` `warn` `no` `raw` | `warn` | + + #### Permissions If you wish to change the internal id for users and groups you can set environment variables to do so. @@ -380,6 +438,7 @@ The following ports are exposed. | Port | Description | | ------- | ------------ | +| `2020` | Fluent Bit | | `10050` | Zabbix Agent | ## Developing / Overriding diff --git a/install/assets/defaults/00-container b/install/assets/defaults/00-container index d4f263b..e1afad2 100755 --- a/install/assets/defaults/00-container +++ b/install/assets/defaults/00-container @@ -5,6 +5,8 @@ CONTAINER_CUSTOM_PATH=${CONTAINER_CUSTOM_PATH:-"/assets/custom/"} CONTAINER_CUSTOM_SCRIPTS_PATH=${CONTAINER_CUSTOM_SCRIPTS_PATH:-"/assets/custom-scripts/"} CONTAINER_ENABLE_CUSTOM_BASH_PROMPT=${CONTAINER_ENABLE_CUSTOM_BASH_PROMPT:-"TRUE"} CONTAINER_ENABLE_DOCKER_SECRETS=${CONTAINER_ENABLE_DOCKER_SECRETS:-"TRUE"} +CONTAINER_ENABLE_FAIL2BAN=${CONTAINER_ENABLE_FAIL2BAN:-"FALSE"} +CONTAINER_ENABLE_FIREWALL=${CONTAINER_ENABLE_FIREWALL:-"FALSE"} CONTAINER_ENABLE_LOGROTATE=${CONTAINER_ENABLE_LOGROTATE:-"TRUE"} CONTAINER_ENABLE_LOGSHIPPING=${CONTAINER_ENABLE_LOGSHIPPING:-"FALSE"} CONTAINER_ENABLE_LOG_PREFIX=${CONTAINER_ENABLE_LOG_PREFIX:-"TRUE"} @@ -14,6 +16,7 @@ CONTAINER_ENABLE_PERMISSIONS=${CONTAINER_ENABLE_PERMISSIONS:-"TRUE"} CONTAINER_ENABLE_PROCESS_COUNTER=${CONTAINER_ENABLE_PROCESS_COUNTER:-"TRUE"} CONTAINER_ENABLE_PROCESS_HELPER=${CONTAINER_ENABLE_PROCESS_HELPER:-"TRUE"} CONTAINER_ENABLE_SCHEDULING=${CONTAINER_ENABLE_SCHEDULING:-"TRUE"} +CONTAINER_FIREWALL_BACKEND=${CONTAINER_FIREWALL_BACKEND:-"iptables"} CONTAINER_LOGSHIPPING_BACKEND=${CONTAINER_LOGSHIPPING_BACKEND:-"fluent-bit"} CONTAINER_LOG_LEVEL=${CONTAINER_LOG_LEVEL:-"NOTICE"} CONTAINER_LOG_PREFIX_DATE_FMT=${CONTAINER_LOG_PREFIX_DATE_FMT:-"%Y-%m-%d"} diff --git a/install/assets/defaults/07-firewall b/install/assets/defaults/07-firewall new file mode 100755 index 0000000..c8749f8 --- /dev/null +++ b/install/assets/defaults/07-firewall @@ -0,0 +1,21 @@ +#!/command/with-contenv bash + +IPTABLES_RULES_PATH=${IPTABLES_RULES_PATH:-"/assets/iptables/"} +IPTABLES_RULES_FILE=${IPTABLES_RULES_FILE:-"iptables.rules"} +FAIL2BAN_BACKEND=${FAIL2BAN_BACKEND:-"AUTO"} +FAIL2BAN_CONFIG_PATH=${FAIL2BAN_CONFIG_PATH:-"/etc/fail2ban/"} +FAIL2BAN_DB_FILE=${FAIL2BAN_DB_FILE:-"fail2ban.sqlite3"} +FAIL2BAN_DB_PATH=${FAIL2BAN_DB_PATH:-"/data/fail2ban/"} +FAIL2BAN_DB_PURGE_AGE=${FAIL2BAN_DB_PURGE_AGE:-"86400"} +FAIL2BAN_DB_TYPE=${FAIL2BAN_DB_TYPE:-"MEMORY"} +FAIL2BAN_IGNORE_IP=${FAIL2BAN_IGNORE_IP:-"127.0.0.1/8 ::1 172.16.0.0/12 192.168.0.0/24"} +FAIL2BAN_IGNORE_SELF=${FAIL2BAN_IGNORE_SELF:-"TRUE"} +FAIL2BAN_LOG_PATH=${FAIL2BAN_LOG_PATH:-"/var/log/fail2ban/"} +FAIL2BAN_LOG_FILE=${FAIL2BAN_LOG_FILE:-"fail2ban.log"} +FAIL2BAN_LOG_LEVEL=${FAIL2BAN_LOG_LEVEL:-"INFO"} +FAIL2BAN_LOG_TYPE=${FAIL2BAN_LOG_TYPE:-"FILE"} +FAIL2BAN_MAX_RETRY=${FAIL2BAN_MAX_RETRY:-"5"} +FAIL2BAN_STARTUP_DELAY=${FAIL2BAN_STARTUP_DELAY:-"15"} +FAIL2BAN_TIME_BAN=${FAIL2BAN_TIME_BAN:-"10m"} +FAIL2BAN_TIME_FIND=${FAIL2BAN_TIME_FIND:-"10m"} +FAIL2BAN_USE_DNS=${FAIL2BAN_USE_DNS:-"warn"} diff --git a/install/assets/functions/00-container b/install/assets/functions/00-container index 0719f75..c0d6cd9 100755 --- a/install/assets/functions/00-container +++ b/install/assets/functions/00-container @@ -994,7 +994,7 @@ showoff() { echo "H4sIAAAAAAAAA61RQRLEIAi78wpvXAq971t68CE8vgni2s7urWUGEyRBHVt7JTYzc+Ga4WD+T+Q/pm9jmQNbIZpNN9OOpGSqnA6I4jJlp1RZZ2OZUbrK3B9nxWw5VB9NiOFNCt5ta8s0kSD3suiBxOQDRh0WxSWQcbuYj9Mp4KuksKAoOVm3qlvRfq1Vl4Nj5fkvZnCsnEeFItgXAgAA" | base64 -d | gunzip echo "${is}" echo "${ir}" - echo "H4sIAAAAAAAAA1NQgAOfzOxUhdxKhfL8omx7hbDM4swShYySkoJiK3398vJyvZLMotSU/LTMEr3kRP3igvy84vwiLgD/c17OQAAAAA==" | base64 -d | gunzip + echo "H4sIAAAAAAAAA1NQgIPggvy84vwihdxUhTQglZJalpqTX5CbmleikJiXolBakJ2aWmClkFFSUlBspa9fXl6uV5JZlJqSn5ZZopecqF8M0c8FALKFIsRTAAAA" | base64 -d | gunzip echo "" } diff --git a/install/etc/cont-init.d/04-scheduling b/install/etc/cont-init.d/04-scheduling index e45ec21..ef33f16 100755 --- a/install/etc/cont-init.d/04-scheduling +++ b/install/etc/cont-init.d/04-scheduling @@ -17,7 +17,7 @@ fi # this is where we want to scan for every crontab env var and write it to its own file and leave a note where it came from or if it was part of system variables ## in the services available section is where we will parse the actual folder and then prepare the crontab right away. might need to update the bash alias to reload cron easy if var_false "${CONTAINER_ENABLE_SCHEDULING}" ; then - print_notice "Disabling Scheduling" + print_debug "Disabling Scheduling" service_stop "$(basename "$0")" else case "${CONTAINER_SCHEDULING_BACKEND,,}" in diff --git a/install/etc/cont-init.d/07-firewall b/install/etc/cont-init.d/07-firewall new file mode 100755 index 0000000..3cb7b17 --- /dev/null +++ b/install/etc/cont-init.d/07-firewall @@ -0,0 +1,190 @@ +#!/command/with-contenv bash + +source /assets/functions/00-container +prepare_service +# shellcheck disable=SC2034 +PROCESS_NAME="firewall" + +output_off +firewall_command=$(which "${CONTAINER_FIREWALL_BACKEND,,}") + +if var_true "${CONTAINER_ENABLE_FIREWALL}" ; then + print_notice "Container configured for firewall with '${CONTAINER_FIREWALL_BACKEND}'" + case "${CONTAINER_FIREWALL_BACKEND,,}" in + "iptables" ) + if [ -f "${IPTABLES_RULES_PATH}"/"${IPTABLES_RULES_FILE}" ]; then + print_notice "Found custom iptables.rules file" + silent iptables-restore "${IPTABLES_RULES_PATH}"/"${IPTABLES_RULES_FILE}" + fi + ;; + *) + print_error "Unknown firewall backend" + exit 1 + ;; + esac + + set -o posix + set -f + if printenv | grep -q "^FIREWALL_RULE" ; then + print_debug "Found existence of FIREWALL_RULE environment variables" + firewallenv=$(mktemp) + printenv | sort | grep '^FIREWALL_RULE_[0-9][0-9]*' | sed "s|FIREWALL_RULE_||g" > ${firewallenv} + cat ${firewallenv} + while IFS= read -r firewall_entry; do + rule_number="$(echo ${firewall_entry} | cut -d = -f1 )" + rule_value="$(echo ${firewall_entry} | cut -d = -f2 )" + print_debug "Adding Rule Number: ${rule_number} with to be parsed by ${CONTAINER_FIREWALL_BACKEND}" + silent "${firewall_command}" ${rule_value} + done < "${firewallenv}" + rm -rf "${firewallenv}" + set +f + unset rule_number rule_value + unset "${!FIREWALL_RULE_RULE_@}" + fi + + if var_true "${CONTAINER_ENABLE_FAIL2BAN}" ; then + print_notice "Container configured to block hosts via 'fail2ban'" + print_debug "Fail2ban: Configure Logging" + mkdir -p "${FAIL2BAN_LOG_PATH}" + touch "${FAIL2BAN_LOG_PATH}"/"${FAIL2BAN_LOG_FILE}" + + print_debug "Fail2ban: Configuring Filesystem" + if [ "${FAIL2BAN_CONFIG_PATH}" != "/etc/fail2ban/" ]; then + echo "not /etc/fail2ban" + print_debug "Fail2ban: Creating Config Dir" + mkdir -p "${FAIL2BAN_CONFIG_PATH}" + silent cp -R /etc/fail2ban/* "${FAIL2BAN_CONFIG_PATH}" + print_debug "Fail2ban: Linking Config to Persistent Storage" + rm -rf /etc/fail2ban + ln -sf "${FAIL2BAN_CONFIG_PATH}" /etc/fail2ban + fi + + mkdir -p /etc/fail2ban/filter.d + mkdir -p /etc/fail2ban/jail.d + + print_debug "Fail2ban: Creating Data Dir" + case "${FAIL2BAN_DB_TYPE,,}" in + file ) + fail2ban_db="${FAIL2BAN_DB_PATH}/${FAIL2BAN_DB_FILE}" + mkdir -p "${FAIL2BAN_DB_PATH}" + ;; + memory ) + fail2ban_db=":memory:" + ;; + none ) + fail2ban_db="None" + ;; + esac + + case "${FAIL2BAN_LOG_TYPE,,}" in + file ) + print_debug "Fail2ban: Creating Log Directory" + mkdir -p "${FAIL2BAN_LOG_PATH}" + touch "${FAIL2BAN_LOG_PATH}"/"${FAIL2BAN_LOG_FILE}" + create_logrotate fail2ban "${FAIL2BAN_LOG_PATH}"/"${FAIL2BAN_LOG_FILE}" none + ;; + console ) + FAIL2BAN_LOG_FILE="STDOUT" + ;; + esac + + print_debug "Fail2Ban: Creating Default Jail Configuration" + cat < "${FAIL2BAN_CONFIG_PATH}"/jail.conf +## Custom Generated Fail2ban jail.conf Configuration! Do not edit, instead set ENV Vars +## Last Generated on $(TZ=${TIMEZONE} date +'%Y-%m-%d %H:%M:%S %Z') + +[DEFAULT] +ignorself = ${FAIL2BAN_IGNORE_SELF} +ignoreip = ${FAIL2BAN_IGNORE_IP} +ignorecommand = +bantime = ${FAIL2BAN_TIME_BAN} +findtime = ${FAIL2BAN_TIME_FIND} +maxretry = ${FAIL2BAN_MAX_RETRY} +backend = ${FAIL2BAN_BACKEND} + +# "usedns" specifies if jails should trust hostnames in logs, +# warn when DNS lookups are performed, or ignore all hostnames in logs +# +# yes: if a hostname is encountered, a DNS lookup will be performed. +# warn: if a hostname is encountered, a DNS lookup will be performed, +# but it will be logged as a warning. +# no: if a hostname is encountered, will not be used for banning, +# but it will be logged as info. +# raw: use raw value (no hostname), allow use it for no-host filters/actions (example user) +usedns = ${FAIL2BAN_USE_DNS} + +logencoding = auto +enabled = false +mode = normal +filter = %(__name__)s[mode=%(mode)s] +destemail = root@localhost +sender = root@ +mta = sendmail +protocol = tcp +chain = +port = 0:65535 +fail2ban_agent = Fail2Ban/%(fail2ban_version)s +banaction = iptables-multiport +banaction_allports = iptables-allports +action_ = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] +action_mw = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] + %(mta)s-whois[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"] +action_mwl = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] + %(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"] +action_xarf = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] + xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath=%(logpath)s, port="%(port)s"] +action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"] + %(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"] +action_blocklist_de = blocklist_de[email="%(sender)s", service=%(filter)s, apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"] +action_badips = badips.py[category="%(__name__)s", banaction="%(banaction)s", agent="%(fail2ban_agent)s"] +action_badips_report = badips[category="%(__name__)s", agent="%(fail2ban_agent)s"] +action_abuseipdb = abuseipdb +action = %(action_)s +EOF + + print_debug "Fail2ban: Configuring main config file" + cat < "${FAIL2BAN_CONFIG_PATH}"/fail2ban.conf +## Custom Generated fail2ban.conf Configuration! Do not edit, instead set ENV Vars +## Last Generated on $(TZ=${TIMEZONE} date +'%Y-%m-%d %H:%M:%S %Z') + +[Definition] +loglevel = ${FAIL2BAN_LOG_LEVEL} +logtarget = ${FAIL2BAN_LOG_PATH}/${FAIL2BAN_LOG_FILE} +syslogsocket = auto +socket = /var/run/fail2ban/fail2ban.sock +pidfile = /var/run/fail2ban/fail2ban.pid +dbfile = ${fail2ban_db} +dbpurgeage = ${FAIL2BAN_DB_PURGE_AGE} +EOF + + if [ -d "${FAIL2BAN_CONFIG_PATH}"/jail.d ] && dir_notempty ; then + for fail2ban_file in "${FAIL2BAN_CONFIG_PATH}"/jail.d/*.conf ; do + if [ ! -d "$fail2ban_file" ] ; then + print_debug "Substituting Environment Variables for: '${fail2ban_file}'" + fail2ban_tmpfile=$(mktemp) + cp --attributes-only --preserve "${fail2ban_file}" "${fail2ban_tmpfile}" + cat "$fail2ban_file}" | envsubst > "${fail2ban_tmpfile}" && mv "${fail2ban_tmpfile}" "${fail2ban_file}" + fi + done + fi + + if var_true "${CONTAINER_ENABLE_MONITORING}" && [ "${CONTAINER_MONITORING_BACKEND,,}" = "zabbix" ]; then + cat < "${ZABBIX_CONFIG_PATH}"/"${ZABBIX_CONFIG_FILE}".d/tiredofit-fail2ban.conf +# Zabbix Fail2ban Configuration - Automatically generated based on container startup options +# Find Companion Zabbix Server Templates at https://github.com/tiredofit/docker-alpine or https://github.com/tiredofit/docker-debian +# Autoregister=fail2ban + +UserParameter=fail2ban.status[*],fail2ban-client status '$1' | grep 'Currently banned:' | grep -E -o '[0-9]+' +UserParameter=fail2ban.discovery,fail2ban-client status | grep 'Jail list:' | sed -e 's/^.*:\W\+//' -e 's/\(\(\w\|-\)\+\)/{"{#JAIL}":"\1"}/g' -e 's/.*/{"data":[\0]}/' +UserParameter=fail2ban.version,fail2ban-server -V | head -n1 | awk '{print $2}' | sed "s|v||" +EOF + fi + else + service_stop "$(basename "$0")" + fi +else + service_stop "$(basename "$0")" +fi + +output_on +liftoff diff --git a/install/etc/services.available/03-monitoring/run b/install/etc/services.available/03-monitoring/run index 974191b..99336aa 100755 --- a/install/etc/services.available/03-monitoring/run +++ b/install/etc/services.available/03-monitoring/run @@ -47,6 +47,14 @@ case "${CONTAINER_MONITORING_BACKEND}" in chown -R "${ZABBIX_USER}":root "${ZABBIX_CONFIG_PATH}" chmod -R 0755 "${ZABBIX_CONFIG_PATH}" + + if var_true "${CONTAINER_ENABLE_FIREWALL}" && var_true "${CONTAINER_ENABLE_FAIL2BAN}" ; then + while [ ! -S "/var/run/fail2ban/fail2ban.sock" ] ; do + sleep 1 + done + setfacl -m g:fail2ban:rwx /var/run/fail2ban/fail2ban.sock + fi + print_start "Starting Zabbix Agent (${zabbix_agent_type}) ${ZABBIX_VERSION}" silent s6-setuidgid "${ZABBIX_USER}" ${zabbix_command} -c "${ZABBIX_CONFIG_PATH}"/"${ZABBIX_CONFIG_FILE}" -f ;; diff --git a/install/etc/services.available/07-firewall/run b/install/etc/services.available/07-firewall/run new file mode 100755 index 0000000..f3e56be --- /dev/null +++ b/install/etc/services.available/07-firewall/run @@ -0,0 +1,22 @@ +#!/command/with-contenv bash + +source /assets/functions/00-container +PROCESS_NAME="firewall" +prepare_service defaults single + +output_off +check_container_initialized +check_service_initialized init + +liftoff + +print_debug "Sleeping for '${FAIL2BAN_STARTUP_DELAY}' seconds before starting Fail2ban to make sure logs are popualated" +sleep ${FAIL2BAN_STARTUP_DELAY} + +print_start "Starting Fail2ban" + +if [ "${FAIL2BAN_LOG_TYPE,,}" = "file" ] ; then + silent fail2ban-server -f +else + fail2ban-server -f +fi diff --git a/zabbix_templates/zabbix_fail2ban.json b/zabbix_templates/zabbix_fail2ban.json new file mode 100644 index 0000000..ed08edb --- /dev/null +++ b/zabbix_templates/zabbix_fail2ban.json @@ -0,0 +1,143 @@ +{ + "zabbix_export": { + "version": "6.2", + "date": "2022-08-04T17:17:20Z", + "template_groups": [ + { + "uuid": "a571c0d144b14fd4a87a9d9b2aa9fcd6", + "name": "Templates/Applications" + } + ], + "templates": [ + { + "uuid": "48d19098672f4e7aa7dab1942260d87d", + "template": "Fail2Ban", + "name": "Fail2Ban", + "groups": [ + { + "name": "Templates/Applications" + } + ], + "items": [ + { + "uuid": "f47a5d9d3e4949989ef6b6514e04a035", + "name": "Fail2Ban: Version", + "type": "ZABBIX_ACTIVE", + "key": "fail2ban.version", + "delay": "60m", + "history": "7d", + "trends": "0", + "value_type": "CHAR", + "tags": [ + { + "tag": "Application", + "value": "Fail2Ban" + } + ], + "triggers": [ + { + "uuid": "7bc5287a76c045f79bd0921261943f38", + "expression": "last(/Fail2Ban/fail2ban.version,#1)<>last(/Fail2Ban/fail2ban.version,#2) \nand length(last(/Fail2Ban/fail2ban.version))>0", + "name": "Fail2Ban: Version has changed (new version: { ITEM.VALUE })", + "priority": "INFO" + } + ] + }, + { + "uuid": "de416c540fd0435db1822e38c036f0d7", + "name": "Fail2Ban: Processes", + "type": "ZABBIX_ACTIVE", + "key": "proc.num[fail2ban-server]", + "history": "7d", + "description": "Tests if the server is alive", + "valuemap": { + "name": "Service state" + }, + "tags": [ + { + "tag": "Application", + "value": "Fail2Ban" + } + ], + "triggers": [ + { + "uuid": "ffa07343b51d4bf58c2b8c324c6a7a62", + "expression": "sum(/Fail2Ban/proc.num[fail2ban-server],#3)=0", + "name": "Fail2ban: Process is not running", + "priority": "AVERAGE" + } + ] + } + ], + "discovery_rules": [ + { + "uuid": "ccbd8ba7a96d47b8953af017e3b0f803", + "name": "Fail2ban: Jail Discovery", + "type": "ZABBIX_ACTIVE", + "key": "fail2ban.discovery", + "description": "Discovery of jails from fail2ban daemon.", + "item_prototypes": [ + { + "uuid": "8cc0b05211fc4278b2feb46727a4ca97", + "name": "Fail2Ban: $1 banned IPs", + "type": "ZABBIX_ACTIVE", + "key": "fail2ban.status.[{#JAIL}]", + "delay": "60", + "history": "7d", + "units": "count", + "tags": [ + { + "tag": "Application", + "value": "Fail2Ban" + } + ] + } + ], + "graph_prototypes": [ + { + "uuid": "b151e34af81548b1b92cf0a6b36cdee7", + "name": "Fail2Ban: Count of banned IPs on jail {#JAIL}", + "graph_items": [ + { + "sortorder": "1", + "color": "00C800", + "item": { + "host": "Fail2Ban", + "key": "fail2ban.status.[{#JAIL}]" + } + } + ] + } + ] + } + ], + "tags": [ + { + "tag": "Service", + "value": "Baremetal" + }, + { + "tag": "Service", + "value": "Log Analysis" + } + ], + "valuemaps": [ + { + "uuid": "249132609d114d21bf84a38a3c559bfd", + "name": "Service state", + "mappings": [ + { + "value": "0", + "newvalue": "Down" + }, + { + "value": "1", + "newvalue": "Up" + } + ] + } + ] + } + ] + } +} \ No newline at end of file