Skip to main content

The Seccomp Profile Is Set To docker/default In Pod

More Info:

Applying the default seccomp profile restricts the syscalls available to containers, reducing the kernel attack surface.

Risk Level

Medium

Address

Security

Compliance Standards

  • CIS Kubernetes

Triage and Remediation

Remediation

Manual Steps
  1. Identify pods and collect their seccomp settings

    • On any machine with kubectl access, list all pods and export their specs for review:
      kubectl get pods -A -o yaml > /tmp/all-pods-with-seccomp.yaml
    • Alternatively, spot-check a specific namespace:
      kubectl get pods -n NAMESPACE -o yaml > /tmp/namespace-pods-with-seccomp.yaml
  2. Review pods for explicit or inherited seccomp profiles

    • Search for seccompProfile usage:
      grep -n "seccompProfile:" -n /tmp/all-pods-with-seccomp.yaml
    • For pods of concern, inspect their security context to see whether they use the runtime default profile:
      kubectl get pod POD_NAME -n NAMESPACE -o yaml
    • In the output, look under:
      • .spec.securityContext.seccompProfile
      • .spec.containers[].securityContext.seccompProfile
      • .spec.initContainers[].securityContext.seccompProfile
        Check that type: RuntimeDefault is set where required.
  3. Decide which workloads must use the runtime default seccomp profile

    • For each pod/workload, determine:
      • Whether it is security-sensitive (public-facing, multi-tenant, or runs with elevated permissions).
      • Whether it needs a custom seccomp profile (e.g., legacy or low-level system tools) or can use the runtime default (type: RuntimeDefault).
    • Document any justified exceptions (pods that must use a custom profile or cannot yet be restricted) along with business/technical rationale.
  4. Update pod or controller manifests to use the runtime default seccomp profile

    • For pods you decide should use the default profile and that currently lack it, edit the owning resource (Deployment/StatefulSet/DaemonSet/Job/CronJob, or Pod manifest) on any machine with kubectl access:
      kubectl edit deployment DEPLOYMENT_NAME -n NAMESPACE
    • Under spec.template.spec.securityContext (pod-level) or under each container’s securityContext, add or adjust:
      securityContext:
      seccompProfile:
      type: RuntimeDefault
    • For workloads managed via GitOps or other IaC, make the same change in the source manifest instead of using kubectl edit, then apply:
      kubectl apply -f PATH/TO/MANIFEST.yaml
  5. Reconcile pods to pick up the new seccomp settings

    • For controllers (Deployments, etc.), ensure a rollout occurs so new pods use the updated security context:
      kubectl rollout restart deployment DEPLOYMENT_NAME -n NAMESPACE
      kubectl rollout status deployment DEPLOYMENT_NAME -n NAMESPACE
    • For standalone Pods not managed by a controller, delete and recreate them from the updated manifest:
      kubectl delete pod POD_NAME -n NAMESPACE
      kubectl apply -f UPDATED_POD_MANIFEST.yaml
  6. Verify the applied seccomp profile on running pods

    • After updates and rollouts, confirm that pods are now using the runtime default profile:
      kubectl get pod POD_NAME -n NAMESPACE -o yaml | \
      grep -A3 "seccompProfile"
    • Confirm that relevant pods show:
      seccompProfile:
      type: RuntimeDefault
    • Optionally, re-export and re-scan cluster-wide to ensure coverage:
      kubectl get pods -A -o yaml | grep -A3 "seccompProfile"
Using kubectl
# 1) List all pods and their seccompProfile (any machine with kubectl access)
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.securityContext.seccompProfile.type}{"\t"}{.spec.securityContext.seccompProfile.localhostProfile}{"\n"}{end}' \
| column -t

How to read this:

  • Column 1: Namespace
  • Column 2: Pod name
  • Column 3: Pod-level seccompProfile.type
  • Column 4: Pod-level seccompProfile.localhostProfile

Indications of a potential problem:

  • type is empty (no pod-level seccomp profile set).
  • type is Unconfined.
  • type is Localhost but localhostProfile does not correspond to your approved/default profile.
  • You rely only on container-level seccomp instead of pod-level, or there is inconsistency across pods.

# 2) For a specific pod, show full securityContext for pod and containers
# Replace <namespace> and <pod-name> with actual values
kubectl get pod -n <namespace> <pod-name> -o yaml | \
sed -n '/^spec:/,/^status:/p'

Focus on:

