seccomp: syscall filtering with profiles that actually load
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— allowSCMP_ACT_ERRNO— deny, returnEPERMto the processSCMP_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." UseSCMP_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/podis 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.
nodeNameplus a profile on one node is a valid exam answer; forgetting the other nodes is the usual miss.