initial commit
This commit is contained in:
parent
4981a04b9d
commit
95fb9386a8
1
remote/authorized_keys
Normal file
1
remote/authorized_keys
Normal file
@ -0,0 +1 @@
|
||||
command="/usr/local/bin/ssl-update.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIORHtLf6y6rF7EQ9UdPhILDUOLybxffwjyHzxsmOk735 autofirewall
|
55
remote/ssl-update.sh
Normal file
55
remote/ssl-update.sh
Normal file
@ -0,0 +1,55 @@
|
||||
#!/bin/ksh
|
||||
# install to /usr/local/bin on firewall
|
||||
# OpenBSD pdksh
|
||||
|
||||
hostname_file='/etc/myname'
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
printf 'Must be run as root.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$hostname_file" ]; then
|
||||
printf 'No hostname file. Is this the right server?\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$(<"$hostname_file")" != 'danknasty' ]; then
|
||||
printf 'Only designed to be run on danknasty.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fw_config="/etc/pf_${ssl_service}.conf"
|
||||
|
||||
if [ ! -f "$fw_config" ]; then
|
||||
printf 'No firewall config found for %s at %s.\n' "$ssl_service" "$fw_config" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf 'Setting "%s" for "%s".\n' "$state" "$ssl_service"
|
||||
printf 'Firewall config: "%s"\n' "$fw_config"
|
||||
|
||||
if [ "$state" == 'HTTP_UP' ]; then
|
||||
printf 'Removing comment\n'
|
||||
sed -i 's/^# pass/pass/' "$fw_config"
|
||||
if [ $? != 0 ]; then
|
||||
printf 'Failed to configure %s http port up.\n' "$ssl_service" >&2
|
||||
exit 1
|
||||
fi
|
||||
elif [ "$state" == 'HTTP_DOWN' ]; then
|
||||
printf 'Adding comment\n'
|
||||
sed -i 's/^pass/# pass/' "$fw_config"
|
||||
if [ $? != 0 ]; then
|
||||
printf 'Failed to configure %s http port down.\n' "$ssl_service" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
printf 'Invalid state: %s.\n' "$state" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
/usr/local/bin/pfhup
|
||||
if [ $? != 0 ]; then
|
||||
printf 'Failed to restart firewall. Check config immediately.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf 'success\n'
|
132
update_cert.py
Executable file
132
update_cert.py
Executable file
@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Automation for cert renewal.
|
||||
|
||||
assumptions:
|
||||
* router is danknasty
|
||||
* generate key in /root/.ssh/id_autofirewall on server
|
||||
* firewall has config from `authorized_keys` file
|
||||
* firewall sshd config contains: `AcceptEnv ssl_service state`
|
||||
* firewall has `ssl-update.sh` copied to /usr/local/bin and chmod +x
|
||||
"""
|
||||
|
||||
import getpass
|
||||
import os
|
||||
import pathlib
|
||||
import pexpect
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
services = ['git', 'plex', 'jellyfin', 'photoprism']
|
||||
|
||||
|
||||
def rmdir(directory):
|
||||
directory = pathlib.Path(directory)
|
||||
for item in directory.iterdir():
|
||||
if item.is_dir():
|
||||
rmdir(item)
|
||||
else:
|
||||
item.unlink()
|
||||
directory.rmdir()
|
||||
|
||||
|
||||
def main(args):
|
||||
|
||||
# Get SSH decryption password
|
||||
|
||||
cmd = ['/usr/bin/su', '-l', 'luke', '/usr/bin/pass', 'show', 'ssh/autofirewall']
|
||||
p = subprocess.run(cmd, capture_output=True)
|
||||
decrypt_pp = p.stdout.decode('UTF-8').strip()
|
||||
if not decrypt_pp:
|
||||
sys.exit('Couldnt get decryption passpharase')
|
||||
|
||||
# Start Certbot, get data to send to service
|
||||
|
||||
challenge_path = pathlib.Path('/usr/share/nginx/html/'
|
||||
'.well-known/acme-challenge/')
|
||||
if challenge_path.is_dir():
|
||||
rmdir(challenge_path)
|
||||
challenge_path.mkdir()
|
||||
challenge_path.chmod(0o755)
|
||||
if len(args) != 1:
|
||||
sys.exit(f'Give a service to renew: {", ".join(services)} ')
|
||||
service = args[0]
|
||||
if service not in services:
|
||||
sys.exit(f'Give a service to renew: {", ".join(services)} ')
|
||||
|
||||
fqdn = f'{service}.drheck.dev'
|
||||
cmd = ['/usr/bin/certbot', 'certonly', '--manual', '-d', fqdn]
|
||||
p = pexpect.spawnu(' '.join(cmd))
|
||||
# p.logfile = sys.stderr
|
||||
res = p.expect(['Create a file containing just this data:\r\n\r\n([^\r]+)\r',
|
||||
pexpect.TIMEOUT, pexpect.EOF], timeout=20)
|
||||
if res > 0:
|
||||
sys.exit('Timed out')
|
||||
data = p.match.group(1)
|
||||
long_match = ('And make it available on your web server at this URL:'
|
||||
'\r\n\r\nhttp://%s/.well-known/acme-challenge/([^\r]+)\r')
|
||||
res = p.expect([long_match % (fqdn,), pexpect.TIMEOUT, pexpect.EOF])
|
||||
if res > 0:
|
||||
sys.exit('Timed out')
|
||||
filename = p.match.group(1)
|
||||
res = p.expect(['Press Enter to Continue', pexpect.EOF], timeout=0)
|
||||
|
||||
# Certbot is paused. Got the data
|
||||
|
||||
# put data in acme-challenge file
|
||||
data_file = challenge_path / pathlib.Path(filename)
|
||||
try:
|
||||
with open(data_file, 'w') as f:
|
||||
f.write(data)
|
||||
except:
|
||||
sys.exit(f'Failed to write {data_file}')
|
||||
data_file.chmod(0o644)
|
||||
|
||||
# put symlink in nginx enabled sites
|
||||
|
||||
symlink_name = pathlib.Path(f'{service}-le')
|
||||
nx_conf = pathlib.Path('/etc/nginx')
|
||||
avail_path = nx_conf / pathlib.Path('sites-available')
|
||||
enabled_path = nx_conf / pathlib.Path('sites-enabled')
|
||||
|
||||
service_available_file = avail_path / symlink_name
|
||||
service_enabled_symlink = enabled_path / symlink_name
|
||||
if not service_enabled_symlink.is_symlink():
|
||||
service_enabled_symlink.symlink_to(service_available_file)
|
||||
|
||||
# open port 80 to ${service}.drheck.dev
|
||||
|
||||
os.environ['state'] = 'HTTP_DOWN'
|
||||
os.environ['ssl_service'] = service
|
||||
cmd = ['/usr/bin/ssh', '-i', '/root/.ssh/id_autofirewall', '-o',
|
||||
'SendEnv=state', '-o', 'SendEnv=ssl_service', '-l', 'luke131',
|
||||
'danknasty', 'doas', '-n', '/usr/local/bin/ssl-update.sh']
|
||||
print(f'cmd: {cmd}')
|
||||
p = pexpect.spawnu(' '.join(cmd))
|
||||
p.logfile = sys.stderr
|
||||
res = p.expect(["""Enter passphrase for key '/root/.ssh/id_autofirewall':""", pexpect.TIMEOUT, pexpect.EOF])
|
||||
if res > 0:
|
||||
sys.exit('Couldnt send decryption key to ssh.')
|
||||
p.sendline(decrypt_pp)
|
||||
res = p.expect(['success', pexpect.TIMEOUT, pexpect.EOF])
|
||||
if res > 0:
|
||||
sys.exit(f'Failed. error: {p.before}')
|
||||
|
||||
print(f'Turned up HTTP for {service}')
|
||||
|
||||
# restart nginx
|
||||
# continue with certbot
|
||||
# close port 80 to git.drheck.dev
|
||||
# remove symlink in nginx enabled sites
|
||||
# restart nginx
|
||||
# chmod
|
||||
# /etc/letsencrypt/live/git.drheck.dev
|
||||
# /etc/letsencrypt/archive/git.drheck.dev
|
||||
# restart gitea
|
||||
# p.expect(r'up\s+(.*?),\s+([0-9]+) users?,\s+load averages?: ([0-9]+\.[0-9][0-9]),?\s+([0-9]+\.[0-9][0-9]),?\s+([0-9]+\.[0-9][0-9])')
|
||||
# duration, users, av1, av5, av15 = p.match.groups()
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
Loading…
x
Reference in New Issue
Block a user