integration - continue work on storageless config for k8s and swarm

This commit is contained in:
florian 2021-09-03 22:40:37 +02:00
parent e55dff8128
commit 062fa3e78a
No known key found for this signature in database
GPG Key ID: 3D80806F12602A7C
12 changed files with 100 additions and 107 deletions

View File

@ -16,6 +16,7 @@ chmod ugo+x /opt/bunkerized-nginx/entrypoint/* /opt/bunkerized-nginx/scripts/*
chmod ugo+x /opt/bunkerized-nginx/gen/main.py
chmod ugo+x /opt/bunkerized-nginx/jobs/main.py
chmod ugo+x /opt/bunkerized-nginx/jobs/reload.py
chmod ugo+x /opt/bunkerized-nginx/jobs/certbot-*.sh
chmod 770 /opt/bunkerized-nginx
chmod 440 /opt/bunkerized-nginx/settings.json

View File

@ -6,6 +6,15 @@ import Controller
from logger import log
CONFIGS = {
"conf": "/etc/nginx",
"letsencrypt": "/etc/letsencrypt",
"http": "/http-confs",
"server": "/server-confs",
"modsec": "/modsec-confs",
"modsec-crs": "/modsec-crs-confs"
}
class Config :
def __init__(self, type, api_uri, http_port="8080") :
@ -64,12 +73,32 @@ class Config :
instance.kill("SIGHUP")
except :
ret = False
elif self.__type == Controller.Type.SWARM :
ret = self.__api_call(instances, "/reload")
elif self.__type == Controller.Type.KUBERNETES :
elif self.__type == Controller.Type.SWARM or self.__type == Controller.Type.KUBERNETES :
ret = self.__api_call(instances, "/reload")
return ret
def send(self, instances) :
ret = True
if self.__type == Controller.Type.DOCKER :
return ret
elif self.__type == Controller.Type.SWARM or self.__type == Controller.Type.KUBERNERTES :
fail = False
for name, path in CONFIGS.items() :
file = self.__tarball(path)
if not self.__api_call(instances, "/" + name, file=file) :
log("config", "ERROR", "can't send config " + name + " to instance(s)")
fail = True
file.close()
if fail :
ret = False
return ret
def __tarball(path) :
file = io.BytesIO()
with tarfile.open(mode="w:gz", fileobj=file) as tar :
tar.add(path, arcname=".")
return file
def __ping(self, instances) :
return self.__api_call(instances, "/ping")
@ -120,7 +149,7 @@ class Config :
log("config", "ERROR", "exception while waiting for bunkerized-nginx instances : " + traceback.format_exc())
return False
def __api_call(self, instances, path) :
def __api_call(self, instances, path, file=None) :
ret = True
nb = 0
urls = []
@ -146,7 +175,10 @@ class Config :
for url in urls :
req = None
try :
req = requests.post(url)
if file == None :
req = requests.post(url)
else :
req = requests.post(url, {'file': file})
except :
pass
if req and req.status_code == 200 and req.text == "ok" :

View File

@ -51,3 +51,10 @@ class Controller(ABC) :
except :
ret = False
return ret
def _send(self, instances) :
try :
ret = self._config.send(instances)
except :
ret = False
return ret

View File

@ -96,9 +96,9 @@ class IngressController(Controller.Controller) :
def process_events(self, current_env) :
self.__old_env = current_env
t_pod = Thread(target=self.__watch_pod)
t_ingress = Thread(target=self.__watch_ingress)
t_service = Thread(target=self.__watch_service)
t_pod = Thread(target=self.__watch, args=("pod",))
t_ingress = Thread(target=self.__watch, args=("ingress",))
t_service = Thread(target=self.__watch, args=("service",))
t_pod.start()
t_ingress.start()
t_service.start()
@ -106,63 +106,38 @@ class IngressController(Controller.Controller) :
t_ingress.join()
t_service.join()
def __watch_pod(self) :
def __watch(self, type) :
w = watch.Watch()
for event in w.stream(self.__api.list_pod_for_all_namespaces, label_selector="bunkerized-nginx") :
what = None
if type == "pod" :
what = self.__api.list_pod_for_all_namespaces
elif type == "ingress" :
what = self.__extensions_api.list_ingress_for_all_namespaces
elif type == "service" :
what = self.__api.list_service_for_all_namespaces
for event in w.stream(what, label_selector="bunkerized-nginx") :
self.lock.acquire()
new_env = self.get_env()
if new_env != self.__old_env :
try :
if self.gen_conf(new_env) :
self.__old_env = new_env.copy()
log("CONTROLLER", "INFO", "successfully generated new configuration")
if self.reload() :
log("controller", "INFO", "successful reload")
else :
log("controller", "ERROR", "failed reload")
except :
log("controller", "ERROR", "exception while receiving event")
self.lock.release()
def __watch_ingress(self) :
w = watch.Watch()
for event in w.stream(self.__extensions_api.list_ingress_for_all_namespaces, label_selector="bunkerized-nginx") :
self.lock.acquire()
new_env = self.get_env()
if new_env != self.__old_env :
try :
if self.gen_conf(new_env) :
self.__old_env = new_env.copy()
log("CONTROLLER", "INFO", "successfully generated new configuration")
if self.reload() :
log("controller", "INFO", "successful reload")
else :
log("controller", "ERROR", "failed reload")
except :
log("controller", "ERROR", "exception while receiving event")
self.lock.release()
def __watch_service(self) :
w = watch.Watch()
for event in w.stream(self.__api.list_service_for_all_namespaces, label_selector="bunkerized-nginx") :
self.lock.acquire()
new_env = self.get_env()
if new_env != self.__old_env :
try :
if self.gen_conf(new_env) :
self.__old_env = new_env.copy()
log("CONTROLLER", "INFO", "successfully generated new configuration")
if self.reload() :
log("controller", "INFO", "successful reload")
else :
log("controller", "ERROR", "failed reload")
except :
log("controller", "ERROR", "exception while receiving event")
if not self.gen_conf(new_env) :
raise Exception("can't generate configuration")
if not self.send() :
raise Exception("can't send configuration")
if not self.reload() :
raise Exception("can't reload configuration")
self.__old_env = new_env.copy()
log("CONTROLLER", "INFO", "successfully loaded new configuration")
except Exception as e :
log("controller", "ERROR", "error while computing new event : " + str(e))
self.lock.release()
def reload(self) :
return self._reload(self.__get_services(autoconf=True))
def send(self) :
return self._send(self.__get_services(autoconf=True))
def wait(self) :
self.lock.acquire()
try :

View File

@ -46,23 +46,24 @@ class SwarmController(Controller.Controller) :
if new_env != old_env :
self.lock.acquire()
try :
log("controller", "INFO", "generating new configuration")
if self.gen_conf(new_env) :
old_env = new_env.copy()
log("controller", "INFO", "successfully generated new configuration")
if self.reload() :
log("controller", "INFO", "successful reload")
else :
log("controller", "ERROR", "failed reload")
else :
log("controller", "ERROR", "can't generate new configuration")
except :
log("controller", "ERROR", "exception while receiving event")
if not self.gen_conf(new_env) :
raise Exception("can't generate configuration")
if not self.send() :
raise Exception("can't send configuration")
if not self.reload() :
raise Exception("can't reload configuration")
self.__old_env = new_env.copy()
log("CONTROLLER", "INFO", "successfully loaded new configuration")
except Exception as e :
log("controller", "ERROR", "error while computing new event : " + str(e))
self.lock.release()
def reload(self) :
return self._reload(self.__get_instances())
def send(self) :
return self._send(self.__get_instances())
def wait(self) :
self.lock.acquire()
try :

View File

@ -820,6 +820,7 @@ do_and_check_cmd chmod 750 /opt/bunkerized-nginx/entrypoint/*
do_and_check_cmd chmod 750 /opt/bunkerized-nginx/gen/main.py
do_and_check_cmd chmod 750 /opt/bunkerized-nginx/jobs/main.py
do_and_check_cmd chmod 750 /opt/bunkerized-nginx/jobs/reload.py
do_and_check_cmd chmod 750 /opt/bunkerized-nginx/jobs/certbot-*.sh
# Set permissions for /usr/local/bin/bunkerized-nginx
do_and_check_cmd chown root:root /usr/local/bin/bunkerized-nginx
do_and_check_cmd chmod 750 /usr/local/bin/bunkerized-nginx

View File

@ -37,31 +37,10 @@ spec:
- name: MULTISITE
value: "yes"
volumeMounts:
- name: confs
mountPath: /etc/nginx
readOnly: true
- name: letsencrypt
mountPath: /etc/letsencrypt
readOnly: true
- name: acme-challenge
mountPath: /acme-challenge
readOnly: true
- name: www
mountPath: /www
readOnly: true
volumes:
- name: confs
hostPath:
path: /shared/confs
type: Directory
- name: letsencrypt
hostPath:
path: /shared/letsencrypt
type: Directory
- name: acme-challenge
hostPath:
path: /shared/acme-challenge
type: Directory
- name: www
hostPath:
path: /shared/www
@ -108,22 +87,10 @@ spec:
- name: API_URI
value: "/ChangeMeToSomethingHardToGuess"
volumeMounts:
- name: confs
mountPath: /etc/nginx
- name: letsencrypt
mountPath: /etc/letsencrypt
- name: acme-challenge
mountPath: /acme-challenge
volumes:
- name: confs
hostPath:
path: /shared/confs
type: Directory
- name: letsencrypt
hostPath:
path: /shared/letsencrypt
type: Directory
- name: acme-challenge
hostPath:
path: /shared/acme-challenge
type: Directory

View File

@ -14,10 +14,7 @@ services:
mode: host
protocol: tcp
volumes:
- /shared/confs:/etc/nginx:ro
- /shared/www:/www:ro
- /shared/letsencrypt:/etc/letsencrypt:ro
- /shared/acme-challenge:/acme-challenge:ro
environment:
- SWARM_MODE=yes
- USE_API=yes
@ -41,9 +38,7 @@ services:
image: bunkerity/bunkerized-nginx-autoconf
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /shared/confs:/etc/nginx
- /shared/letsencrypt:/etc/letsencrypt
- /shared/acme-challenge:/acme-challenge
environment:
- SWARM_MODE=yes
- API_URI=/ChangeMeToSomethingHardToGuess # must match API_URI from nginx

View File

@ -6,7 +6,7 @@ class CertbotNew(Job) :
def __init__(self, redis_host=None, copy_cache=False, domain="", email="", staging=False) :
name = "certbot-new"
data = ["certbot", "certonly", "--webroot", "-w", "/opt/bunkerized-nginx/acme-challenge", "-n", "-d", domain, "--email", email, "--agree-tos"]
data = ["certbot", "certonly", "--manual", "--preferred-challenges=http", "--manual-auth-hook", "/opt/bunkerized-nginx/jobs/certbot-auth.sh", "--manual-cleanup-hook", "/opt/bunkerized-nginx/jobs/certbot-cleanup.sh", "-n", "-d", domain, "--email", email, "--agree-tos"]
if staging :
data.append("--staging")
type = "exec"

3
jobs/certbot-auth.sh Normal file
View File

@ -0,0 +1,3 @@
#!/bin/bash
echo $CERTBOT_VALIDATION > /opt/bunkerized-nginx/acme-challenge/.well-known/acme-challenge/$CERTBOT_TOKEN

3
jobs/certbot-cleanup.sh Normal file
View File

@ -0,0 +1,3 @@
#!/bin/bash
rm -f /opt/bunkerized-nginx/acme-challenge/.well-known/acme-challenge/$CERTBOT_TOKEN

View File

@ -41,6 +41,13 @@ api_list["^/letsencrypt$"] = function ()
return M.extract_file("/tmp/letsencrypt.tar.gz", "/etc/letsencrypt/")
end
api_list["^/acme$"] = function ()
if not M.save_file("/tmp/acme.tar.gz") then
return false
end
return M.extract_file("/tmp/acme.tar.gz", "/acme-challenge")
end
api_list["^/http$"] = function ()
if not M.save_file("/tmp/http.tar.gz") then
return false
@ -75,7 +82,7 @@ function M.save_file (name)
return false
end
form:set_timeout(1000)
file = io.open(name, "a")
file = io.open(name, "w")
while true do
local typ, res, err = form:read()
if not typ then
@ -89,6 +96,7 @@ function M.save_file (name)
file:write(res)
end
end
file:flush()
file:close()
return true
end