nyacme/nyacme/__main__.py
2024-04-07 11:39:19 +02:00

97 lines
3.1 KiB
Python

import argparse
from genericpath import exists
import logging
import os.path
import shutil
import subprocess
from datetime import datetime
from pathlib import Path
from .config import read_config
logging.basicConfig(level=logging.INFO, format='[%(levelname)s] %(name)s: %(message)s')
log = logging.getLogger('nyacme')
def main() -> None:
parser = argparse.ArgumentParser(
prog='nyacme',
description='fun uacme wrapper'
)
parser.add_argument('-c', '--config', default='/etc/nyacme.toml')
parser.add_argument('-o', '--output', default='/etc/ssl/uacme')
args = parser.parse_args()
config = read_config(args.config)
output_dir = Path(args.output)
acquired = False
for domain in config.certificates:
# arguments passed to uacme
uacme_domains = [domain]
if domain.startswith('*.'):
uacme_domains = [ domain[2:], domain ]
domain = domain[2:]
cert_path = output_dir / domain / 'cert.pem'
if cert_path.is_file():
cmd = [ 'openssl', 'x509', '-enddate', '-noout', '-in', cert_path ]
out = subprocess.run(cmd, stdout=subprocess.PIPE, check=True).stdout.decode('utf-8').strip()
date = datetime.strptime(out, 'notAfter=%b %d %H:%M:%S %Y %Z')
# if more than 1 month, skip
delta = date - datetime.now()
if delta.days > 30:
log.info(f'cert for {domain} expires in more than a month ({delta.days} days), skipping')
continue
log.info(f'getting cert for {domain}')
env = os.environ.copy()
env['NYACME_CONFIG'] = args.config
hook_path = shutil.which('nyacme-hook')
if not hook_path:
log.warning('setting hook path to hook launcher from git repo')
hook_path = os.path.join(os.path.dirname(__file__), '..', 'hook_launcher.py')
res = subprocess.run([
'uacme', '-v',
'--hook', hook_path,
'--confdir', args.output,
'-b', '384',
'--type', 'EC',
# '--force',
'issue'
] + uacme_domains, env=env)
if res.returncode == 0:
acquired = True
private_key = output_dir / 'private' / domain / 'key.pem'
domain_key = output_dir / domain / 'cert.pem.key'
domain_pem = output_dir / domain / 'cert.pem'
domain_key.unlink(missing_ok=True)
domain_key.hardlink_to(private_key)
# TODO: add user/group to config
shutil.chown(domain_key, 'acme', 'acme')
domain_key.chmod(0o440)
all_dir = output_dir / 'all'
all_dir.mkdir(parents=True, exists_ok=True)
all_pem = all_dir / f'{domain}.pem'
all_key = all_dir / f'{domain}.pem.key'
all_pem.unlink(missing_ok=True)
all_pem.hardlink_to(domain_pem)
all_key.unlink(missing_ok=True)
all_key.hardlink_to(domain_key)
if acquired:
for cmd in config.post_acquire:
subprocess.run(cmd, shell=True, check=True)
if __name__ == '__main__':
main()