[Unit] Description=lchat public SSH access ledger (one collect pass) After=network-online.target Wants=network-online.target [Service] Type=oneshot # Optional overrides: STATUS_BUCKET / STATUS_REGION (mirror status-publish.sh). EnvironmentFile=-/data/status.env # "+" = outside the sandbox: both ReadWritePaths must exist before # ProtectSystem=strict mounts them, or the first-ever run fails to namespace. ExecStartPre=+/usr/bin/mkdir -p /data/ssh-ledger /opt/lchat/status-pages ExecStart=/opt/lchat/ssh-ledger-collect.sh # --- hardening (see docs/instance-router.md § Hardening) --- # Runs as ROOT deliberately: the sshd journal is root/systemd-journal readable # and /data/ssh-ledger + /opt/lchat/status-pages are its only writes — # ProtectSystem=strict pins exactly those. It is fired by # lchat-ssh-ledger.timer, never routed or listening, and publishes METADATA # ONLY (see the script's privacy header). ProtectSystem=strict ReadWritePaths=/data/ssh-ledger /opt/lchat/status-pages ProtectHome=yes PrivateTmp=yes PrivateDevices=yes ProtectClock=yes ProtectHostname=yes ProtectKernelTunables=yes ProtectKernelModules=yes ProtectKernelLogs=yes NoNewPrivileges=yes RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX RestrictNamespaces=yes RestrictRealtime=yes LockPersonality=yes MemoryDenyWriteExecute=yes MemoryMax=256M TasksMax=64