28 lines
1.3 KiB
Python
28 lines
1.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Fresh-image AppArmor profiles, loaded before application services start."""
|
|
from pathlib import Path
|
|
import os
|
|
import stat
|
|
import subprocess
|
|
|
|
BASE = Path('/usr/share/archipelago/apparmor')
|
|
NAMES = ('aiui', 'core-lightning', 'grafana', 'home-assistant', 'mempool', 'nostr-relay', 'router', 'searxng')
|
|
|
|
def main():
|
|
if os.geteuid() != 0: raise SystemExit('root image principal required')
|
|
if Path('/sys/module/apparmor/parameters/enabled').read_text().strip() != 'Y':
|
|
raise SystemExit('AppArmor must be enabled; application startup refused')
|
|
for name in NAMES:
|
|
path = BASE/name
|
|
for entry in (Path('/'), *reversed(path.parents[:-1]), path):
|
|
metadata = entry.lstat()
|
|
if (metadata.st_uid != 0 or metadata.st_mode & 0o022 or entry.is_symlink()
|
|
or (entry == path and (not stat.S_ISREG(metadata.st_mode) or metadata.st_nlink != 1))):
|
|
raise SystemExit('unsafe application profile asset: '+str(entry))
|
|
subprocess.run(['/usr/sbin/apparmor_parser','--replace','--skip-cache',str(path)],check=True,timeout=30)
|
|
loaded = Path('/sys/kernel/security/apparmor/profiles').read_text().splitlines()
|
|
if any(name+' (enforce)' not in loaded for name in NAMES):
|
|
raise SystemExit('all application profiles must be enforced')
|
|
|
|
if __name__ == '__main__': main()
|