Skip to content

$ cat ./posts/security/hardening-systemd-units.service

-rw-r--r-- 1.8K #security #systemd

Hardening systemd units

by chris · 2 min read · /security


systemd can put a service in a namespace with a read-only filesystem, no network, no new privileges and a syscall filter — all from the unit file. For a service you did not write, this is the cheapest security work available.

1. Start from the analyser

systemd-analyze security nginx.service

It scores every unit on the system and lists what is missing. The score is a heuristic, not a target, but it points at the directives worth adding.

2. The directives that carry most of the weight

[Service]
NoNewPrivileges=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectSystem=strict
ProtectHome=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM

ProtectSystem=strict makes the entire filesystem read-only except /dev, /proc and /sys. Anything the service legitimately writes gets an explicit exception:

ReadWritePaths=/var/lib/myservice /var/log/myservice

3. Test the sandbox, not just the syntax

A tightened unit that starts is not a tightened unit that works. Exercise the paths that write files, rotate logs and reload configuration, then read the journal for EPERM. A syscall filter usually fails at the least convenient moment — during a reload, hours after the deploy.

4. Drop the ones you cannot justify

Every directive here has a cost in debuggability. If a service needs raw sockets, say so in a comment next to the exception rather than removing the whole line. The unit file is documentation of what the service is allowed to do, and it should read that way.

← cd .. fris@linux:~/blog$ man security