Hiding other processes from a service reduces what an attacker can learn after a compromise. It also removes context that operators and incident responders often expect to find inside the service. PrivatePIDs= and ProcSubset= provide different forms of that visibility reduction, and each has a different failure mode.

A private PID namespace

PrivatePIDs=yes places the service in a new PID namespace. The first service process becomes PID 1 in that namespace. The /proc mount shown to the service only lists processes in the same namespace because systemd also enables MountAPIVFS=yes.

The host still sees the real process tree. A host-side ps command can identify the service processes, and the host can inspect their namespace links. The isolation applies to the service's view, not to the kernel's accounting of the same processes.

PrivatePIDs= has operational constraints. It is supported for service units, but not with Type=forking, because the kernel terminates processes in a PID namespace when PID 1 exits. If the running kernel does not support PID namespaces, systemd ignores the setting. A deployment check that only reads the unit file can therefore report a setting that had no effect.

Removing non-process entries from proc

ProcSubset=pid changes the procfs mount option for the service. Files and directories that are not directly associated with process management and introspection become invisible. This can remove access to kernel APIs exposed through /proc, including configuration and status interfaces that tools may use without an obvious process-management purpose.

The systemd manual describes the option as useful for a small set of cases. Many normal applications use /proc entries outside the process subset. An application may start, answer a health check, and fail only when an optional feature reads a kernel interface later.

This is not the same control as hiding process metadata for other users. ProtectProc= and related mount options address which process information is visible under /proc/<pid>. ProcSubset=pid changes which parts of procfs exist at all.

What an investigator loses

Inside the namespace, a compromised service sees a smaller environment. That can slow discovery of adjacent processes, host-wide load, and unrelated services. It does not erase host evidence. Host process accounting, cgroups, auditd, the kernel log, and the host /proc remain available if those systems were configured and protected.

The important distinction is between evidence collection and service visibility. A service should not need host-wide process discovery to do its job. The response team still needs a protected host path to collect that evidence. If the service's diagnostics also run inside the sandbox, they may return an incomplete process list and can mislead an on-call engineer.

Build a tested policy

A useful baseline for a network service that does not inspect other processes may look like this:

[Service]
User=app
PrivatePIDs=yes
ProcSubset=pid
ProtectProc=invisible
NoNewPrivileges=yes

Repeated entries are merged where the directive supports it, but do not use repetition as a substitute for checking the effective value. Some services need ProcSubset=all because they collect their own kernel statistics. That exception should be documented per unit.

Run the complete application workflow after applying the settings. Start it, exercise scheduled work, request metrics, and stop it cleanly. Then inspect the host view:

systemctl show example.service -p PrivatePIDs -p ProcSubset -p MainPID
ps -o pid,ppid,user,comm -p "$(systemctl show -p MainPID --value example.service)"
readlink "/proc/$(systemctl show -p MainPID --value example.service)/ns/pid"

The namespace identifier should differ from the host process used for comparison. The host must still see the service process.

Keep the operational path

Sandboxing two different audiences requires two different paths. The service gets a narrow view of /proc. The responder gets an authenticated, logged host path to process, cgroup, network, and audit evidence. Test the responder path before an incident, and record where its output is stored independently of the compromised host.

PrivatePIDs= and ProcSubset=pid can reduce reconnaissance and accidental interference. They do not replace host monitoring, and they can make the service's own diagnostics less useful. Treat the visibility loss as part of the design, not as an unexpected incident symptom.

References