Preserve app gate TLS access through provisioning and certificate rotation

This commit is contained in:
archipelago
2026-10-06 15:19:38 -04:00
parent 719e723816
commit 9f0df2ac44
9 changed files with 200 additions and 2 deletions
@@ -0,0 +1,38 @@
#!/usr/bin/env python3
"""Keep the node TLS leaf private while allowing the management daemon to read it."""
import argparse
import os
from pathlib import Path
import pwd
import stat
def repair(key: Path, service_uid: int, service_gid: int) -> bool:
try:
fd = os.open(key, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)
except FileNotFoundError:
return False # A node without TLS is not provisioned by this repair.
try:
before = os.fstat(fd)
if not stat.S_ISREG(before.st_mode) or before.st_uid not in (0, service_uid):
raise RuntimeError('Unexpected node TLS key type or owner; left unchanged')
# The daemon's primary group is the sole additional reader. Never make
# the key world-readable or grant group write/execute permissions.
mode = 0o640 if before.st_mode & stat.S_IWUSR else 0o440
if before.st_gid == service_gid and stat.S_IMODE(before.st_mode) == mode:
return False
os.fchown(fd, -1, service_gid)
os.fchmod(fd, mode)
os.fsync(fd)
return True
finally:
os.close(fd)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--key-name', choices=['archipelago.key', 'archipelago.key.new', 'archipelago.key.rotnew'], default='archipelago.key')
args = parser.parse_args()
account = pwd.getpwnam('archipelago')
changed = repair(Path('/etc/archipelago/ssl') / args.key_name, account.pw_uid, account.pw_gid)
print('Node app TLS permissions repaired' if changed else 'Node app TLS permissions unchanged')
+5 -1
View File
@@ -362,6 +362,10 @@ stage_tls() {
[ -s "$TLS_STAGE_KEY" ] && [ -s "$TLS_STAGE_CRT" ] || return 1
tls_pair_matches "$TLS_STAGE_KEY" "$TLS_STAGE_CRT" || return 1
chmod 600 "$TLS_STAGE_KEY"
if getent passwd archipelago >/dev/null 2>&1; then
chgrp "$(id -gn archipelago)" "$TLS_STAGE_KEY" || return 1
chmod 640 "$TLS_STAGE_KEY" || return 1
fi
return 0
}
@@ -376,7 +380,7 @@ stage_ssh() {
swap_tls() {
mv -f "$TLS_STAGE_KEY" "$TLS_KEY" || return 1
mv -f "$TLS_STAGE_CRT" "$TLS_CRT" || return 1
chmod 600 "$TLS_KEY"
# Preserve the staged daemon-readable mode through the atomic rename.
return 0
}