From ceed9048820164405f347e11a17c73d90e708539 Mon Sep 17 00:00:00 2001 From: bunkerity Date: Tue, 16 Mar 2021 17:56:24 +0100 Subject: [PATCH] road to swarm - still some mess to fix --- autoconf/AutoConf.py | 3 +++ autoconf/Config.py | 20 +++++++++++++------- autoconf/ReloadServer.py | 23 +++++++++++++++++++++++ autoconf/app.py | 12 +++++++++--- autoconf/reload.py | 19 +++++++++++++++++++ confs/global/api-temp.conf | 26 ++++++++++++++++++++++++++ confs/global/nginx-temp.conf | 9 +++++++++ entrypoint/nginx-temp.sh | 15 +++++++++++---- scripts/abusers.sh | 14 +++++++++++--- scripts/certbot-new.sh | 4 ---- scripts/certbot-renew-hook.sh | 15 +++++++++------ scripts/exit-nodes.sh | 14 +++++++++++--- scripts/geoip.sh | 14 +++++++++++--- scripts/proxies.sh | 14 +++++++++++--- scripts/referrers.sh | 14 +++++++++++--- scripts/user-agents.sh | 14 +++++++++++--- 16 files changed, 188 insertions(+), 42 deletions(-) create mode 100644 autoconf/ReloadServer.py create mode 100644 autoconf/reload.py create mode 100644 confs/global/api-temp.conf diff --git a/autoconf/AutoConf.py b/autoconf/AutoConf.py index 9d06434..d4bda1a 100644 --- a/autoconf/AutoConf.py +++ b/autoconf/AutoConf.py @@ -11,6 +11,9 @@ class AutoConf : self.__sites = {} self.__config = Config(self.__swarm, api) + def reload(self) : + return self.__config.reload(self.instances) + def pre_process(self, objs) : for instance in objs : (id, name, labels) = self.__get_infos(instance) diff --git a/autoconf/Config.py b/autoconf/Config.py index a303bd1..3ce2e32 100644 --- a/autoconf/Config.py +++ b/autoconf/Config.py @@ -92,8 +92,9 @@ class Config : # Include the server conf utils.replace_in_file("/etc/nginx/nginx.conf", "}", "include /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf;\n}") - return self.__reload(instances) + return self.reload(instances) except Exception as e : + traceback.print_exc() utils.log("[!] Error while activating config : " + str(e)) return False @@ -107,9 +108,10 @@ class Config : # Remove the include utils.replace_in_file("/etc/nginx/nginx.conf", "include /etc/nginx/" + vars["SERVER_NAME"] + "/server.conf;\n", "") - return self.__reload(instances) + return self.reload(instances) except Exception as e : + traceback.print_exc() utils.log("[!] Error while deactivating config : " + str(e)) return False @@ -127,13 +129,13 @@ class Config : utils.log("[!] Error while deactivating config : " + str(e)) return False - def __reload(self, instances) : - return self.__api(instances, "/reload") + def reload(self, instances) : + return self.__api_call(instances, "/reload") def __status(self, instances) : - return self.__api(instances, "/status") + return self.__api_call(instances, "/status") - def __api(self, instances, path) : + def __api_call(self, instances, path) : ret = True for instance_id, instance in instances.items() : # Reload the instance object just in case @@ -146,7 +148,11 @@ class Config : nodeID = task["NodeID"] taskID = task["ID"] fqdn = name + "." + nodeID + "." + taskID - req = requests.post("http://" + fqdn + ":8080" + self.__api + path) + req = False + try : + req = requests.post("http://" + fqdn + ":8080" + self.__api + path) + except : + pass if req and req.status_code == 200 : utils.log("[*] Sent reload order to instance " + fqdn + " (service.node.task)") else : diff --git a/autoconf/ReloadServer.py b/autoconf/ReloadServer.py new file mode 100644 index 0000000..344791a --- /dev/null +++ b/autoconf/ReloadServer.py @@ -0,0 +1,23 @@ +import socketserver, threading + +class ReloadServerHandler(socketserver.BaseRequestHandler): + + def handle(self) : + data = self.request.recv(512) + if not data : + return + with self.server.lock : + ret = self.server.autoconf.reload() + if ret : + self.request.sendall("ok") + else : + self.request.sendall("ko") + +def run_reload_server(autoconf, lock) : + server = socketserver.UnixStreamServer("/tmp/autoconf.pid", ReloadServerHandler) + server.autoconf = autoconf + server.lock = lock + thread = threading.Thread(target=server.serve_forever) + thread.daemon = True + thread.start() + return (server, thread) diff --git a/autoconf/app.py b/autoconf/app.py index 9fd4e6e..f0d204a 100644 --- a/autoconf/app.py +++ b/autoconf/app.py @@ -1,8 +1,9 @@ #!/usr/bin/python3 from AutoConf import AutoConf +from ReloadServer import run_reload_server import utils -import docker, os, stat, sys +import docker, os, stat, sys, select, threading # Connect to the endpoint endpoint = "/var/run/docker.sock" @@ -23,6 +24,9 @@ api = "" if swarm : api = os.getenv("API_URI") autoconf = AutoConf(swarm, api) +lock = threading.Lock() +if swarm : + (server, thread) = run_reload_server(autoconf, lock) # Get all bunkerized-nginx instances and web services created before try : @@ -35,7 +39,8 @@ except docker.errors.APIError as e : sys.exit(3) # Process them before events -autoconf.pre_process(before) +with lock : + autoconf.pre_process(before) # Process events received from Docker try : @@ -55,7 +60,8 @@ try : continue # Process the event - autoconf.process(server, event["Action"]) + with lock : + autoconf.process(server, event["Action"]) except docker.errors.APIError as e : utils.log("[!] Docker API error " + str(e)) diff --git a/autoconf/reload.py b/autoconf/reload.py new file mode 100644 index 0000000..6fe1815 --- /dev/null +++ b/autoconf/reload.py @@ -0,0 +1,19 @@ +#!/usr/bin/python3 + +import sys, socket, os + +if not os.path.exists("/tmp/autoconf.sock") : + sys.exit(1) + +try : + client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + client.connect("/tmp/autoconf.sock") + client.send("reload".encode("utf-8")) + data = client.recv(512) + client.close() + if not data or data.decode("utf-8") != "ok" : + sys.exit(3) +except Exception as e : + sys.exit(2) + +sys.exit(0) diff --git a/confs/global/api-temp.conf b/confs/global/api-temp.conf new file mode 100644 index 0000000..53f6072 --- /dev/null +++ b/confs/global/api-temp.conf @@ -0,0 +1,26 @@ + +location ~ ^/%API_URI% { + +rewrite_by_lua_block { + + local api = require "api" + local api_uri = "%API_URI%" + + if api.is_api_call(api_uri) then + ngx.header.content_type = 'text/plain' + if api.do_api_call(api_uri) then + ngx.log(ngx.WARN, "[API] API call " .. ngx.var.request_uri .. " successfull from " .. ngx.var.remote_addr) + ngx.say("ok") + else + ngx.log(ngx.WARN, "[API] API call " .. ngx.var.request_uri .. " failed from " .. ngx.var.remote_addr) + ngx.say("ko") + end + + ngx.exit(ngx.HTTP_OK) + + end + + ngx.exit(ngx.OK) +} + +} diff --git a/confs/global/nginx-temp.conf b/confs/global/nginx-temp.conf index a846019..50c50cd 100644 --- a/confs/global/nginx-temp.conf +++ b/confs/global/nginx-temp.conf @@ -1,3 +1,5 @@ +load_module /usr/lib/nginx/modules/ngx_http_lua_module.so; + daemon on; pid /tmp/nginx-temp.pid; @@ -8,12 +10,19 @@ events { } http { + proxy_temp_path /tmp/proxy_temp; + client_body_temp_path /tmp/client_temp; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + lua_package_path "/usr/local/lib/lua/?.lua;;"; server { listen 0.0.0.0:%HTTP_PORT% default_server; server_name _; location ~ ^/.well-known/acme-challenge/ { root /acme-challenge; } + %USE_API% location / { return 444; } diff --git a/entrypoint/nginx-temp.sh b/entrypoint/nginx-temp.sh index 057ec4c..4547e97 100644 --- a/entrypoint/nginx-temp.sh +++ b/entrypoint/nginx-temp.sh @@ -6,14 +6,21 @@ # load some functions . /opt/entrypoint/utils.sh -# start nginx with temp conf for let's encrypt challenges -if [ "$(has_value AUTO_LETS_ENCRYPT yes)" != "" ] ; then +# start nginx with temp conf for let's encrypt challenges and API +if [ "$(has_value AUTO_LETS_ENCRYPT yes)" != "" ] || [ "$SWARM_MODE" = "yes" ] ; then cp /opt/confs/global/nginx-temp.conf /tmp/nginx-temp.conf + cp /opt/confs/global/api-temp.conf /tmp/api.conf + if [ "$SWARM_MODE" = "yes" ] ; then + replace_in_file "/tmp/nginx-temp.conf" "%USE_API%" "include /tmp/api.conf;" + replace_in_file "/tmp/api.conf" "%API_URI%" "$API_URI" + else + replace_in_file "/tmp/nginx-temp.conf" "%USE_API%" "" + fi replace_in_file "/tmp/nginx-temp.conf" "%HTTP_PORT%" "$HTTP_PORT" nginx -c /tmp/nginx-temp.conf if [ "$?" -eq 0 ] ; then - echo "[*] Successfully started temp nginx to solve Let's Encrypt challenges" + echo "[*] Successfully started temp nginx" else - echo "[!] Can't start temp nginx to solve Let's Encrypt challenges" + echo "[!] Can't start temp nginx" fi fi diff --git a/scripts/abusers.sh b/scripts/abusers.sh index 2287f99..772d781 100755 --- a/scripts/abusers.sh +++ b/scripts/abusers.sh @@ -6,6 +6,14 @@ # copy old conf to cache cp /etc/nginx/block-abusers.conf /cache +# if we are running nginx +if [ -f /tmp/nginx.pid ] ; then + RELOAD="/usr/sbin/nginx -s reload > /dev/null 2>&1" +# if we are in autoconf +elif [ -f /tmp/autoconf.sock ] ; then + RELOAD="/opt/entrypoint/reload.py" +fi + # generate the new conf curl -s "https://iplists.firehol.org/files/firehol_abusers_30d.netset" | grep -v "^\#.*" | while read entry ; do @@ -21,8 +29,8 @@ if [ "$lines" -gt 1 ] ; then job_log "[BLACKLIST] abusers list updated ($lines entries)" # reload nginx with the new config mv /tmp/block-abusers.conf /etc/nginx/block-abusers.conf - if [ -f /tmp/nginx.pid ] ; then - /usr/sbin/nginx -s reload > /dev/null 2>&1 + if [ "$RELOAD" != "" ] ; then + $RELOAD # new config is ok : save it in the cache if [ "$?" -eq 0 ] ; then cp /etc/nginx/block-abusers.conf /cache @@ -30,7 +38,7 @@ if [ "$lines" -gt 1 ] ; then else job_log "[NGINX] failed nginx reload after abusers list update fallback to old list" cp /cache/block-abusers.conf /etc/nginx - /usr/sbin/nginx -s reload > /dev/null 2>&1 + $RELOAD fi else cp /etc/nginx/block-abusers.conf /cache diff --git a/scripts/certbot-new.sh b/scripts/certbot-new.sh index f0e69a9..6ef742d 100644 --- a/scripts/certbot-new.sh +++ b/scripts/certbot-new.sh @@ -6,8 +6,4 @@ if [ "$?" -ne 0 ] ; then exit 1 fi -# fix rights -chown -R root:nginx /etc/letsencrypt -chmod -R 740 /etc/letsencrypt -find /etc/letsencrypt -type d -exec chmod 750 {} \; exit 0 diff --git a/scripts/certbot-renew-hook.sh b/scripts/certbot-renew-hook.sh index 7e5a889..8800e76 100644 --- a/scripts/certbot-renew-hook.sh +++ b/scripts/certbot-renew-hook.sh @@ -5,14 +5,17 @@ job_log "[CERTBOT] certificates have been renewed" -# fix rights -chown -R root:nginx /etc/letsencrypt -chmod -R 740 /etc/letsencrypt -find /etc/letsencrypt -type d -exec chmod 750 {} \; +# if we are running nginx +if [ -f /tmp/nginx.pid ] ; then + RELOAD="/usr/sbin/nginx -s reload > /dev/null 2>&1" +# if we are in autoconf +elif [ -f /tmp/autoconf.sock ] ; then + RELOAD="echo reload > /tmp/autoconf.sock" +fi # reload nginx -if [ -f /tmp/nginx.pid ] ; then - /usr/sbin/nginx -s reload > /dev/null 2>&1 +if [ "$RELOAD" != "" ] ; then + $RELOAD if [ "$?" -eq 0 ] ; then job_log "[NGINX] successfull nginx reload after certbot renew" else diff --git a/scripts/exit-nodes.sh b/scripts/exit-nodes.sh index d698eea..b093686 100644 --- a/scripts/exit-nodes.sh +++ b/scripts/exit-nodes.sh @@ -6,6 +6,14 @@ # copy old conf to cache cp /etc/nginx/block-tor-exit-node.conf /cache +# if we are running nginx +if [ -f /tmp/nginx.pid ] ; then + RELOAD="/usr/sbin/nginx -s reload > /dev/null 2>&1" +# if we are in autoconf +elif [ -f /tmp/autoconf.sock ] ; then + RELOAD="/opt/entrypoint/reload.py" +fi + # generate the new conf curl -s "https://iplists.firehol.org/files/tor_exits.ipset" | grep -v "^\#.*" | while read entry ; do @@ -21,8 +29,8 @@ if [ "$lines" -gt 1 ] ; then job_log "[BLACKLIST] TOR exit node list updated ($lines entries)" # reload nginx with the new config mv /tmp/block-tor-exit-node.conf /etc/nginx/block-tor-exit-node.conf - if [ -f /tmp/nginx.pid ] ; then - /usr/sbin/nginx -s reload > /dev/null 2>&1 + if [ "$RELOAD" != "" ] ; then + $RELOAD # new config is ok : save it in the cache if [ "$?" -eq 0 ] ; then cp /etc/nginx/block-tor-exit-node.conf /cache @@ -30,7 +38,7 @@ if [ "$lines" -gt 1 ] ; then else job_log "[NGINX] failed nginx reload after TOR exit node list update fallback to old list" cp /cache/block-tor-exit-node.conf /etc/nginx - /usr/sbin/nginx -s reload > /dev/null 2>&1 + $RELOAD fi else cp /etc/nginx/block-tor-exit-node.conf /cache diff --git a/scripts/geoip.sh b/scripts/geoip.sh index 77e69b3..8105f3a 100644 --- a/scripts/geoip.sh +++ b/scripts/geoip.sh @@ -3,6 +3,14 @@ # load some functions . /opt/scripts/utils.sh +# if we are running nginx +if [ -f /tmp/nginx.pid ] ; then + RELOAD="/usr/sbin/nginx -s reload > /dev/null 2>&1" +# if we are in autoconf +elif [ -f /tmp/autoconf.sock ] ; then + RELOAD="/opt/entrypoint/reload.py" +fi + # MMDB from https://db-ip.com/db/download/ip-to-country-lite URL="https://download.db-ip.com/free/dbip-country-lite-$(date +%Y-%m).mmdb.gz" wget -O /tmp/geoip.mmdb.gz "$URL" > /dev/null 2>&1 @@ -13,8 +21,8 @@ if [ "$?" -eq 0 ] && [ -f /tmp/geoip.mmdb.gz ] ; then exit 1 fi mv /tmp/geoip.mmdb /etc/nginx - if [ -f /tmp/nginx.pid ] ; then - /usr/sbin/nginx -s reload > /dev/null 2>&1 + if [ "$RELOAD" != "" ] ; then + $RELOAD if [ "$?" -eq 0 ] ; then cp /etc/nginx/geoip.mmdb /cache job_log "[NGINX] successfull nginx reload after GeoIP DB update" @@ -22,7 +30,7 @@ if [ "$?" -eq 0 ] && [ -f /tmp/geoip.mmdb.gz ] ; then job_log "[NGINX] failed nginx reload after GeoIP DB update" if [ -f /cache/geoip.mmdb ] ; then cp /cache/geoip.mmdb /etc/nginx/geoip.mmdb - /usr/sbin/nginx -s reload > /dev/null 2>&1 + $RELOAD fi fi else diff --git a/scripts/proxies.sh b/scripts/proxies.sh index f84d114..3194fcf 100755 --- a/scripts/proxies.sh +++ b/scripts/proxies.sh @@ -6,6 +6,14 @@ # copy old conf to cache cp /etc/nginx/block-proxies.conf /cache +# if we are running nginx +if [ -f /tmp/nginx.pid ] ; then + RELOAD="/usr/sbin/nginx -s reload > /dev/null 2>&1" +# if we are in autoconf +elif [ -f /tmp/autoconf.sock ] ; then + RELOAD="/opt/entrypoint/reload.py" +fi + # generate the new conf curl -s "https://iplists.firehol.org/files/firehol_proxies.netset" | grep -v "^\#.*" | while read entry ; do @@ -21,8 +29,8 @@ if [ "$lines" -gt 1 ] ; then job_log "[BLACKLIST] proxies list updated ($lines entries)" # reload nginx with the new config mv /tmp/block-proxies.conf /etc/nginx/block-proxies.conf - if [ -f /tmp/nginx.pid ] ; then - /usr/sbin/nginx -s reload > /dev/null 2>&1 + if [ "$RELOAD" != "" ] ; then + $RELOAD # new config is ok : save it in the cache if [ "$?" -eq 0 ] ; then cp /etc/nginx/block-proxies.conf /cache @@ -30,7 +38,7 @@ if [ "$lines" -gt 1 ] ; then else job_log "[NGINX] failed nginx reload after proxies list update fallback to old list" cp /cache/block-proxies.conf /etc/nginx - /usr/sbin/nginx -s reload > /dev/null 2>&1 + $RELOAD fi else cp /etc/nginx/block-proxies.conf /cache diff --git a/scripts/referrers.sh b/scripts/referrers.sh index 070a6f0..a9aaf98 100755 --- a/scripts/referrers.sh +++ b/scripts/referrers.sh @@ -6,6 +6,14 @@ # save old conf cp /etc/nginx/map-referrer.conf /cache +# if we are running nginx +if [ -f /tmp/nginx.pid ] ; then + RELOAD="/usr/sbin/nginx -s reload > /dev/null 2>&1" +# if we are in autoconf +elif [ -f /tmp/autoconf.sock ] ; then + RELOAD="/opt/entrypoint/reload.py" +fi + # generate new conf BLACKLIST="$(curl -s https://raw.githubusercontent.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/master/_generator_lists/bad-referrers.list)" if [ "$?" -ne 0 ] ; then @@ -23,15 +31,15 @@ lines="$(wc -l /tmp/map-referrer.conf | cut -d ' ' -f 1)" if [ "$lines" -gt 1 ] ; then mv /tmp/map-referrer.conf /etc/nginx/map-referrer.conf job_log "[BLACKLIST] referrers list updated ($lines entries)" - if [ -f /tmp/nginx.pid ] ; then - /usr/sbin/nginx -s reload > /dev/null 2>&1 + if [ "$RELOAD" != "" ] ; then + $RELOAD if [ "$?" -eq 0 ] ; then cp /etc/nginx/map-referrer.conf /cache job_log "[NGINX] successfull nginx reload after referrers list update" else cp /cache/map-referrer.conf /etc/nginx job_log "[NGINX] failed nginx reload after referrers list update fallback to old list" - /usr/sbin/nginx -s reload > /dev/null 2>&1 + $RELOAD fi else cp /etc/nginx/map-referrer.conf /cache diff --git a/scripts/user-agents.sh b/scripts/user-agents.sh index b07ae1c..67853b0 100755 --- a/scripts/user-agents.sh +++ b/scripts/user-agents.sh @@ -6,6 +6,14 @@ # save old conf cp /etc/nginx/map-user-agent.conf /cache +# if we are running nginx +if [ -f /tmp/nginx.pid ] ; then + RELOAD="/usr/sbin/nginx -s reload > /dev/null 2>&1" +# if we are in autoconf +elif [ -f /tmp/autoconf.sock ] ; then + RELOAD="/opt/entrypoint/reload.py" +fi + # generate new conf BLACKLIST="$(curl -s https://raw.githubusercontent.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/master/_generator_lists/bad-user-agents.list) $(curl -s https://raw.githubusercontent.com/JayBizzle/Crawler-Detect/master/raw/Crawlers.txt)" @@ -25,15 +33,15 @@ lines="$(wc -l /tmp/map-user-agent.conf | cut -d ' ' -f 1)" if [ "$lines" -gt 1 ] ; then mv /tmp/map-user-agent.conf /etc/nginx/map-user-agent.conf job_log "[BLACKLIST] user-agent list updated ($lines entries)" - if [ -f /tmp/nginx.pid ] ; then - /usr/sbin/nginx -s reload > /dev/null 2>&1 + if [ "$RELOAD" != "" ] ; then + $RELOAD if [ "$?" -eq 0 ] ; then cp /etc/nginx/map-user-agent.conf /cache job_log "[NGINX] successfull nginx reload after user-agent list update" else cp /cache/map-user-agent.conf /etc/nginx job_log "[NGINX] failed nginx reload after user-agent list update fallback to old list" - /usr/sbin/nginx -s reload > /dev/null 2>&1 + $RELOAD fi else cp /etc/nginx/map-user-agent.conf /cache