diff --git a/Makefile b/Makefile index a5265ff86..fec004a5e 100644 --- a/Makefile +++ b/Makefile @@ -78,6 +78,7 @@ test: test.pep8 test.unit test.sh test.robot test.sh: shellcheck -x utils/lib.sh + shellcheck -x utils/filtron.sh test.pep8: pyenvinstall $(PY_ENV_ACT); ./manage.sh pep8_check diff --git a/utils/filtron.sh b/utils/filtron.sh new file mode 100755 index 000000000..f310991a0 --- /dev/null +++ b/utils/filtron.sh @@ -0,0 +1,214 @@ +#!/usr/bin/env bash +# -*- coding: utf-8; mode: sh -*- +# shellcheck disable=SC2119 + +# shellcheck source=utils/lib.sh +source "$(dirname "${BASH_SOURCE[0]}")/lib.sh" + +# ---------------------------------------------------------------------------- +# config +# ---------------------------------------------------------------------------- + +FILTRON_ETC="/etc/filtron" + +SERVICE_NAME="filtron" +SERVICE_USER="${SERVICE_NAME}" +SERVICE_HOME="/home/${SERVICE_USER}" +SERVICE_SYSTEMD_UNIT="${SYSTEMD_UNITS}/${SERVICE_NAME}.service" + +# shellcheck disable=SC2034 +SERVICE_GROUP="${SERVICE_USER}" + +GO_ENV="${SERVICE_HOME}/.go_env" +GO_PKG_URL="https://dl.google.com/go/go1.13.5.linux-amd64.tar.gz" +GO_TAR=$(basename "$GO_PKG_URL") + +# ---------------------------------------------------------------------------- +usage(){ +# ---------------------------------------------------------------------------- + + # shellcheck disable=SC1117 + cat <&1 | prefix_stdout +systemctl enable $SERVICE_NAME.service +systemctl restart $SERVICE_NAME.service +EOF + tee_stderr <&1 | prefix_stdout +systemctl status $SERVICE_NAME.service +EOF + wait_key +} + +deactivate_server () { + rst_title "De-Activate $SERVICE_NAME (service)" section + echo + tee_stderr <&1 | prefix_stdout +systemctl stop $SERVICE_NAME.service +systemctl disable $SERVICE_NAME.service +EOF + wait_key +} + +assert_user() { + rst_title "user $SERVICE_USER" section + echo + tee_stderr 1 < "$GO_ENV" <> ~/.profile +EOF +} + +remove_user() { + rst_title "Drop $SERVICE_USER HOME" section + if ask_yn "Do you really want to drop $SERVICE_USER home folder?"; then + userdel -r -f "$SERVICE_USER" + else + rst_para "Leave HOME folder $(du -sh "$SERVICE_HOME") unchanged." + fi +} + +interactive_shell(){ + echo "// exit with STRG-D" + sudo -H -u ${SERVICE_USER} -i +} + +_service_prefix="$SERVICE_USER@$(hostname) -->| " + +install_go(){ + rst_title "Install Go in user's HOME" section + + rst_para "download and install go binary .." + cache_download "${GO_PKG_URL}" "${GO_TAR}" + + tee_stderr 0.1 </dev/null && echo "Go Installation not found in PATH!?!" +which go >/dev/null && go version && echo "congratulations -- Go installation OK :)" +EOF + wait_key +} + +install_filtron() { + tee_stderr <&1 +EOF + install_template "$FILTRON_ETC/rules.json" root root 644 +} + +# ---------------------------------------------------------------------------- +main "$@" +# ---------------------------------------------------------------------------- diff --git a/utils/lib.sh b/utils/lib.sh index 66790bc5f..b5e897549 100755 --- a/utils/lib.sh +++ b/utils/lib.sh @@ -19,7 +19,7 @@ if [[ -z "$CACHE" ]]; then fi if [[ -z "$SYSTEMD_UNITS" ]]; then - SYSTEMD_UNITS="/lib/systemd/system/" + SYSTEMD_UNITS="/lib/systemd/system" fi sudo_or_exit() { @@ -253,9 +253,9 @@ install_template() { # # install_template --no-eval /etc/updatedb.conf root root 644 - local do_eval=0 + local do_eval=1 if [[ "$1" == "--no-eval" ]]; then - do_eval=1; shift + do_eval=0; shift fi local dst="${1}" local owner=${2-$(id -un)} @@ -286,6 +286,8 @@ install_template() { fi fi + mkdir -p "$(dirname "${dst}")" + if [[ -f "${dst}" ]] ; then info_msg "file ${dst} allready exists on this host" choose_one _reply "choose next step with file $dst" \ @@ -296,7 +298,7 @@ install_template() { "replace file") info_msg "install: ${template_file}" sudo -H install -v -o "${owner}" -g "${group}" -m "${chmod}" \ - "${template_file}" "${dst}" + "${template_file}" "${dst}" | prefix_stdout ;; "leave file unchanged") ;; @@ -309,7 +311,7 @@ install_template() { else info_msg "install: ${template_file}" sudo -H install -v -o "${owner}" -g "${group}" -m "${chmod}" \ - "${template_file}" "${dst}" + "${template_file}" "${dst}" | prefix_stdout fi } diff --git a/utils/templates/etc/filtron/rules.json b/utils/templates/etc/filtron/rules.json new file mode 100644 index 000000000..4a232388e --- /dev/null +++ b/utils/templates/etc/filtron/rules.json @@ -0,0 +1,56 @@ +[ + { + "name": "api limit", + "interval": 60, + "limit": 1000, + "filters": ["Path=^/api"], + "aggregations": ["Path"], + "actions": [ + {"name": "block"} + ], + "subrules": [ + { + "name": "drop put", + "interval": 60, + "limit": 100, + "filters": ["Method=PUT"], + "aggregations": ["Header:X-Forwarded-For"], + "actions": [ + {"name": "shell", + "params": {"cmd": "iptables -A INPUT -s %v -j DROP", "args": ["Header:X-Forwarded-For"]}} + ] + } + ] + }, + { + "name": "log'n'block rss", + "interval": 300, + "limit": 2500, + "filters": ["Path=^/$", "GET:format=rss"], + "actions": [ + {"name": "log"}, + {"name": "block"} + ] + }, + { + "name": "log rule", + "filters": ["Path=/"], + "actions": [ {"name": "log"} ], + "subrules": [ + { + "name": "block missing accept-language", + "filters": ["!Header:Accept-Language"], + "actions": [ + {"name": "block"} + ] + }, + { + "name": "block curl", + "filters": ["Header:User-Agent=[Cc]url"], + "actions": [ + {"name": "block"} + ] + } + ] + } +] diff --git a/utils/templates/lib/systemd/system/filtron.service b/utils/templates/lib/systemd/system/filtron.service new file mode 100644 index 000000000..fdb67731a --- /dev/null +++ b/utils/templates/lib/systemd/system/filtron.service @@ -0,0 +1,29 @@ +[Unit] + +Description=${SERVICE_NAME} +After=syslog.target +After=network.target + +[Service] + +Type=simple +User=${SERVICE_USER} +Group=${SERVICE_GROUP} +WorkingDirectory=${SERVICE_HOME} +ExecStart=${SERVICE_HOME}/go-apps/bin/filtron -rules ${FILTRON_RULES} + +Restart=always +Environment=USER=${SERVICE_USER} HOME=${SERVICE_HOME} + +# Some distributions may not support these hardening directives. If you cannot +# start the service due to an unknown option, comment out the ones not supported +# by your version of systemd. + +ProtectSystem=full +PrivateDevices=yes +PrivateTmp=yes +NoNewPrivileges=true + +[Install] + +WantedBy=multi-user.target