Stage 3 · Build
systemd Service Management & Resource Control
systemd Sandboxing
NoNewPrivileges, ProtectSystem, PrivateTmp, DynamicUser, and capability bounding sets.
Sandboxing Overview
systemd provides extensive sandboxing directives to limit what a service can access. These directives use Linux kernel features (namespaces, cgroups, capabilities, seccomp) to create isolated service environments.
# Filesystem
ProtectSystem=strict # / and /usr read-only, /etc and /boot inaccessible
ProtectHome=yes # Make /home, /root, /run/user inaccessible
ReadWritePaths=/var/lib/myapp # Allow write to specific paths
PrivateTmp=yes # Private /tmp namespace
ProtectSystemTmpfs=yes # Make /tmp a tmpfs
# Network
PrivateNetwork=yes # No network access
RestrictAddressFamilies=AF_INET AF_INET6 # Only IPv4/IPv6 sockets
# Capabilities
CapabilityBoundingSet=CAP_NET_BIND_SERVICE # Limit capabilities
NoNewPrivileges=yes # Prevent privilege escalation
# System
ProtectKernelTunables=yes # Make /proc and /sys read-only
ProtectKernelModules=yes # Prevent module loading
ProtectControlGroups=yes # Make cgroup read-only
ProtectKernelLogs=yes # Prevent access to kernel log
# Resource limits
LimitNOFILE=65536
LimitNPROC=4096
MemoryMax=1G
CPUQuota=200%systemd sandboxing directives are applied at service start. They are the easiest way to harden services without modifying application code.
Filesystem Sandboxing
# ProtectSystem=strict makes / and /usr read-only
# /etc and /boot are completely inaccessible
[Service]
ProtectSystem=strict
ReadWritePaths=/var/lib/myapp /var/log/myapp
# ProtectHome=yes makes /home, /root, /run/user inaccessible
[Service]
ProtectHome=yes
# PrivateTmp=yes gives the service its own /tmp
[Service]
PrivateTmp=yes
# Prevents /tmp-based attacks and information leakage
# PrivateDevices=yes prevents access to physical devices
[Service]
PrivateDevices=yes
# ProtectKernelTunables=yes makes /proc/sys and /sys read-only
[Service]
ProtectKernelTunables=yes
# InaccessiblePaths blocks specific paths
[Service]
InaccessiblePaths=/etc/shadow /etc/gshadowProtectSystem=strict is the strongest filesystem sandbox. Always combine with ReadWritePaths for directories the service needs to write to.
Network Sandboxing
# Complete network isolation
[Service]
PrivateNetwork=yes
# Service has its own network namespace (no network access)
# Restrict socket families
[Service]
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
# Only IPv4, IPv6, and Unix sockets
# Allow only specific ports (with firewall rules)
[Service]
RestrictAddressFamilies=AF_INET AF_INET6
# Combine with iptables/nftables for port restrictions
# Port limit
[Service]
RestrictSUIDSGID=yes
# Prevent creating SUID/SGID files
# Socket activation (service only gets socket when activated)
[Service]
SocketActivated=yes
# Service gets socket from systemd, no direct bindPrivateNetwork=yes is the strongest network sandbox. For services that need network, use RestrictAddressFamilies to limit socket types.
Process Sandboxing
# NoNewPrivileges prevents privilege escalation
[Service]
NoNewPrivileges=yes
# No setuid, setgid, or capability changes
# CapabilityBoundingSet limits available capabilities
[Service]
CapabilityBoundingSet=
# No capabilities at all (most restrictive)
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETUID CAP_SETGID
# Only specific capabilities
# SystemCallFilter restricts available syscalls
[Service]
SystemCallFilter=@system-service
# Only syscalls needed by system services
SystemCallFilter=~@debug @mount @reboot @swap @obsolete
# Block debug, mount, reboot, swap, and obsolete syscalls
# SystemCallArchitecture=x86_64
# Only allow x86_64 syscalls (prevents 32-bit exploits)
# RestrictNamespaces=yes
# Prevent creating new namespaces
# RestrictRealtime=yes
# Prevent real-time scheduling
# RestrictSUIDSGID=yes
# Prevent SUID/SGID file creationNoNewPrivileges is the single most important security directive. CapabilityBoundingSet limits what the service can do even if compromised.
DynamicUser
# DynamicUser creates a temporary user for the service
[Service]
DynamicUser=yes
# systemd creates a user/group at start
# User is deleted at stop
# No need to create system users
# Combine with StateDirectory for persistent data
[Service]
DynamicUser=yes
StateDirectory=myapp
# /var/lib/myapp is created and owned by dynamic user
# Combine with RuntimeDirectory
[Service]
DynamicUser=yes
RuntimeDirectory=myapp
# /run/myapp is created
# CacheDirectory for cache data
[Service]
DynamicUser=yes
CacheDirectory=myapp
# /var/cache/myapp is created
# Logs
[Service]
DynamicUser=yes
LogsDirectory=myapp
# /var/log/myapp is createdDynamicUser eliminates the need for static system users. systemd creates and manages the user automatically. StateDirectory ensures data persists across restarts.
Complete Sandboxing Example
# /etc/systemd/system/sandboxed-web.service
[Unit]
Description=Sandboxed Web Application
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
DynamicUser=yes
WorkingDirectory=/opt/webapp
# Filesystem
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/webapp /var/log/webapp
PrivateTmp=yes
PrivateDevices=yes
StateDirectory=webapp
LogsDirectory=webapp
# Network
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
# Capabilities
NoNewPrivileges=yes
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
# Kernel
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
# System calls
SystemCallFilter=@system-service
SystemCallArchitecture=x86_64
# Resources
LimitNOFILE=65536
MemoryMax=512M
CPUQuota=100%
ExecStart=/opt/webapp/bin/server --port 8080
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetThis service has minimal filesystem access, limited capabilities, restricted syscalls, and resource limits. It can only bind to port 8080 and write to its own directories.
Begin with ProtectSystem, ProtectHome, and NoNewPrivileges. Add more directives as you verify the service works correctly.
Start with sandboxing directives removed, then add them back one by one. Test after each addition to identify which directive breaks the service.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.