Challenge Medium

Lock Down Container Syscalls With Seccomp Profiles

Run a Deployment under the container runtime's seccomp profile, roll out a custom profile to the worker nodes, and fix a profile that blocks a syscall the application needs.

Scenario

The security team is rolling out seccomp in the beacon namespace. Seccomp limits which Linux system calls (syscalls) a container can make.

DeploymentState
beacon-apiRuns with seccomp explicitly turned off.
beacon-workerHas no seccomp settings. 2 replicas, one on each worker node.
beacon-syncUses a custom profile, beacon-strict.json, and keeps crashing.
Note

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.


Task

  1. Make the beacon-api Deployment in the beacon namespace run with the seccomp profile that the container runtime provides.
  2. Apply the profile /home/laborant/seccomp/no-chmod.json to the beacon-worker Deployment in the beacon namespace at container level, on its worker container, not at Pod level. Both replicas must run with it, and the profile must be available on both worker nodes.
  3. Fix the beacon-sync Deployment in the beacon namespace so that it runs:
    • Keep it on the beacon-strict.json profile.
    • Unblock only mkdir and mkdirat. Every other syscall in the profile must stay blocked.
    • Update the profile on both worker nodes.
Important

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

See: Restrict a Container's Syscalls with seccomp

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.


⚒ Test Cases