securityContext:
seccompProfile:
type: RuntimeDefault # desired example per benchmark
# or other type/value currently used

and any securityContext.seccompProfile under each container.

Indications of a potential problem:

  • Missing seccompProfile at pod level and at all container levels.
  • Explicit type: Unconfined.
  • type values that do not align with your chosen default (RuntimeDefault per remediation).

# 3) Identify pods with explicitly Unconfined seccomp at pod level
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{" "}{.spec.securityContext.seccompProfile.type}{"\n"}{end}' \
| awk '$3=="Unconfined"'

Any line returned here represents a pod that explicitly disables seccomp at the pod level and should be reviewed.


# 4) Identify pods with no pod-level seccompProfile
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{" "}{.spec.securityContext.seccompProfile.type}{"\n"}{end}' \
| awk 'NF<3 || $3==""'

Pods listed here rely entirely on container-level configuration or runtime defaults; they require manual review to ensure this is acceptable and consistent with the intent to use the default seccomp profile.


# 5) Inspect container-level seccomp configuration for a specific pod
kubectl get pod -n <namespace> <pod-name> -o jsonpath='{range .spec.containers[*]}{.name}{"\t"}{.securityContext.seccompProfile.type}{"\t"}{.securityContext.seccompProfile.localhostProfile}{"\n"}{end}'

Indications of a potential problem:

  • type is Unconfined.
  • type is empty and pod-level also has no seccompProfile.
  • Mixed usage within the same pod (some containers configured, some not), unless this is an intentional design and documented.

Verification after you make any manifest changes (no automated fix here):

# Re-run summary to confirm pods you changed now show the expected type (e.g., RuntimeDefault)
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.securityContext.seccompProfile.type}{"\t"}{.spec.securityContext.seccompProfile.localhostProfile}{"\n"}{end}' \
| column -t

Review that the pods you modified now have seccompProfile.type: RuntimeDefault (or your chosen default) and that no unexpected Unconfined or empty profiles remain, subject to your security policy and workload requirements.

Automation
#!/usr/bin/env bash
# Report Pods whose seccomp profile is NOT explicitly set to RuntimeDefault
# Run on any machine with kubectl access and current-context pointing to the target cluster.

set -euo pipefail

echo "Namespace,Pod,ContainerType,ContainerName,SeccompType,SeccompLocalhostProfile"

# 1) Check pod-level securityContext.seccompProfile
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| . as $pod
| (
.metadata.namespace as $ns
| .metadata.name as $podname
| .spec.securityContext.seccompProfile.type // "UNSET" as $type
| .spec.securityContext.seccompProfile.localhostProfile // "UNSET" as $lp
| [$ns,$podname,"pod","-", $type, $lp] | @csv
)
'

# 2) Check container-level securityContext.seccompProfile (overrides pod-level)
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| . as $pod
| .metadata.namespace as $ns
| .metadata.name as $podname
| (
.spec.containers[]? as $c
| [
$ns,
$podname,
"container",
$c.name,
($c.securityContext.seccompProfile.type // "UNSET"),
($c.securityContext.seccompProfile.localhostProfile // "UNSET")
] | @csv
),
(
.spec.initContainers[]? as $c
| [
$ns,
$podname,
"initContainer",
$c.name,
($c.securityContext.seccompProfile.type // "UNSET"),
($c.securityContext.seccompProfile.localhostProfile // "UNSET")
] | @csv
)
'

How to run (any machine with kubectl access):

chmod +x report-seccomp-runtime-default.sh
./report-seccomp-runtime-default.sh > seccomp-report.csv

Interpretation (what indicates a problem):

  • For this control, you want every workload to use the default runtime seccomp profile:

    • Pod-level or container-level SeccompType should be RuntimeDefault.
    • SeccompLocalhostProfile should typically be UNSET when SeccompType is RuntimeDefault.
  • Lines that are potential problems and need manual review:

    • SeccompType is UNSET
      → No explicit seccomp profile set; behavior depends on kubelet/container runtime defaults.

    • SeccompType is anything other than RuntimeDefault (e.g. Localhost, Unconfined)
      → Not using the default runtime profile; check if this is an intentional exception.

    • SeccompType is Localhost with a custom SeccompLocalhostProfile
      → Strong indication of non-default profile; validate the policy and exception process.

Use the CSV to filter for non-compliant entries, for example:

# Show all lines that are not explicitly RuntimeDefault
grep -v 'RuntimeDefault' seccomp-report.csv