# Privileged Container

> A privileged container has effectively root on the node: all Linux capabilities, host devices, and the ability to escape the container boundary. ZopNight checks 3 workload kinds. Most workloads that request it do not need it; the few that genuinely do are recognisable.

Source: https://zop.dev/integrations/kubernetes/recommendations/privileged-container
Updated: 2026-08-19

---

## What privileged actually grants

`securityContext.privileged: true` is not a partial elevation. It disables most of the isolation
that makes a container a container: every Linux capability is granted, `/dev` on the host is
visible, and AppArmor and seccomp profiles do not apply.

A process in a privileged container can mount the host filesystem, load kernel modules and access
other containers' namespaces. Compromising it is equivalent to compromising the node, and by
extension every workload scheduled there, plus the kubelet's credentials.

## The workloads that genuinely need it

A short list, and it is worth knowing so this finding is not applied blindly:

- **CNI plugins** configuring host networking
- **CSI drivers** mounting volumes into the host mount namespace
- **Node-level agents**: monitoring, security tooling, log collectors reading host paths
- **Anything managing kernel state**, such as tuning sysctls at boot

These are almost always DaemonSets shipped by an infrastructure vendor. A privileged application
Deployment is a different matter entirely.

## Usually it is one capability, not all of them

Most workloads that request privileged actually need a single capability. `NET_ADMIN` for network
manipulation, `SYS_TIME` for clock adjustment, `SYS_PTRACE` for a debugger.

Granting that one capability keeps every other boundary intact:

```yaml
securityContext:
  privileged: false
  capabilities:
    add: ["NET_ADMIN"]
```

The usual reason a workload is privileged is that somebody hit a permission error, set
`privileged: true`, and it worked.

## Selecting containers with privileged set to true

```bash
kubectl get deploy,statefulset,daemonset -A -o json | jq -r '
  .items[] | . as $w | .spec.template.spec.containers[]
  | select(.securityContext.privileged == true)
  | "\($w.kind) \($w.metadata.namespace)/\($w.metadata.name): \(.name)"'
```

## Preventing the class

Pod Security Admission at the `baseline` level rejects privileged pods at admission time. Applied
as a namespace label, it stops new ones arriving while you work through the existing list.
That matters more than the list itself, because otherwise the backlog refills.
