audit_seccomp
The audit seccomp gadget provides a stream of events with syscalls that had their seccomp filters generating an audit log. An audit log can be generated in one of these two conditions:
- The Seccomp profile has the flag
SECCOMP_FILTER_FLAG_LOG
(supported from runc v1.2.0, see runc#3390) and returns any action other thanSECCOMP_RET_ALLOW
. - The Seccomp profile does not have the flag
SECCOMP_FILTER_FLAG_LOG
but returnsSCMP_ACT_LOG
orSCMP_ACT_KILL*
.
Getting started
- kubectl gadget
- ig
$ kubectl gadget run ghcr.io/inspektor-gadget/gadget/audit_seccomp:v0.39.0 [flags]
$ sudo ig run ghcr.io/inspektor-gadget/gadget/audit_seccomp:v0.39.0 [flags]
Flags
No flags.
Guide
First, we need to create a pod / container with a seccomp profile that executes some fordibben syscalls.
- kubectl gadget
- ig
We'll use the Security Profiles Operator to handle seccomp profiles, however them can be handled manually as explained in Restrict a Container's Syscalls with seccomp
- Install the Security Profiles Operator
- Install a SeccompProfile that logs the
mkdir
and blocks theunshare
syscalls.
# seccompprofile.yaml
apiVersion: security-profiles-operator.x-k8s.io/v1beta1
kind: SeccompProfile
metadata:
name: log
annotations:
description: "Log some syscalls"
spec:
defaultAction: SCMP_ACT_ALLOW
syscalls:
- action: SCMP_ACT_KILL
names:
- unshare
- action: SCMP_ACT_LOG
names:
- mkdir
$ kubectl apply -f seccompprofile.yaml
- Start a pod with that SeccompProfile.
# mypod.yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
securityContext:
seccompProfile:
type: Localhost
localhostProfile: operator/default/log.json
restartPolicy: Never
containers:
- name: container1
image: busybox
command: ["sh"]
args: ["-c", "while true ; do mkdir /tmp/dir42 ; unshare -i; sleep 1; done"]
$ kubectl apply -f mypod.yaml
- Prepare a Seccomp Profile.
{
"defaultAction": "SCMP_ACT_ALLOW",
"syscalls": [
{
"action": "SCMP_ACT_KILL",
"names": [
"unshare"
]
}
]
}
Create a container using that profile:
$ docker run --name test-audit-seccomp -d --security-opt seccomp=profile.json \
busybox /bin/sh -c 'while true ; do unshare -i; sleep 1 ; done'
Then, start the audit_seccomp gadget and observe how it logs the unshare
syscall being denied.
- kubectl gadget
- ig
$ kubectl gadget run audit_seccomp:v0.39.0
K8S.NODE K8S.NAMESPACE K8S.PODNAME K8S.CONTAINERN… COMM PID TID CODE SYSCALL
minikube-docker default mypod container1 mkdir 60482 60482 …_RET_LOG SYS_MKDIR
minikube-docker default mypod container1 unshare 60483 60483 …L_THREAD SYS_UNSH…
minikube-docker default mypod container1 mkdir 60553 60553 …_RET_LOG SYS_MKDIR
minikube-docker default mypod container1 unshare 60554 60554 …L_THREAD SYS_UNSH…
^C
$ sudo -E ig run audit_seccomp:v0.39.0
RUNTIME.CONTAINERNAME COMM PID TID CODE SYSCALL
test-audit-seccomp unshare 485855 485855 …_KILL_THREAD SYS_UNSHARE
test-audit-seccomp unshare 485865 485865 …_KILL_THREAD SYS_UNSHARE
test-audit-seccomp unshare 485868 485868 …_KILL_THREAD SYS_UNSHARE
test-audit-seccomp unshare 485888 485888 …_KILL_THREAD SYS_UNSHARE
^C
In the previous examples, it is straightforward why the application is performing the syscall. The unshare program executes the unshare syscall and the mkdir program executes the mkdir syscall. For bigger applications, it can be useful to show the user stack trace.
- kubectl gadget
- ig
$ kubectl gadget run audit_seccomp:v0.39.0 --collect-ustack -o jsonpretty
...
"ustack": {
"addresses": "[0]0x000000000040332e; [1]0x00000000004771e6; [2]0x000000000047752e; [3]0x000000000048250b; [4]0x00000000004829ae; [5]0x0000000000482a7e; [6]0x0000000000482afe; [7]0x0000000000482b7e; [8]0x0000000000435a9d; [9]0x00000000004625a1; ",
...
"symbols": "[0]runtime/internal/syscall.Syscall6; [1]syscall.Syscall; [2]syscall.Syscall.abi0; [3]golang.org/x/sys/unix.Chroot; [4]main.level3; [5]main.level2; [6]main.level1; [7]main.main; [8]runtime.main; [9]runtime.goexit.abi0; "
}
^C
$ sudo -E ig run audit_seccomp:v0.39.0 --collect-ustack -o jsonpretty
...
"ustack": {
"addresses": "[0]0x000000000040332e; [1]0x00000000004771e6; [2]0x000000000047752e; [3]0x000000000048250b; [4]0x00000000004829ae; [5]0x0000000000482a7e; [6]0x0000000000482afe; [7]0x0000000000482b7e; [8]0x0000000000435a9d; [9]0x00000000004625a1; ",
...
"symbols": "[0]runtime/internal/syscall.Syscall6; [1]syscall.Syscall; [2]syscall.Syscall.abi0; [3]golang.org/x/sys/unix.Chroot; [4]main.level3; [5]main.level2; [6]main.level1; [7]main.main; [8]runtime.main; [9]runtime.goexit.abi0; "
}
^C
Finally, clean the system:
- kubectl gadget
- ig
$ kubectl delete -f mypod.yaml
$ kubectl delete -f seccompprofile.yaml
$ docker rm -f test-trace-bind