Systemd Security Hardening

Harden systemd services using sandboxing directives. Learn ProtectSystem, ProtectHome, NoNewPrivileges, PrivateTmp, and capability restrictions to minimize attack surface.

Advanced Configurations

Detailed Explanation

Locking Down Services with systemd

Systemd provides extensive sandboxing capabilities that restrict what a service can do. These directives apply security boundaries at the kernel level using namespaces, seccomp filters, and capability controls.

[Unit]
Description=Hardened Web Application
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/myapp
User=appuser
Group=appuser

# Filesystem restrictions
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/opt/myapp/data /var/log/myapp

# Privilege restrictions
NoNewPrivileges=yes
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE

# Network restrictions
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes

# Misc
RestrictSUIDSGID=yes
RestrictNamespaces=yes
LockPersonality=yes
MemoryDenyWriteExecute=yes

Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Filesystem Protection

ProtectSystem=strict: Mounts the entire filesystem read-only except for /dev, /proc, and /sys. Use ReadWritePaths= to grant specific write access.

Three levels:

  • true: /usr and /boot read-only
  • full: Additionally /etc read-only
  • strict: Everything read-only (recommended)

ProtectHome=yes: Makes /home, /root, and /run/user inaccessible.

PrivateTmp=yes: Creates a private /tmp directory visible only to this service. Prevents tmp-based attacks between services.

Privilege Restrictions

NoNewPrivileges=yes: The most important single hardening directive. Prevents the process and all its children from gaining new privileges through setuid/setgid binaries, filesystem capabilities, or other mechanisms.

CapabilityBoundingSet=: Restricts Linux capabilities. For example, to allow binding to ports below 1024 without running as root:

CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE

Kernel Protection

  • ProtectKernelTunables=yes: Blocks writing to /proc/sys, /sys, etc.
  • ProtectKernelModules=yes: Blocks loading kernel modules
  • ProtectControlGroups=yes: Makes cgroup hierarchy read-only

Auditing Security

Use systemd-analyze security to audit a service:

systemd-analyze security myapp.service

This outputs a security score (0-10, lower is better) with recommendations for each directive.

Incremental Hardening

Start with these essential directives and add more as you verify the service still works:

# Step 1: Essential (safe for most services)
NoNewPrivileges=yes
PrivateTmp=yes

# Step 2: Filesystem (test with your app)
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/path/to/data

# Step 3: Advanced (may break some apps)
PrivateDevices=yes
ProtectKernelTunables=yes
MemoryDenyWriteExecute=yes

Use Case

Hardening a production web application's systemd service to minimize the blast radius of a potential security breach by restricting filesystem access, blocking privilege escalation, and isolating the process.

Try It — Systemd Unit File Generator

Open full tool