Generate a seccomp profile from a workload
A useful seccomp profile is one your workload actually exercises -
not one a security analyst guessed at. The seccomp-gen operator
records the syscall surface of a target Pod through the
Tetragon bridge during a fixed time window,
then emits a SeccompTrainingProfile CR carrying a complete OCI
seccomp.json. You apply the profile to your workload as a
separate, explicit step.
Prerequisites
Section titled “Prerequisites”- ugallu umbrella chart installed with
seccomp-genand thetetragon-bridgesubchart enabled. - Tetragon installed and the bridge service reachable at
ugallu-tetragon-bridge.ugallu-system-privileged.svc:50051. - A workload with stable behaviour. New deployments still warming up are bad training subjects - capture them once they’ve reached steady state.
kubectl -n ugallu-system get deploy ugallu-seccomp-genkubectl -n ugallu-system-privileged get service ugallu-tetragon-bridgeIdentify the target
Section titled “Identify the target”Pick a Pod (or a label selector across multiple replicas). For a single pod:
kubectl -n payments get pods -l app=api# api-canary-7c4d 1/1 RunningRun the training
Section titled “Run the training”apiVersion: security.ugallu.io/v1alpha1kind: SeccompTrainingRunmetadata: name: payments-api-canary namespace: ugallu-systemspec: targetSelector: matchLabels: { app: api, tier: canary } targetNamespace: payments duration: 15m replicaRatio: 50 defaultAction: SCMP_ACT_ERRNOkubectl apply -f train.yamlkubectl -n ugallu-system get seccomptrainingruns -wThe run walks Pending -> Running -> Succeeded once the duration
expires. While running, the engine subscribes to the bridge filtered
by the matched Pod UIDs and accumulates the unique syscall surface,
debounced with a 30-second sliding window so a flurry of fork/exec
at workload start doesn’t drown out the steady-state surface.
Inspect the profile
Section titled “Inspect the profile”kubectl -n ugallu-system get seccomptrainingprofiles# NAME AGE SYSCALLS# payments-api-canary 15m 42
kubectl -n ugallu-system get seccomptrainingprofile payments-api-canary \ -o jsonpath='{.spec.profileJSON}' | jq .The output is a runtime-spec-compatible JSON:
{ "defaultAction": "SCMP_ACT_ERRNO", "syscalls": [ { "names": ["read", "write", "openat", "close", "fstat", "mmap", "munmap", "brk", "rt_sigaction", "futex", "clone", "execve", "exit_group"], "action": "SCMP_ACT_ALLOW" } ]}Apply the profile
Section titled “Apply the profile”The operator does not apply the profile to your workload for you - that’s an explicit human step. There are two ways:
Option A - localhost profile (most permissive cluster-wide)
Section titled “Option A - localhost profile (most permissive cluster-wide)”Drop the JSON onto every node where the workload runs (typically
under /var/lib/kubelet/seccomp/profiles/), then reference it from
the pod template:
spec: template: spec: securityContext: seccompProfile: type: Localhost localhostProfile: payments-api-canary.jsonA DaemonSet that mirrors SeccompTrainingProfile CRs into the
node directory is on the roadmap.
Option B - inline RuntimeDefault override (Kubernetes 1.27+)
Section titled “Option B - inline RuntimeDefault override (Kubernetes 1.27+)”Some clusters allow Localhost profiles to be loaded as
ConfigMaps via container runtime extensions. Check your runtime’s
docs. Failing that, copy the RuntimeDefault profile and merge
the training output by hand.
Validate
Section titled “Validate”Roll the new profile to one canary first. The profile is deny-by-default with an allowlist of observed syscalls - if your workload executes a code path that wasn’t exercised during training, the kernel will SIGSYS the offending syscall. Treat training duration like a coverage exercise: the longer the run + broader the workload, the safer the resulting profile.
Watch for SeccompTrainingFailed SEs - that fires when the
training engine couldn’t attach to the bridge, or the window
expired with no observed syscalls (target wasn’t doing anything).
Cleanup
Section titled “Cleanup”kubectl -n ugallu-system delete seccomptrainingrun payments-api-canaryThe corresponding SeccompTrainingProfile is owned by the run via
ownerRef and is GC’d by Kubernetes once the run is deleted - so
hold onto the profile JSON externally (committed to the GitOps
repo, ideally) before deleting the run.