Minimize The Admission Of Containers With Capabilities
More Info:
Added Linux capabilities expand a containers privileges beyond the default set. Drop all capabilities where applications do not need them.
Risk Level
High
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
Identify pods using capabilities (any machine with kubectl access)
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.containers[*].securityContext.capabilities}{"\n"}{end}' \| grep -v '{}'Also include init containers:
kubectl get pods -A -o json | \jq -r '.items[] |.metadata.namespace as $ns |.metadata.name as $pod |(.spec.containers[]?,.spec.initContainers[]?) as $c |select($c.securityContext.capabilities != null) |[$ns, $pod, $c.name, ($c.securityContext.capabilities // {})] | @tsv' -
Map capabilities to owning teams and justify need
For each pod/container from step 1, capture its manifest and share with the owning team/application owner:kubectl get pod <pod-name> -n <namespace> -o yaml > /tmp/<namespace>-<pod-name>.yamlAsk them to confirm which listed capabilities are strictly required and whether the container can run with
ALLdropped. -
Decide namespace policy: which namespaces can/should forbid capabilities
Using the information from step 2, classify namespaces:- Namespaces where no containers need extra capabilities → candidates to enforce “drop all capabilities”.
- Namespaces with a few exceptional workloads → decide whether to:
- Move those workloads to a separate namespace, or
- Exempt the namespace for now and document the risk.
-
Design the admission policy to enforce dropping capabilities
Decide on your enforcement mechanism (example options to prepare for implementation):- ValidatingAdmissionPolicy / ValidatingAdmissionWebhook that rejects pods/containers unless:
securityContext.capabilities.dropcontains"ALL", andsecurityContext.capabilities.addis unset/empty.
- Limit the policy’s
namespaceSelectoror similar scoping so it only applies to namespaces identified in step 3.
- ValidatingAdmissionPolicy / ValidatingAdmissionWebhook that rejects pods/containers unless:
-
Update application manifests to be compliant before enforcing
For each workload in namespaces you plan to protect, adjust the manifests (local Git/IaC repo, not directly in-cluster) so containers explicitly drop all capabilities, for example:securityContext:runAsNonRoot: truecapabilities:drop:- ALLWhere teams have justified specific capabilities as required, either:
- Keep those workloads out of the strict namespaces, or
- Document and prepare explicit policy exceptions in the admission policy design.
-
Verify resulting posture after policy deployment
After implementing your chosen admission policy (outside the scope of this manual review), confirm:- New pods can only be created in protected namespaces if they drop all capabilities and do not add any.
- Periodically re-run:
Review any remaining capabilities and update namespace classification and policies as needed.kubectl get pods -A -o json | \jq -r '.items[] |.metadata.namespace as $ns |.metadata.name as $pod |(.spec.containers[]?,.spec.initContainers[]?) as $c |select($c.securityContext.capabilities.add != null and($c.securityContext.capabilities.add | length) > 0) |[$ns, $pod, $c.name, ($c.securityContext.capabilities.add // [])] | @tsv'
Using kubectl
# 1) List all pods with any explicit capabilities set (all namespaces)
# Run on: any machine with kubectl access
kubectl get pods --all-namespaces -o jsonpath='{range .items[?(@.spec.containers[*].securityContext.capabilities)]}{.metadata.namespace}{"\t"}{.metadata.name}{"\n"}{end}'
# Same for initContainers
kubectl get pods --all-namespaces -o jsonpath='{range .items[?(@.spec.initContainers[*].securityContext.capabilities)]}{.metadata.namespace}{"\t"}{.metadata.name}{"\n"}{end}'
Problem indication: Any pod listed here has at least one container or initContainer with capabilities defined; these need review.
# 2) For a specific namespace, show pods and whether any container sets capabilities
NAMESPACE=default
kubectl get pods -n "$NAMESPACE" -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name,CAPS:.spec.containers[*].securityContext.capabilities
Problem indication: Any non-empty CAPS field (e.g. map[add:[NET_ADMIN] drop:[ALL]]) means the pod is explicitly manipulating capabilities and must be reviewed.
# 3) Inspect full capability settings for a specific pod
NAMESPACE=default
POD=my-pod
kubectl get pod "$POD" -n "$NAMESPACE" -o yaml
What to look for as potential problems in the YAML:
securityContext.capabilities.addpresent and non-empty, for example:add: ["NET_ADMIN"]add: ["SYS_ADMIN", "NET_RAW"]
securityContext.capabilities.dropmissing, empty, or does not includeALL.- Containers with no
drop: ["ALL"]in namespaces where applications do not require Linux capabilities.
These locations should be checked:
.spec.containers[*].securityContext.capabilities.spec.initContainers[*].securityContext.capabilities.spec.ephemeralContainers[*].securityContext.capabilities(if used)
# 4) Summarize all added capabilities cluster-wide
kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{range .spec.containers[*]}{.name}{": "}{.securityContext.capabilities.add}{"; "}{end}{"\n"}{end}' \
| grep -v '\[\]' # filter out lines with empty add lists
Problem indication: Any line showing a non-empty add list (e.g. [NET_ADMIN], [SYS_ADMIN NET_RAW]) is a potential risk and should be justified or removed.
# 5) Verify after manual remediation (spot-check)
# Re-run capability listing for a namespace after you update manifests
NAMESPACE=default
kubectl get pods -n "$NAMESPACE" -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name,CAPS:.spec.containers[*].securityContext.capabilities
Verification indication: For namespaces where you decided all applications can run without Linux capabilities, the CAPS column should be empty or show only drop:[ALL] and no add entries.
Automation
#!/usr/bin/env bash
#
# Report pods whose containers add Linux capabilities or fail to drop all capabilities.
# Run on: any machine with kubectl access and current context set.
#
# Requires: kubectl, jq
set -euo pipefail
echo "Scanning all namespaces for capability usage..."
# 1) Pods where any container explicitly *adds* capabilities
echo
echo "=== Pods with explicitly ADDED capabilities (potentially high risk) ==="
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| {
ns: .metadata.namespace,
pod: .metadata.name,
containers: (
[
(.spec.initContainers // [] )[],
(.spec.containers // [] )[]
]
)
}
| .containers[]
| {
ns: .ns,
pod: .pod,
cname: .name,
adds: (.securityContext.capabilities.add // []),
drops: (.securityContext.capabilities.drop // [])
}
| select((.adds | length) > 0)
| "\(.ns)\t\(.pod)\t\(.cname)\tadd=\(.adds | join(\";\"))\tdrop=\(.drops | join(\";\"))"
' | column -t || echo "None found or jq error."
# 2) Pods where containers define capabilities but do NOT drop ALL
echo
echo "=== Pods with capabilities defined but NOT dropping ALL (review) ==="
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| {
ns: .metadata.namespace,
pod: .metadata.name,
containers: (
[
(.spec.initContainers // [] )[],
(.spec.containers // [] )[]
]
)
}
| .containers[]
| {
ns: .ns,
pod: .pod,
cname: .name,
adds: (.securityContext.capabilities.add // []),
drops: (.securityContext.capabilities.drop // [])
}
# Container has a capabilities section at all
| select((.adds | length) > 0 or (.drops | length) > 0)
# but does not drop ALL
| select((.drops | map(ascii_upcase) | index("ALL")) | not)
| "\(.ns)\t\(.pod)\t\(.cname)\tadd=\(.adds | join(\";\"))\tdrop=\(.drops | join(\";\"))"
' | column -t || echo "None found or jq error."
# 3) Summary counts
echo
echo "=== Summary ==="
echo "- Pods with any container that ADDS capabilities:"
kubectl get pods --all-namespaces -o json \
| jq '
.items[]
| [
(.spec.initContainers // [] )[],
(.spec.containers // [] )[]
]
| map(.securityContext.capabilities.add // [])
| map(length)
| add
' | awk '{ if ($1=="") print 0; else print $1; }'
echo "- Containers defining capabilities but NOT dropping ALL:"
kubectl get pods --all-namespaces -o json \
| jq '
[
.items[]
| {
ns: .metadata.namespace,
pod: .metadata.name,
containers: [
(.spec.initContainers // [] )[],
(.spec.containers // [] )[]
]
}
| .containers[]
| {
adds: (.securityContext.capabilities.add // []),
drops: (.securityContext.capabilities.drop // [])
}
| select((.adds | length) > 0 or (.drops | length) > 0)
| select((.drops | map(ascii_upcase) | index("ALL")) | not)
] | length
'
echo
echo "Review guidance:"
echo "- Any line in the first section (ADDED capabilities) indicates a pod that expands beyond default capabilities."
echo "- Any line in the second section indicates a container that defines capabilities but does not drop ALL."
echo "- For namespaces where applications do not require capabilities, ensure containers drop ALL and avoid add= entries."
How to interpret problematic output
- Any row in
Pods with explicitly ADDED capabilities (potentially high risk)indicates a container that is explicitly requesting extra Linux capabilities. These should be reviewed and justified; in namespaces that should not use capabilities, they are a problem. - Any row in
Pods with capabilities defined but NOT dropping ALL (review)shows containers that configure capabilities but do not includedrop: ["ALL"]. In namespaces that should drop all capabilities, these are non-compliant and should be redesigned or restricted by admission policy.