Lock Down Container Syscalls With Seccomp Profiles
Scenario
The security team is rolling out seccomp in the beacon namespace. Seccomp limits which Linux system calls (syscalls) a container can make.
| Deployment | State |
|---|---|
beacon-api | Runs with seccomp explicitly turned off. |
beacon-worker | Has no seccomp settings. 2 replicas, one on each worker node. |
beacon-sync | Uses a custom profile, beacon-strict.json, and keeps crashing. |
Task
- Make the
beacon-apiDeployment in thebeaconnamespace run with the seccomp profile that the container runtime provides. - Apply the profile
/home/laborant/seccomp/no-chmod.jsonto thebeacon-workerDeployment in thebeaconnamespace at container level, on itsworkercontainer, not at Pod level. Both replicas must run with it, and the profile must be available on both worker nodes. - Fix the
beacon-syncDeployment in thebeaconnamespace so that it runs:- Keep it on the
beacon-strict.jsonprofile. - Unblock only
mkdirandmkdirat. Every other syscall in the profile must stay blocked. - Update the profile on both worker nodes.
- Keep it on the
Work on dev-machine as the default laborant user. The beacon Pods run only on the worker nodes, node-01 and node-02, because the control plane node cplane-01 is tainted. From dev-machine, copy files to a worker node with scp and log in with ssh. laborant can use sudo on the nodes.
Do not change the container images or commands, and do not run any container as privileged.
Hint 1 | Where seccomp is set in a Pod
Seccomp is part of the securityContext, at Pod level or container level:
securityContext:
seccompProfile:
type: <type>
localhostProfile: <path> # used by one of the types only
kubectl explain pod.spec.securityContext.seccompProfile
Hint 2 | Checking whether a container is filtered
The kernel reports the seccomp mode of every process:
kubectl exec <pod> -n <namespace> -- grep Seccomp /proc/1/status
0 means no filter, 2 means a filter is active.
Hint 3 | Where custom profiles live
In this cluster, custom profiles are kept on each node in:
/var/lib/kubelet/seccomp/profiles/
localhostProfile is relative to the kubelet's seccomp directory, /var/lib/kubelet/seccomp/, so a file at /var/lib/kubelet/seccomp/profiles/app.json is referenced as profiles/app.json. The directory belongs to root. When the kubelet cannot load a profile, the reason is in the Pod's events:
kubectl describe pod <pod> -n <namespace>
scp <file> <node>:<path>
ssh <node>
Hint 4 | Reading a profile
A profile is JSON: a defaultAction for every syscall, and a list of syscalls rules that override it. A program's error message names the operation that failed, and that operation is carried out by one or more syscalls:
kubectl logs <pod> -n <namespace>
The kubelet reads a profile when a container starts, so a container that is already running keeps the filter it started with.