CKSKubernetes 1.35

Lessons

seccomp: syscall filtering with profiles that actually load

updated 2026-10-22 by seed

The three values

securityContext:
  seccompProfile:
    type: RuntimeDefault        # the container runtime's own allow-list
#    type: Localhost
#    localhostProfile: profiles/audit.json
#    type: Unconfined          # no filtering at all

RuntimeDefault is the one you should default to: it blocks the dangerous
syscalls (kexec_load, bpf, perf_event_open, …) while a normal app runs
fine. Unconfined is what the exam asks you to fix.

A custom profile that blocks one syscall

{
  "defaultAction": "SCMP_ACT_ALLOW",
  "architectures": ["SCMP_ARCH_X86_64", "SCMP_ARCH_X86", "SCMP_ARCH_X32"],
  "syscalls": [
    {
      "names": ["mkdir", "mkdirat"],
      "action": "SCMP_ACT_ERRNO"
    }
  ]
}
  • SCMP_ACT_ALLOW — allow
  • SCMP_ACT_ERRNO — deny, return EPERM to the process
  • SCMP_ACT_LOG — allow but log (audit mode)
  • SCMP_ACT_KILL_PROCESS — kill

Where the file has to be

localhostProfile is relative to the kubelet's seccomp root, which defaults
to /var/lib/kubelet/seccomp:

sudo mkdir -p /var/lib/kubelet/seccomp/profiles
sudo cp mkdir-deny.json /var/lib/kubelet/seccomp/profiles/
spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: profiles/mkdir-deny.json

The profile file must exist on the node that runs the Pod. If the task pins
the node, put it there; if not, put it on every node that could run it.

Pod level vs container level

spec:
  securityContext:
    seccompProfile: {type: RuntimeDefault}      # every container
  containers:
  - name: app
    securityContext:
      seccompProfile:
        type: Localhost                         # this one overrides
        localhostProfile: profiles/strict.json

Container-level wins. A Localhost at container level with no profile path is
invalid and the Pod is rejected.

Prove it

kubectl get pod app -n prod -o jsonpath='{.spec.containers[0].securityContext.seccompProfile}'
kubectl exec -n prod app -- grep -i seccomp /proc/self/status
# Seccomp: 2      (2 = filter mode, 0 = disabled)
kubectl exec -n prod app -- mkdir /tmp/x      # EPERM with the profile above

/proc/self/status is the honest check: Seccomp: 0 means nothing is applied,
whatever the manifest says.

The audit-profile task

"Create a profile that logs write for a workload without blocking it." Use
SCMP_ACT_LOG on the syscall you care about and SCMP_ACT_ALLOW as the default;
the audit lines land in the kernel log, visible with dmesg | grep audit.

Traps

  • The old annotation seccomp.security.alpha.kubernetes.io/pod is gone. Use the field.
  • A JSON file with a trailing comma fails silently at Pod start — validate with python3 -m json.tool profile.json.
  • Wrong relative path → failed to load seccomp profile: no such file.
  • Profiles are per node. nodeName plus a profile on one node is a valid exam answer; forgetting the other nodes is the usual miss.