added 'read' service and bug fixes

* added read service (kavita)
* renamed script to match repo

bugs:
* chown keys after custom site scripts in case of pfx or other generation (this was not getting chowned before and breaking the site)
This commit is contained in:
LuKe Tidd 2022-10-01 14:10:55 -04:00
parent f0cd9433de
commit a4e16f4cb1
2 changed files with 33 additions and 25 deletions

View File

@ -5,21 +5,20 @@ automation for cert renewal with local hooks
given a service:
* start letsencrypt's certbot "manually", getting ownership proof data
* write proof into nginx's serving path
* log into the firewall, allow http for the given service
* enable http for the given service
* turn up a custom nginx site for the proof
* log into the firewall, allow http to the given service
* enable http for the given service in nginx
* instruct let's encrypt to check the proof
* get new keys
* new expiration date on certs
* disable http for the service
* log into firewall, block http for the given service
* set permissions and ownership on new keys
* perform service specific hooks
* jellyfin/plex: generate a pkcs12 key and
put it in the right place
* set permissions and ownership on new keys
All secrets are GPG encrypted and one password prompt allows for script access
to all secrets necessary.
State:
* running for all services, no known bugs at this time

View File

@ -18,7 +18,8 @@ import subprocess
import sys
import time
supported_services = ['git', 'plex', 'jellyfin', 'photoprism', 'nextcloud']
supported_services = [
'git', 'plex', 'jellyfin', 'photoprism', 'nextcloud', 'read']
restart_delay = {
'plex': 10
@ -29,22 +30,22 @@ pfx_key_path = {
'jellyfin': '/etc/letsencrypt/live/jellyfin.drheck.dev/jellyfin.pfx',
}
# Cert owning user if different than the name of the service
users = {
'jellyfin': 'jellyfin',
'git': 'gitea',
'plex': 'plex',
'photoprism': 'photoprism',
'nextcloud': 'nextcloud',
'read': 'http',
}
# systemd service names that don't match the service name
# service : systemd_service
systemd_services = {
'git': 'gitea',
'plex': 'plexmediaserver',
'read': 'kavita',
}
cert_files = ['privkey1.pem', 'fullchain1.pem', 'chain1.pem', 'cert1.pem']
router = 'danknasty'
router_user = 'luke131'
router_key = '/root/.ssh/id_autofirewall'
@ -61,7 +62,9 @@ def firewall_mod(state, service, decrypt_pp):
log.info(f'env for fw: ssl_service: {service}')
log.info(f'cmd to connect to firewall: "{" ".join(cmd)}"')
p = pexpect.spawnu(' '.join(cmd))
res = p.expect([f'Enter passphrase for key "{router_key}":',
p.logfile = sys.stderr
log.info(f'key string: {router_key}')
res = p.expect([f'''Enter passphrase for key ['"]{router_key}['"]:''',
pexpect.TIMEOUT, pexpect.EOF])
if res > 0:
sys.exit('Couldnt send decryption key to ssh.')
@ -149,8 +152,8 @@ def restart(service):
cmd = ['/usr/bin/systemctl', 'status', systemd_service]
log.info(f'cmd to show status of service: "{" ".join(cmd)}"')
p = subprocess.run(cmd, capture_output=True)
stderr = p.stdout.decode('UTF-8')
sys.stderr.write(p.stdout)
stderr = p.stderr.decode('UTF-8')
sys.stderr.write(stderr)
sys.exit(1)
log.info(f'{service} has restarted OK')
@ -175,6 +178,7 @@ def pfx_gen(service):
'-certfile', f'/etc/letsencrypt/live/{service}.drheck.dev/chain.pem']
log.info(f'cmd to encrypt private key: "{" ".join(cmd)}"')
p = pexpect.spawnu(' '.join(cmd))
p.logfile = sys.stderr
res = p.expect(['Enter Export Password:', pexpect.EOF, pexpect.TIMEOUT])
if res > 0:
sys.exit('Failed to run openssl to generate '
@ -196,7 +200,8 @@ def pfx_gen(service):
def main(args):
logging.basicConfig(level=os.environ.get("LOGLEVEL", "WARNING"))
# logging.basicConfig(level=os.environ.get("LOGLEVEL", "WARNING"))
logging.basicConfig(level=os.environ.get("LOGLEVEL", "INFO"))
log.info(f'program start: {sys.argv}')
if len(args) != 1:
@ -232,9 +237,9 @@ def main(args):
fqdn = f'{service}.drheck.dev'
log.info(f'fqdn: {fqdn}')
# Dry run:
cmd = ['/usr/bin/certbot', '--dry-run', 'certonly', '--manual', '-d', fqdn]
# cmd = ['/usr/bin/certbot', '--dry-run', 'certonly', '--manual', '-d', fqdn]
# Real run:
# cmd = ['/usr/bin/certbot', 'certonly', '--manual', '-d', fqdn]
cmd = ['/usr/bin/certbot', 'certonly', '--manual', '-d', fqdn]
log.info(f'certbot cmd: "{" ".join(cmd)}"')
cb = pexpect.spawnu(' '.join(cmd))
res = cb.expect(
@ -319,12 +324,21 @@ def main(args):
log.info(f'live keypath: {live}')
log.info(f'archive keypath: {archive}')
user = users[service]
if service in globals():
log.info(f'{service} has a service specific function to run')
eval(f'{service}()')
log.info(f'{service} specific work complete.')
user = service
if service in users:
user = users[service]
log.info(f'service {service} has user {user}')
uid = pwd.getpwnam(user).pw_uid
gid = pwd.getpwnam(user).pw_gid
log.info(f'uid: {uid} gid: {gid}')
# chown after custom service in case pfx or other key is generated
log.info(f'uid: {uid} gid: {gid}')
os.chown(live, uid, gid)
log.info(f'live keypath chmodded')
os.chown(archive, uid, gid)
@ -334,11 +348,6 @@ def main(args):
log.info(f'{cert_file} chowned to service user')
log.info(f'chmodded new keys from certbot')
if service in globals():
log.info(f'{service} has a service specific function to run')
eval(f'{service}()')
log.info(f'{service} specific work complete.')
restart(service)