Architecture and operating model
systemd sandbox directives do not turn a service into a full container. They layer restrictions over process identity, Linux capabilities, mount namespaces, devices, address families and system calls. DynamicUser allocates an ephemeral UID/GID. ProtectSystem=strict makes most of the file system read-only, while StateDirectory, CacheDirectory and LogsDirectory create controlled writable locations.
CapabilityBoundingSet limits capabilities the service can ever gain; AmbientCapabilities passes only a required capability to a non-root process. NoNewPrivileges blocks new setuid or file-capability elevation. SystemCallFilter and RestrictAddressFamilies narrow behavior, but test application libraries, DNS, logging and JIT behavior for the deployed version.
Deploy by observing first and tightening incrementally. The systemd-analyze security score is a comparison signal, not proof by itself. The service should access only expected files, sockets and network families, with denials correlated from journal or audit logs to functional tests.
- 1Inventory service dependencies and access
- 2Apply incremental drop-in sandbox
- 3Run functional and negative tests
- 4Verify security score and journal
Design parameters
- Writable paths
- Define them with StateDirectory/RuntimeDirectory; avoid broad ReadWritePaths exceptions.
- Capability set
- Derive the minimum from `capsh --print` or observed errors.
- Address families
- Test AF_UNIX, AF_INET and AF_INET6 needs including DNS, logging and local sockets.
- System calls
- Pilot filter groups on the actual version; assess JIT or eBPF users separately.
Worked example
An HTTP service on port 8080 that writes `/var/lib/acme-api` and logs to journald needs neither root nor CAP_NET_BIND_SERVICE. DynamicUser=yes, StateDirectory=acme-api, ProtectSystem=strict and AF_UNIX/AF_INET/AF_INET6 may suffice. Binding directly to 443 requires a capability or a front proxy as a separate design choice.
Exposure may fall from 6.2/10 to 2.1/10, but acceptance must also cover API functions, state after restart, DNS, logs and a controlled forbidden-write test. Report the score with functional coverage and attack-surface evidence.
Example commands: replace lab values and confirm permissions and software versions before use.
sudo systemctl edit acme-api.service
# [Service]
# DynamicUser=yes
# StateDirectory=acme-api
# ProtectSystem=strict
# ProtectHome=yes
# NoNewPrivileges=yes
# PrivateTmp=yes
# CapabilityBoundingSet=
# RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
systemd-analyze security acme-api.service
systemd-analyze verify /etc/systemd/system/acme-api.service.d/override.conf
journalctl -u acme-api.service -b
Troubleshooting
| Observation | Likely cause / distinction | Verification |
|---|---|---|
| Read-only file system | The service may write outside a location allowed under ProtectSystem. | Find the path in journal and document it with StateDirectory or narrow ReadWritePaths. |
| Operation not permitted | A capability, syscall or namespace restriction may block real behavior. | Map audit/journal evidence to one directive and relax only that control. |
| Ownership changes after DynamicUser | Persistent data may live in a manually created path tied to an ephemeral UID. | Use StateDirectory ownership management and remove fixed-UID assumptions. |
Acceptance checks
- Inventory file, socket, device and network access.
- Record baseline and final `systemd-analyze security` scores.
- Run positive functional tests after restart.
- Run negative `/etc` write and unnecessary-family tests.
- Correlate journal or audit denials with each change.
- Keep the drop-in and rollback step in version control.
Related concepts
Service lifecycle and dependencies
A running process does not prove that users receive correct service. Review startup order, network or database dependencies, environment variables, file access and health checks together. Restart loops can conceal the root cause. Compare exit codes, recent logs and resource limits, and identify whether systemd or container management triggered the restart. After a controlled restart, validate sessions, writes and dependent services.
Isolation versus virtualization
Containers and VMs provide different isolation boundaries. Containers share the host kernel; VMs run guest operating systems. Rootless execution, namespaces and capability restrictions can reduce risk, but configuration and host security still matter. Images, running containers and persistent volumes have separate lifecycles. Updating an image does not back up data. Verify process privileges, mounts, network access and persistence after recreation separately.
Least privilege and separation of duties
Least privilege limits the permissions needed for a task to specific resources and time periods. Giving everyone the same administrator role complicates access reviews and investigations. Separate daily-use identities from privileged accounts, and restrict interactive use and unnecessary network access for service identities. An access matrix should show which operation an identity may perform on each resource. Test whether an application keeps working after a permission is removed: unnecessary privileges sometimes become visible only during controlled reduction.
Filesystem and storage layers
An application directory, mount point, logical volume and physical device belong to different layers. Inode exhaustion, read-only mounts and filesystem errors can stop writes even when space appears available. A snapshot often shares the same storage failure domain and is not an independent backup. Mount options and expansion methods depend on the filesystem. Verify mounts after reboot: writing to an unmounted directory can fill the wrong device.
File permissions and service identities
File access combines users/groups, permission bits, ACLs and security policies. Running an application as root can hide permission problems; prefer a justified, restricted service identity in production. Directory traversal permission differs from file-read permission. Sharing permissions do not necessarily override filesystem restrictions. Identify the account actually running the application, directory chain and ACLs when troubleshooting. Test narrowly required access rather than opening permissions globally.
Telemetry and time correlation
Telemetry combines logs, metrics and events that explain system behavior. A log describes an event, a metric shows behavior over time, and a distributed trace follows a request across components. Clock differences can make one event appear to occur at several times. Use synchronized clocks, reliable source identifiers and consistent time-zone handling. Alarm design should consider duration and user impact alongside thresholds. Monitor gaps in collection separately: absence of logs must not be interpreted as absence of incidents.
Primary documentation
Prepared by the Doz Teknoloji technical team using the primary references below. Calculations and lab scenarios state their assumptions; validate the applicable product version before rollout.