From 3259a1b66a92405e17d55185b3e031dcccb21396 Mon Sep 17 00:00:00 2001 From: Joao M Date: Thu, 25 Aug 2022 01:52:13 +0000 Subject: [PATCH] Add python certbot --- src/functions/__init__.py | 118 ++++++++++++++++++++++++-------------- src/main.py | 6 +- 2 files changed, 80 insertions(+), 44 deletions(-) diff --git a/src/functions/__init__.py b/src/functions/__init__.py index 154a035..c33c161 100644 --- a/src/functions/__init__.py +++ b/src/functions/__init__.py @@ -2,6 +2,8 @@ from datetime import datetime from multiprocessing import Process, Lock import subprocess import shlex +import time +import os class Functions: @staticmethod @@ -58,46 +60,6 @@ class Functions: Functions.log(source, 'error', "%s" % (e)) - - @staticmethod - def log_ts(source, level, message, lock): - if message is None or message == "": - return - - if not isinstance(message, (list, tuple)): - message = [message] - - lock.acquire() - try: - for line in message: - print("[%s] %s [%s]: %s" % (source, datetime.now().strftime("%x %X"), level, line.rstrip())) - finally: - lock.release() - - @staticmethod - def run_bash_ts(source, command, lock): - if not isinstance(command, (list, tuple)): - command = shlex.split(command) - - try: - process = subprocess.Popen(command, - shell=False, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - bufsize=-1, - universal_newlines=True) - - with process.stdout: - for line in iter(process.stdout.readline, b''): - Functions.log(source, "info", line) - - returncode = process.wait() - Functions.log(source, "info", "Return code %s" % (returncode)) - - except Exception as e: - Functions.log_ts(source, 'error', "%s" % (e), lock) - - class DaemonizeHAProxy: def __init__(self): self.process = None @@ -130,7 +92,7 @@ class DaemonizeHAProxy: universal_newlines=True) except Exception as e: - Functions.log_ts(source, 'error', "%s" % (e), lock) + Functions.log(source, 'error', "%s" % (e)) def __start(self): @@ -144,7 +106,7 @@ class DaemonizeHAProxy: Functions.log(source, "info", "Return code %s" % (returncode)) except Exception as e: - Functions.log_ts(source, 'error', "%s" % (e), lock) + Functions.log(source, 'error', "%s" % (e)) def is_alive(self): return self.thread.is_alive() @@ -157,4 +119,74 @@ class DaemonizeHAProxy: self.process.terminate() self.thread.terminate() - \ No newline at end of file + +class Certbot: + def __init__(self, certs, email): + self.certs = certs + self.email = email + + def check_certificates(self, hosts): + if self.email == "" or len(hosts) == 0: + return False + + try: + request_certs = [] + renew_certs = [] + current_time = time.time() + for host in hosts: + filename = "%s/%s.pem" % (self.certs, host) + host_arg = '-d %s' % (host) + if not os.path.exists(filename): + Functions.log("CERTBOT", "info", "Request new certificate for %s" % (host)) + request_certs.append(host_arg) + else: + creation_time = os.path.getctime(filename) + if (current_time - creation_time) // (24 * 3600) > 90: + Functions.log("CERTBOT", "info", "Request expired certificate for %s" % (host)) + request_certs.append(host_arg) + if (current_time - creation_time) // (24 * 3600) >= 45: + Functions.log("CERTBOT", "info", "Renew certificate for %s" % (host)) + renew_certs.append(host_arg) + + certbot_certonly = ('/usr/bin/certbot certonly ' + ' --standalone' + ' --preferred-challenges http' + ' --http-01-port 2080' + ' --agree-tos' + ' --issuance-timeout 90' + ' --no-eff-email' + ' --non-interactive' + ' --max-log-backups=0' + ' --post-hook "/scripts/certbot_to_haproxy.sh"' + ' %s --email %s' % (' '.join(request_certs), self.email) + ) + + ret_reload = False + if len(request_certs) > 0: + Functions.run_bash("CERTBOT", certbot_certonly, return_result=False) + ret_reload = true + + if len(renew_certs) > 0: + Functions.run_bash("CERTBOT", "/usb/bin/certbot renew", return_result=False) + ret_reload = true + + if ret_reload: + self.find_live_certificates() + + return ret_reload + except Excepton as e: + Functions.log("CERTBOT", "error", "%s" % (e)) + return False + + def merge_certificate(self, cert, key, filename): + Functions.save(filename, cert + key) + + def find_live_certificates(self): + letsencrypt_certs = "/etc/letsencrypt/live/" + for item in os.listdir(letsencrypt_certs): + path = os.path.join(letsencrypt_certs, item) + if os.path.isdir(path): + cert = Functions.load(os.path.join(path, "fullchain.pem")) + key = Functions.load(os.path.join(path, "privkey.pem")) + filename = "%s/%s.pem" % (self.certs, item) + self.merge_certificate(cert, key, filename) diff --git a/src/main.py b/src/main.py index c2749f9..17e1130 100644 --- a/src/main.py +++ b/src/main.py @@ -1,4 +1,4 @@ -from functions import Functions, DaemonizeHAProxy +from functions import Functions, DaemonizeHAProxy, Certbot from processor import ProcessorInterface import os import time @@ -25,6 +25,8 @@ def start(): haproxy = DaemonizeHAProxy() haproxy.haproxy("start") + certbot = Certbot(certs_letsencrypt, os.getenv("EASYHAPROXY_LETSENCRYPT_EMAIL")) + while True: time.sleep(10) if old_haproxy is not None: @@ -42,6 +44,8 @@ def start(): haproxy = DaemonizeHAProxy() haproxy.haproxy("reload") old_haproxy.terminate() + + certbot.check_certificates(processor_obj.get_letsencrypt_hosts()) except Exception as e: Functions.log('EASYHAPROXY', 'error', "Err: %s" % (e)) Functions.log('EASYHAPROXY', 'info', 'Heartbeat')