Skip to content

Instantly share code, notes, and snippets.

@jh0ker
Created December 18, 2016 07:18
Show Gist options
  • Save jh0ker/f1a735e152c2d4a96fd13bb5d40d203f to your computer and use it in GitHub Desktop.
Save jh0ker/f1a735e152c2d4a96fd13bb5d40d203f to your computer and use it in GitHub Desktop.
Python 3.5 - Script to check letsencrypt certificates for all domains, renew them if required, concatenate them into bundles and restart haproxy
from os import listdir, system
from os.path import join
from subprocess import run, PIPE
import logging
import re
from datetime import datetime, timedelta
logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s',
level=logging.INFO,
filename='/root/renew_certificates.log',
filemode='w')
BASE_DIR = '/etc/letsencrypt/live'
CERT_FILE = 'fullchain.pem'
KEY_FILE = 'privkey.pem'
COMBINED_FILE = 'cert_key.pem'
DOMAINS = listdir(BASE_DIR)
def certificate_expires_soon(domain):
try:
logging.info('Testing certificate for domain "%s"', domain)
cmd = ['openssl', 'x509', '-in', join(BASE_DIR, domain, CERT_FILE), '-text', '-noout']
openssl_out = run(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
if openssl_out.returncode is not 0:
logging.error(
'Command "%s" failed with return code %d', ' '.join(cmd), openssl_out.returncode)
logging.error('Captured stdout: %s', openssl_out.stdout)
logging.error('Captured stderr: %s', openssl_out.stderr)
sys.exit(1)
valid_until, = re.match(
r'.*Not After : (.*?)\n.*', openssl_out.stdout, flags=re.DOTALL).groups()
valid_until = datetime.strptime(valid_until, '%b %d %H:%M:%S %Y %Z')
time_left = valid_until - datetime.now()
logging.info('Valid until: %s', valid_until)
logging.info('Time left: %s', time_left)
logging.info('Requires renewal: %s', time_left < timedelta(days=1))
return time_left < timedelta(days=1)
except:
logging.exception('Testing certificate for domain "%s" failed!', domain)
sys.exit(1)
if any(certificate_expires_soon(domain) for domain in DOMAINS):
logging.info('At least one certificate is about to expire')
# Renew certificate
cmd = ['letsencrypt', 'renew', '--agree-tos']
logging.info('Executing "%s"', ' '.join(cmd))
letsencrypt_out = run(cmd, universal_newlines=True)
if letsencrypt_out.returncode is not 0:
logging.error(
'Command "%s" failed with return code %d', ' '.join(cmd), letsencrypt_out.returncode)
sys.exit(1)
for domain in DOMAINS:
# Generate combined file for haproxy
cmd = 'cat %s %s > %s' % (
join(BASE_DIR, domain, CERT_FILE),
join(BASE_DIR, domain, KEY_FILE),
join(BASE_DIR, domain, COMBINED_FILE))
logging.info('Executing "%s"', cmd)
returncode = system(cmd)
if returncode is not 0:
logging.error('Command "%s" failed with return code %d', cmd, returncode)
sys.exit(1)
# Restart haproxy
cmd = ['service', 'haproxy', 'restart']
logging.info('Executing "%s"', ' '.join(cmd))
service_out = run(cmd, universal_newlines=True)
if service_out.returncode is not 0:
logging.error(
'Command "%s" failed with return code %d', ' '.join(cmd), service_out.returncode)
sys.exit(1)
logging.info('Success!')
else:
logging.info('No certificate is about to expire')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment