# yaml-language-server: $schema=../../../../schema/control.schema.json id: CB-DEB-SVC-025 title: Confine services with systemd sandboxing options finding: title: Network-facing services run with the full privileges systemd gives by default description: A compromised service can read and change the whole system instead of its own files. status: active profiles: [server-hardened] risk: severity: medium assessment: partial tags: [systemd, sandboxing, services, least-privilege] description: | systemd can confine each service with options in its unit or in a drop-in (`systemctl edit `): a dedicated or dynamic user (`User=`, `DynamicUser=`), a read-only view of the system (`ProtectSystem=strict`, `ProtectHome=`, `ReadWritePaths=`), a private `/tmp` and device set (`PrivateTmp=`, `PrivateDevices=`), no privilege gain (`NoNewPrivileges=`, `CapabilityBoundingSet=`), and kernel and system call filters (`ProtectKernelTunables=`, `RestrictAddressFamilies=`, `SystemCallFilter=`...). `systemd-analyze security` scores each service from 0 (confined) to 10 (unconfined) and labels it `OK`, `MEDIUM`, `EXPOSED` or `UNSAFE`. rationale: | Most daemons only need a few directories, capabilities and system calls. Confining them limits what an attacker gains by exploiting one: no access to other services' data, no kernel tuning, no new privileges. This is the compartmentalization ANSSI asks for each service. impact: | Options that are too strict make a service fail at start-up or at run time (cannot write its files, cannot open a socket). Each change must be tested on the service and kept in a drop-in so package upgrades do not overwrite it. notes: | The check lists the services that `systemd-analyze security` labels `UNSAFE` with their score; it always passes, so the control ends as `review`. A person decides which network-facing services to confine first. Many Debian services already ship hardened units (for example `systemd-resolved`, `chrony`); OpenSSH stays largely unconfined by design, since it must start login sessions. audit: manual: | 1. Run `systemd-analyze security` and note the services rated `UNSAFE` or `EXPOSED`. 2. For each service that listens on the network or parses untrusted data, check that a drop-in under `/etc/systemd/system/.d/` sets the sandboxing options it supports, and that `systemd-analyze security ` shows an improved score. checks: - id: exposure engine: shell description: Lists the services rated UNSAFE by systemd-analyze security, for review. spec: script: | command -v systemd-analyze >/dev/null 2>&1 || { echo "systemd-analyze not found"; exit 3; } o=$(systemd-analyze security --no-pager 2>/dev/null) || { echo "systemd-analyze security failed"; exit 3; } total=$(printf '%s\n' "$o" | awk 'NR > 1' | grep -c .) unsafe=$(printf '%s\n' "$o" | awk 'NR > 1 && $3 == "UNSAFE" { printf "%s=%s ", $1, $2 }') n=$(printf '%s' "$unsafe" | wc -w) echo "$n of $total services UNSAFE: $unsafe" remediation: manual: | For each service to confine, run `systemctl edit ` and add the options it tolerates, for example: ``` [Service] ProtectSystem=strict ReadWritePaths=/var/lib/ ProtectHome=yes PrivateTmp=yes PrivateDevices=yes NoNewPrivileges=yes ProtectKernelTunables=yes ProtectKernelModules=yes ProtectControlGroups=yes RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 ``` Restart the service, check that it works and its logs (`journalctl -u `), then compare `systemd-analyze security `. rollback: | Run `systemctl revert ` to remove the drop-ins, then restart the service. references: - title: systemd.exec(5), Debian manual pages url: https://manpages.debian.org/trixie/systemd/systemd.exec.5.en.html publisher: Debian kind: vendor-doc accessed: 2026-10-18 - title: systemd-analyze(1), Debian manual pages url: https://manpages.debian.org/trixie/systemd/systemd-analyze.1.en.html publisher: Debian kind: vendor-doc accessed: 2026-10-18 - title: Debian Wiki - ServiceSandboxing url: https://wiki.debian.org/ServiceSandboxing publisher: Debian kind: vendor-doc accessed: 2026-10-18 - title: ANSSI-BP-028 v2.0 - Recommandations de configuration d'un système GNU/Linux (R64, R65, R66) url: https://messervices.cyber.gouv.fr/documents-guides/fr_np_linux_configuration-v2.0.pdf publisher: ANSSI kind: guide accessed: 2026-10-18 mappings: - framework: anssi-linux framework_version: "2.0" id: R64 relation: partial note: Covers service privileges through systemd users and capabilities. - framework: anssi-linux framework_version: "2.0" id: R65 relation: partial note: Covers compartmentalization with systemd namespaces; containers and VMs are out of scope. - framework: anssi-linux framework_version: "2.0" id: R66 relation: partial note: Covers system call and kernel access filters set by systemd. - framework: nist-800-53r5 framework_version: "5.1.1" id: SC-39 relation: related - framework: nist-800-53r5 framework_version: "5.1.1" id: AC-6 relation: related threats: - framework: mitre-attack id: T1068 - framework: mitre-attack id: T1190 - framework: cwe id: CWE-250 authors: - name: Alice github: Sn0wAlice verified: - date: 2026-10-18 by: Sn0wAlice versions: ["12"] environment: Proxmox VM, Debian 12 genericcloud image, kernel 6.1.0-54-cloud-amd64 notes: "Check lists the UNSAFE services from systemd-analyze security and ends as review, on fresh and loaded systems." - date: 2026-10-18 by: Sn0wAlice versions: ["13"] environment: Proxmox VM, Debian 13 genericcloud image, kernel 6.12.113+deb13-cloud-amd64 notes: "Check lists the UNSAFE services from systemd-analyze security and ends as review, on fresh and loaded systems." introduced_in: 0.1.0 created: 2026-10-18 updated: 2026-10-18