Marco d'Itri <m...@linux.it> writes: > On Jul 04, Andrey Rakhmatullin <w...@wrar.name> wrote: > >> Cool but looks like a lot of work.
[...] >> start with applying all of them and then looking what needs to be >> disabled? > This is what I do. FYI below is my basic workflow. Once you've done 2-5 daemons, you get a "feel" for the trouble spots. Total time to harden a unit from EXPOSURE=10 to EXPOSURE=3 usually takes me 1-4 hours. If I've used the daemon before & know its config format & source code, usually 1 hour. I typically start with a "deny all" ruleset. Either I copy-paste from another daemon I did earlier, or I copy-paste from "systemd-analyze security". A slightly out-of-date one is https://github.com/cyberitsolutions/prisonpc-systemd-lockdown/blob/main/systemd/system/0-EXAMPLES/20-default-deny.conf Usually the daemon segfaults immediately. In "coredumpctl" I see what the last syscall was. Typically it is setuid so per I know to allowlist these: SystemCallFilter=@setuid CapabilityBoundingSet=CAP_SETUID CAP_SETGID This is because the daemon does a no-op setuid(123) even if it's ALREADY 123 (due to User=%p in frobozzd.service). This could be patched away, but so far my policy has been "focus on stuff that doesn't require patching", so instead I just allow that syscall. It is very common to need both AF_UNIX and AF_NETLINK, so I don't even try to block those. Things that need network (e.g. postfix, nginx) would also need AF_INET, AF_INET6, IPAddressAllow=all, &c. The next most common failure is being unable to write to somewhere due to ProtectSystem=strict, so I look for things like /run/frobozzd.pid or /var/lib/frobozzd/state.db in the error logs (journalctl -u frobozzd). If systemd's existing things like RuntimeDirectory=%p aren't enough to cover it, I add ReadWritePaths=, or downgrade ProtectSystem=strict to ProtectSystem=yes. If it's still crashing, I remove "SystemCallFilter=~@privileged @resources" and "CapabilityBoundingSet=" entirely. If that works, I strace or bisect to find which syscalls must be allowlisted. If it's *STILL* crashing, I bisect over the entire hardening denylist. (Comment out half. Does it work now? If so, it's mad about the commented-out half. Repeat.) The hardest part is the rare case where a daemon will automatically detect that an action failed, then *silently* switch to a less-secure mode. It is very hard to spot this is happening until after the hardened unit has been in production for a month or two. PS: I typically have a dev loop like: journalctl -fu frobozzd & while ! systemctl restart frobozzd; do systemctl edit frobozzd; done Or if it's on another host, M-! <hardening.conf ssh root@test ' cat >/etc/systemd/system/frobozzd.service.d/hardening.conf; systemctl daemon-reload; systemctl restart frobozzd; systemctl status frobozzd' PPS: so far I've been talking about system units, but user units can also have hardening! For example, I bet this only needs write access to /sys/blah/rfkill, and could have it's TCP privileges revoked: org.gnome.SettingsDaemon.Rfkill.service 9.8 UNSAFE 😨 Also by default "systemd-analyze security" doesn't mention timer/path-fired units like e2scrub or fsck. If you want to see those you have to do something like "systemctl list-units --all --type=service".