systemd Service Sandboxing
PrivateTmp, PrivateNetwork, ProtectSystem, NoNewPrivileges, and systemd-analyze security.
Overview
systemd provides a rich set of sandboxing directives that restrict what a service can access — without writing custom seccomp profiles or AppArmor rules. These directives leverage the same Linux kernel primitives (namespaces, seccomp, cgroups, capabilities) used by containers, but are configured declaratively in unit files.
Effective sandboxing follows least privilege: each service should have exactly the access it needs and nothing more. A compromised web server that cannot access /home/, /root, or the network (if it only serves static files) has severely limited blast radius.
Core Sandboxing Directives
Filesystem isolation: - PrivateTmp=yes — the service gets its own private /tmp and /var/tmp. Other services cannot access its temp files. - ProtectSystem=strict — mounts /usr, /boot, and /etc read-only. The service cannot modify system files. - ProtectHome=yes — makes /home, /root, and /run/user inaccessible. - ReadOnlyPaths= — make specific paths read-only. - ReadWritePaths= — re-grant write access to specific paths (used together with ProtectSystem=strict).
Privilege isolation: - NoNewPrivileges=yes — the service cannot gain new privileges via setuid binaries or file capabilities. This single directive blocks a large class of privilege escalation attacks. - User= / Group= — run the service as a non-root user. - CapabilityBoundingSet= — restrict which capabilities the service can ever hold.
Network isolation: - PrivateNetwork=yes — the service gets its own network namespace with only a loopback interface. Cannot make outbound connections or listen on ports.
Auditing Security Score
systemd-analyze security prints a security score and lists which sandboxing directives are missing. A score of 10 (worst) means no sandboxing at all; 0.0 (best) is fully sandboxed.
Key concepts
- PrivateTmp=yes
- Service gets its own private /tmp and /var/tmp via a mount namespace. Other services cannot read its temp files. Prevents /tmp race conditions and information leaks.
- ProtectSystem=strict
- Mounts /usr, /boot, and /etc read-only. The service cannot write to system directories. Combine with ReadWritePaths= to re-grant write access to specific paths.
- ProtectHome=yes
- Makes /home, /root, and /run/user inaccessible (tmpfs overlay). Service cannot read user home directories or SSH keys.
- NoNewPrivileges=yes
- Sets the PR_SET_NO_NEW_PRIVS bit. The process and all its children cannot gain new privileges via setuid executables or file capabilities. Blocks most local privilege escalation.
- PrivateNetwork=yes
- Gives the service its own network namespace with only loopback. Cannot connect to the network, listen on external ports, or interact with other services over the network.
- systemd-analyze security
- Security auditing command that scores a service from 0 (best) to 10 (worst) based on which sandboxing directives are applied. Lists missing directives with their risk contribution.
When to use it
- Hardening a third-party service unit — add PrivateTmp, NoNewPrivileges, ProtectSystem=strict as a baseline
- Auditing service security posture — systemd-analyze security nginx to see score and missing directives
- Preventing a compromised service from accessing other services tmp files — PrivateTmp=yes
- Blocking a service from making outbound network connections (e.g., a local metrics exporter) — PrivateNetwork=yes
- Running a service as non-root with filesystem write access only to its data directory — User=appuser + ReadWritePaths=/var/lib/myapp
Interview questions
- How do you harden a systemd service unit for a web application? Show the unit file directives.
- What does systemd-analyze security show and how do you use it to improve a unit?
Sign up free to read the full topic
More Linux topics
Start free on Cariara · Coding problems · System design studio