×

The Advanced Audit Logging Framework provided in OKD Security Profiles Operator (SPO) 0.10.0 provides logging of container activities in an Fedora CoreOS (FCOS) container back to the hosting cluster. With the Advanced Audit Logging Framework, you can correlate an OKD user with their direct actions on the node during oc exec, oc rsh, and oc debug sessions. The advanced audit logging results in detailed logs in a JSON Lines format.

Benefits of Advanced Audit Logging Framework

The kubectl exec, oc exec, oc rsh and oc debug commands do not pass user authentication details into the exec session on the container, making it hard to correlate Kubernetes user actions caused by actions on the host. The audit logger in SPO addresses this with mutating webhooks that inject the request UID from the Kubernetes API server as an environment variable into the session. Every request to the API server including the request to start a new exec session has a request UID. This request UID is then logged by the Advanced Audit Logging Framework. The request ID is used to correlate the activity with the API server audit logs, providing an audit trail within the node.

With the addition of the Advanced Audit Logging Framework, SPO now has two use cases:

  • Pod auditing

  • Node auditing

The use of privileged seccompProfile configuration is required only for the case of node auditing.

The Security Profiles Operator supports only Fedora CoreOS (FCOS) worker nodes appropriate to the version of OKD in use.

Red Hat Enterprise Linux (RHEL) nodes are not supported.

Performance considerations

It is important to consider the performance cost of using seccomp profiles for extensive logging. SPO is designed to minimize this impact by primarily logging only process creations and handling them asynchronously. This approach helps prevent logging from becoming a bottleneck on your nodes.

The Advanced Audit Logging feature uses eBPF as a supplemental data source. While it is possible for eBPF to be used as a primary data source for this type of logging, that functionality is not currently a configurable feature within the Operator. For most use cases, the default asynchronous, process-creation-focused logging approach provides an excellent balance between security visibility and cluster performance.

Prerequisites for use of the Advanced Audit Logging Framework

Before enabling the Advanced Audit Logging Framework, ensure the following requirements are met.

Security Profiles Operator version 0.10.0 or later is installed. Those instructions can be found at Installing the Security Profiles Operator. The Advanced Audit Logging Framework requires Security Profiles Operator version 0.10.0 or later.

For node debugging sessions:

  • To audit oc debug node sessions, CRI-O version 1.33 or later is required. It is available in OKD 4.20 or later.

  • The --privileged-seccomp-profile flag must be configured in CRI-O to apply seccompProfiles to privileged containers.

  • The supported Linux used with the Advanced Audit Logging Framework is Fedora CoreOS (FCOS) running in a container in OKD 4.20 or later.

If you are using the CRI-O runtime, you must configure it to allow seccompProfile to be applied to privileged containers. Add the following flag to your CRI-O runtime configuration: --privileged-seccomp-profile=/var/lib/kubelet/seccomp/operator/profile1.json. This is explained in more detail in the Advanced Audit Logging installation and enablement steps. The --privileged-seccomp-profile flag is available starting with OCP 4.20 and later.

If you are using any version of SPO before 0.9.0, you must perform a migration procedure to install versions 0.9.0 or 0.10.0. The migration procedure converts SPO to operate on cluster-scoped resources.

First-time installation of SPO version 0.10.0 does not require migration. Also, if you are currently on SPO 0.9.0, you do not require migration and can directly upgrade to SPO 0.10.0.

Do not attempt to upgrade directly from SPO versions before 0.9.0 to either 0.9.0 or 0.10.0 if you are currently running SPO. You must perform the migration procedure to convert SPO for operation at the cluster level.

This change allows Advanced Audit Logging of events inside the worker node.

This capability is not provided for control nodes since SPO does not operate on etcd nodes.

The Audit JSON log enricher

The SPO Advanced Audit Logging Framework is enabled by the Audit JSON log enricher. Similar to the log enricher feature, the Audit JSON log enricher watches the auditd (/var/log/audit/audit.log) or the syslog (/var/log/syslog) daemons and generates a new audit log in JSON lines format.

Each JSON line includes the following:

  • Timestamp: When the activity happened, shown in a standard ISO format

  • Executable Name: The name of the program that was run (bash, ls).

  • Linux Command Line Arguments (cmdline): The extra instructions given when the program was started (ls -l /home).

  • User and Group IDs (UID/GID): The identification numbers of the system user who ran the program.

  • System Calls (syscalls): A list of system calls (syscalls) that the process made

This log format and configuration is similar to how Kubernetes records audit logs. This is useful for:

  • Seeing what users and automated processes are doing inside a pod.

  • Tracking when someone uses commands such as kubectl exec to enter a running container and run commands or scripts.

  • Monitoring activities in debug containers where users might run various tools.

Kubernetes API log compared to Advanced Audit Logging output

To understand the value of Advanced Audit Logging, compare the Kubernetes API Server Audit Log to the Advanced Audit Logging output:

Kubernetes API Server Audit Log
{
  "kind": "Event",
  "apiVersion": "audit.k8s.io/v1",
  "level": "Metadata",
  "auditID": "4d434cd4-xxxx-xxxx-xxxx-2d9aa46292ce",
  "stage": "ResponseComplete",
  "requestURI": "/api/v1/namespaces/test-namespace/pods/test-pod/exec?command=sh&command=-c&command=touch+/tmp/testfile.txt&container=nginx",
  "verb": "create",
  "user": {
    "username": "kube:admin",
    "groups": ["system:cluster-admins", "system:authenticated"]
  },
  "sourceIPs": ["xxx.xxx.xxx.xxx"],
  "userAgent": "oc/4.19.0 (linux/amd64)",
  "objectRef": {
    "resource": "pods",
    "namespace": "test-namespace",
    "name": "test-pod",
    "subresource": "exec"
  },
  "responseStatus": {
    "code": 101
  },
  "requestReceivedTimestamp": "2026-02-16T14:01:06.056518Z",
  "annotations": {
    "authorization.k8s.io/decision": "allow",
    "authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding...",
    "execmetadata.spo.io/SPO_EXEC_REQUEST_UID": "aec3e0e1-xxxx-xxxx-xxxx-a7c58241f1a9"
  }
}

The correlation key is the SPO_EXEC_REQUEST_UID on the last line in the above file.

Advanced Audit Logging Output
{
  "auditID": "d586679d-xxxx-xxxx-xxxx-9dc8ab273065",
  "cmdLine": "touch /tmp/testfile.txt ",		// Linux command with arguments
  "executable": "/bin/dash",
  "gid": 0,
  "node": {
    "name": "worker-1"
  },
  "pid": 144968,
  "requestUID": "aec3e0e1-xxxx-xxxx-xxxx-a7c58241f1a9", // Correlation key
  "resource": {
    "container": "nginx",
    "namespace": "test-namespace",
    "pod": "test-pod"
  },
  "syscalls": ["execve"],
  "timestamp": "2026-02-16T14:01:07.000Z",
  "uid": 0,
  "version": "spo/v1_alpha"
}

Enabling Advanced Audit Logging

To enable Advanced Audit Logging, configure the Audit JSON log enricher and specify a set of filters to only log user activity.

Procedure
  1. Enable the JSON enricher by running the following command:

    # kubectl -n openshift-security-profiles patch spod spod --type=merge -p '{"spec":{"enableJsonEnricher":true}}'

    Monitor the SPOD pods for correct restart and wait for all SPOD pods to show Running before proceeding.

  2. Check the pods for application of the change with the following command:

    $ oc get pods -n openshift-security-profiles -l name=spod -w

    Wait until all SPOD pods show Running before proceeding.

    Each configuration change triggers a restart of the SPOD pods. After applying a patch, wait for all SPOD pods to return to the Running state before continuing.

    The Audit JSON log enricher uses eBPF as a supplemental data source. While processing auditd logs from /var/log/audit/audit.log, the enricher attempts to fetch ephemeral data from /proc/<pid> directories. Due to a race condition, these files might be deleted before they can be read. To ensure data completeness, the enricher falls back to fetching the necessary information from eBPF whenever it is not found in /proc/<pid>.

Audit JSON Log Enricher configuration

The Audit JSON Log Enricher requires some configuration to set interval, configure the destination of the log data and set the audit log file path. This procedure demonstrates how to set up and fine tune your Advanced Audit Logging Framework audit logs.

Each configuration change triggers a restart of the SPOD pods. After applying a patch, wait for all SPOD pods to return to the Running state before continuing.

Setting the audit log interval determines how often audit logs are created using the auditLogIntervalSeconds option.

Procedure
  1. Configure the audit log interval to 30 seconds by using the following command:

    # kubectl -n openshift-security-profiles patch spod spod --type=merge -p '{"spec":{"enableJsonEnricher":true,"verbosity":0,"jsonEnricherOptions":{"auditLogIntervalSeconds":30}}}'

    Wait until all SPOD pods show Running before proceeding. By default, audit logs go to your standard output in JSON lines format. You can send them to a file instead.

    Configure the security profiles operator to store the log file on the node. Update the security-profiles-operator-profile ConfigMap with two keys. This example yaml uses both keys to set up a host path volume at /tmp/logs.

  2. Save this JSON in a file, such as patch-volume-source.json and check it using the following command:

    $ cat patch-volume-source.json
    {
      "data": {
        "json-enricher-log-volume-mount-path": "/tmp/logs",
        "json-enricher-log-volume-source.json": "{\"hostPath\": {\"path\": \"/tmp/logs\",\"type\": \"DirectoryOrCreate\"}}"
      }
    }
    • json-enricher-log-volume-source.json: Defines the type of volume (for example, a host path and empty directory) where logs will be stored. This must be a JSON string representing a corev1.VolumeSource object.

    • json-enricher-log-volume-mount-path: Specifies the directory path where the log file will be generated.

  3. Update the config map by saving this JSON in this file called patch-volume-source.json and then update the config map with the following command:

    # kubectl patch configmap security-profiles-operator-profile -n openshift-security-profiles --patch-file patch-volume-source.json

    Wait until all SPOD pods show Running before proceeding.

  4. To set the audit log file path, configure the JSON log enricher with the full path to your audit log file by including the filename, using this command:

    # kubectl -n openshift-security-profiles patch spod spod --type=merge -p '{"spec":{"enableJsonEnricher":true,"verbosity":0,"jsonEnricherOptions":{"auditLogPath":"/tmp/logs/audit1.log"}}}'

    Wait until all SPOD pods show Running before proceeding

Audit log file fine-tuning and rotation

For audit logging to a file, you can manage file size and how long each file is kept. These options are similar to Kubernetes API server log settings.

Procedure
  1. You configure these by patching the JSON log enricher options:

    # kubectl -n openshift-security-profiles patch spod spod --type=merge -p '{"spec":{"enableJsonEnricher":true,"verbosity":0,"jsonEnricherOptions":{"auditLogPath":"/tmp/logs/audit1.log","auditLogMaxSize":500,"auditLogMaxBackups":2,"auditLogMaxAge":10}}}'

    Wait until all SPOD pods show Running before proceeding.

    • auditLogMaxSize: The maximum size (in megabytes) a log file can reach before it’s rotated (a new file is started).

    • auditLogMaxBackups: The maximum number of older, rotated log files to keep. Set to 0 for no limit.

    • auditLogMaxAge: The maximum number of days to keep old log files.

  2. Increase the logging level for the JSON log enricher container to help with debugging. A value of 0 sets minimal logs. A value of 1 sets more detailed logs. You can choose either of these two levels and enable either level with the following command:

    # kubectl -n openshift-security-profiles patch spod spod --type=merge -p '{"spec":{"enableJsonEnricher":true, "verbosity": 1}}'

    Wait until all SPOD pods show Running before proceeding.

Advanced Audit Logs for a specific pod

To enable single pod log activity, create a SeccompProfile to log specific syscalls such as execve and clone a ProfileBinding to automatically apply this profile to pods in a target namespace. The SeccompProfile applies to the cluster and the ProfileBinding applies to the workloads in that namespace.

With CRI-O versions 1.33 and newer, starting with OKD 4.20, a feature was introduced to allow SeccompProfiles for privileged containers. You can apply the SecompProfile we created to the CRI-O configuration. The key is to configure the CRI-O runtime to use the profile by passing an additional flag.

To do this, you must add the flag –privileged-seccomp-profile to the CRI-O runtime configuration. This step ensures that even privileged debugging pods are subject to the SeccompProfile logging, maintaining complete audit coverage.

You must bind the profile to a namespace in order to apply it to a workload. This will automatically apply the profile to new pods in the default namespace.

Procedure
  1. Create a file such as profile1.yaml with the following content:

    apiVersion: security-profiles-operator.x-k8s.io/v1beta1
    kind: SeccompProfile
    metadata:
      name: profile1
      namespace: openshift-security-profiles
    spec:
      defaultAction: SCMP_ACT_ALLOW
      syscalls:
      - action: SCMP_ACT_LOG
        names:
          - execve
          - clone
          - getpid

    This profile allows all normal actions (defaultAction: SCMP_ACT_ALLOW). It specifically tells the system to log when a process tries to run a new program (execve), create a new process (clone), or get its own process ID (getpid). These actions often indicate user interaction within a pod.

  2. Use`kubectl apply` to apply this SeccompProfile profile to your cluster as in the following command:

    # kubectl apply -f profile1.yaml

    SPO must use the privileged SeccompProfile

  3. Create a file named image_sec_comp.yaml containing the following yaml:

    apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
    kind: ProfileBinding
    metadata:
      namespace: default
      name: all-pod-binding
    spec:
      profileRef:
        kind: SeccompProfile
        name: profile1
      image: "*"
  4. Apply the binding using the following command:

    # kubectl apply -f image_sec_comp.yaml
  5. Label the namespace to activate it using the following command:

    # kubectl label ns default spo.x-k8s.io/enable-binding=true
  6. Create a pod using the profile:

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
      labels:
        app: my-app
    spec:
      securityContext:
        SeccompProfile:
          type: Localhost
          localhostProfile: operator/profile1.json
      containers:
        - name: nginx
          image: quay.io/security-profiles-operator/test-nginx:1.19.1
    • type: Localhost means you are using a profile you have defined in the cluster.

    • localhostProfile: operator/profile1.json tells the pod to use the profile1 you created. The operator/ part indicates where the Security Profiles Operator stores these profiles.

  7. Apply the pod definition to create the pod by running the following command:

    # kubectl apply -f my-pod.yaml
  8. Exec/rsh into the pod and run the following command:

    # kubectl exec -it my-nginx-pod -- /bin/sh
  9. Create an empty file by running this command:

    # touch /tmp/audittest/demo-file
    • To monitor the advanced audit log tail, use the following command:

      # kubectl -n openshift-security-profiles logs --since=1m --selector name=spod -c json-enricher --max-log-requests 6 -f
    • Alternatively, to monitor or inspect the advanced audit log file, you need to identify the node on which the pod is scheduled:

      # kubectl get pod my-pod -o wide

      The audit log file specified in the auditLogPath is written to the node’s file system where the pod is running. To monitor or inspect the audit logs, you must access the node directly and check the file at the specified path such as /tmp/logs/audit1.log.

  10. SSH to a node by using the following command:

    $ sudo ssh core@<node-name>
  11. View the audit log by using the following command:

    $ cat /tmp/logs/audit1.log

    Example output

    {
    "auditID": "a1b2c3d4-e5f6-7890-abcd-111111111111",
    "cmdLine": "mkdir /tmp/audittest ",
    "executable": "/bin/bash",
    "gid": 0,
    "node": {"name": "worker-1"},
    "pid": 27184,
    "requestUID": "f011c4a3-b20e-44ed-bb91-23e03ae31b3e",
    "resource": {
    "container": "nginx",
    "namespace": "default",
    "pod": "my-pod"
    },
    "syscalls": ["getpid", "execve"],
    "timestamp": "2026-02-16T06:34:53.000Z",
    "uid": 0,
    "version": "spo/v1_alpha"
    }
    {
    "auditID": "a1b2c3d4-e5f6-7890-abcd-222222222222",
    "cmdLine": "touch /tmp/audittest/demo-file ",
    "executable": "/bin/bash",
    "gid": 0,
    "node": {"name": "worker-1"},
    "pid": 27274,
    "requestUID": "f011c4a3-b20e-44ed-bb91-23e03ae31b3e",
    "resource": {
    "container": "nginx",
    "namespace": "default",
    "pod": "my-pod"
    },
    "syscalls": ["getpid", "execve"],
    "timestamp": "2026-02-16T06:35:02.000Z",
    "uid": 0,
    "version": "spo/v1_alpha"
    }

    By following above steps, you can enable and monitor audit logs in JSON lines format for your Kubernetes pods, giving you better visibility into their activities.

Monitoring the audit logs

There are two ways to monitor the advanced audit logs generated by the json-enricher container. By following these steps you can enable and monitor audit logs in JSON lines format for your Kubernetes pods, giving you better visibility into their activities.

Procedure
  1. To monitor the advanced audit log tail use the following command:

    # kubectl -n openshift-security-profiles logs --since=1m --selector name=spod -c json-enricher --max-log-requests 6 -f
  2. To monitor the advanced audit log file, it is specified in the auditLogPath and written to the node’s file system where the pod is running. To monitor or inspect the audit logs, you must access the node directly and check the file at the specified path such as /tmp/logs/audit1.log.

  3. Identify the node on which the pod is scheduled using the following command:

    # kubectl get pod my-pod -o wide
  4. SSH to a node with the following command:

    $ sudo ssh core@<node-name>
  5. View the audit log with the following command:

    $ cat /tmp/logs/audit1.log

    The example output should look like this:

    {
    "auditID": "a1b2c3d4-e5f6-7890-abcd-111111111111",
    "cmdLine": "mkdir /tmp/audittest ",
    "executable": "/bin/bash",
    "gid": 0,
    "node": {"name": "worker-1"},
    "pid": 27184,
    "requestUID": "f011c4a3-b20e-44ed-bb91-23e03ae31b3e",
    "resource": {
    "container": "nginx",
    "namespace": "default",
    "pod": "my-pod"
    },
    "syscalls": ["getpid", "execve"],
    "timestamp": "2026-02-16T06:34:53.000Z",
    "uid": 0,
    "version": "spo/v1_alpha"
    }
    {
    "auditID": "a1b2c3d4-e5f6-7890-abcd-222222222222",
    "cmdLine": "touch /tmp/audittest/demo-file ",
    "executable": "/bin/bash",
    "gid": 0,
    "node": {"name": "worker-1"},
    "pid": 27274,
    "requestUID": "f011c4a3-b20e-44ed-bb91-23e03ae31b3e",
    "resource": {
    "container": "nginx",
    "namespace": "default",
    "pod": "my-pod"
    },
    "syscalls": ["getpid", "execve"],
    "timestamp": "2026-02-16T06:35:02.000Z",
    "uid": 0,
    "version": "spo/v1_alpha"
    }

Auditing node debugging sessions

To audit kubectl debug sessions, you must enable privileged seccomp profiles in CRI-O.

If you are using the CRI-O runtime, you must configure it to allow seccomp profiles on privileged containers by adding the --privileged-seccomp-profile=/var/lib/kubelet/seccomp/operator/profile1.json flag to your CRI-O runtime configuration.

The --privileged-seccomp-profile flag is available starting with OKD 4.20 or later and CRI-O version 1.33 or later.

Procedure
  1. SSH into the target node using the following command:

    # ssh core@<node_ip_address>
  2. Check to see if the files are there:

    # ls /var/lib/kubelet/seccomp/operator/

    Example output

    # kubelet-config.json  profile1.json
  3. Stop the kubelet with the following commands:

    # systemctl stop kubelet
  4. Stop CRI-O with the command:

    # systemctl stop crio
  5. Set the CRI-O options with the following command:

    # echo "CRIO_CONFIG_OPTIONS --privileged-seccomp-profile=/var/lib/kubelet/seccomp/operator/profile1.json" > /etc/sysconfig/crio
  6. Now restart the cubelet with this command:

    # systemctl start kubelet
  7. Restart CRI-O with this command:

    # systemctl start crio
  8. To audit kubectl debug sessions, run the following command:

    # kubectl debug node/<node_name> -it --image=ubuntu -- bash

    Create the file on the container for the debugging information.

  9. chroot to the host with this command:

    # chroot /host
  10. Go into the /tmp directory with this command:

    # cd /tmp
  11. Create an empty file named demonodedebug with this command:

    # touch demonodedebug
  12. Exit the node with the command:

    # exit
  13. To monitor the logs, SSH to a node with this command:

    $ sudo ssh core@<node_name>
  14. View the audit log using this command:

    $ cat /tmp/logs/audit1.log

    Example output:

    {
      "auditID": "edce381a-998d-4f3f-99d8-d0c4d0c8a613",
      "cmdLine": "touch demonodedebug",
      "executable": "/usr/bin/bash",
      "gid": 0,
      "node": {"name": "worker-1"},
      "pid": 99086,
      "resource": {
        "container": "container-00",
        "namespace": "openshift-security-profiles",
        "pod": "worker-1-debug"
      },
      "syscalls": ["execve", "getpid"],
      "timestamp": "2026-02-12T13:50:11.000Z",
      "uid": 0,
      "version": "spo/v1_alpha"
    }

Correlate with Kubernetes audit logs

Use the requestUID from the Security Profiles Operator (SPO) log to find the corresponding API server log entry, confirming who initiated the session.

Procedure
  1. Start the pod by running the following command:

    $ oc exec my-pod -c nginx -- sh -c "touch /tmp/testfile.txt"
  2. Identify the node where the pod is running:

    $ NODE=$(oc get pod my-pod -o jsonpath='{.spec.nodeName}')
  3. Access the node and check the JSON enriched audit log using the following commands:

    # oc debug node/$NODE
    # chroot /host
    # grep "testfile" /tmp/logs/audit1.log | jq .

Audit JSON Log Enricher Output

The Audit JSON Log Enricher captures two entries for this exec session, the SPO-EXEC_REQUEST_UID injection and the command run on the pod. They are connected by looking for the common UID value.

  1. The first listing is the container runtime wrapper.

    {
      "auditID": "062e2bd2-xxxx-xxxx-xxxx-57fb39d65a99",
      "cmdLine": "env SPO_EXEC_REQUEST_UID=aec3e0e1-xxxx-xxxx-xxxx-a7c58241f1a9 sh -c touch /tmp/testfile.txt ",
      "executable": "/usr/bin/crun",
      "pid": 144966,
      "requestUID": "aec3e0e1-xxxx-xxxx-xxxx-a7c58241f1a9",
      "resource": {
        "container": "nginx",
        "namespace": "default",
        "pod": "my-pod"
      },
      "node": {
        "name": "worker-1"
      },
      "syscalls": ["execve", "getpid", "clone"],
      "timestamp": "2026-02-16T14:01:07.000Z"
    }
  2. The second listing is the actual command executed.

    {
      "auditID": "d586679d-xxxx-xxxx-xxxx-9dc8ab273065",
      "cmdLine": "touch /tmp/testfile.txt ",
      "executable": "/bin/dash",
      "pid": 144968,
      "requestUID": "aec3e0e1-xxxx-xxxx-xxxx-a7c58241f1a9", // Correlation key
      "resource": {
        "container": "nginx",
        "namespace": "default",
        "pod": "my-pod"
      },
      "node": {
        "name": "worker-1"
      },
      "syscalls": ["execve"],
      "timestamp": "2026-02-16T14:01:07.000Z"
    }
  3. You can search the Kubernetes API audit log by using the requestUID with the following command:

    $ oc adm node-logs --role=master --path=kube-apiserver/audit.log | grep request_UID

Kubernetes API audit log output

The output of the Kubernetes API audit log is YAML. It contains the SPO_EXEC_REQUEST_UID field which provides the correlation key with which you can search the Advanced Audit Logging output.

{
  "kind": "Event",
  "apiVersion": "audit.k8s.io/v1",
  "level": "Metadata",
  "auditID": "4d434cd4-xxxx-xxxx-xxxx-2d9aa46292ce",
  "stage": "ResponseComplete",
  "requestURI": "/api/v1/namespaces/test-namespace/pods/test-pod/exec?command=sh&command=-c&command=touch+/tmp/testfile.txt&container=nginx",
  "verb": "create",
  "user": {
    "username": "kube:admin",
    "groups": ["system:cluster-admins", "system:authenticated"]
  },
  "sourceIPs": ["xxx.xxx.xxx.xxx"],
  "userAgent": "oc/4.19.0 (linux/amd64)",
  "objectRef": {
    "resource": "pods",
    "namespace": "default",
    "name": "my-pod",
    "subresource": "exec"
  },
  "responseStatus": {
    "code": 101
  },
  "requestReceivedTimestamp": "2026-02-16T14:01:06.056518Z",
  "annotations": {
    "authorization.k8s.io/decision": "allow",
    "authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding...",
    "execmetadata.spo.io/SPO_EXEC_REQUEST_UID": "aec3e0e1-xxxx-xxxx-xxxx-a7c58241f1a9"
}

The final field in this example, SPO_EXEC_REQUEST_UID is the correlation key.

Correlation key

The connection of the two correlation keys enables administrators to establish a complete audit trail. Who executed a command, from Kubernetes API audit log kube:admin at IP xxx.xxx.xxx.xxx and what the command did at the system level, can be found in the SPO JSON Enricher log touch /tmp/testfile.txt.

The requestUID field in Audit JSON Enricher logs matches the annotations.execmetadata.spo.io/SPO_EXEC_REQUEST_UID annotation in the Kubernetes API audit log.

aec3e0e1-xxxx-xxxx-xxxx-a7c58241f1a9

Correlating with API Server Audit Log

By default, when you use the kubectl exec command to access a pod or container, Kubernetes does not pass the user’s authentication details into that session’s environment. This means the Audit JSON log enricher cannot provide audit information for exec commands. The UID or GID shown, maps to the system user. In most cases this would be the root user.

To address this, the Audit JSON log enricher relies on mutating webhooks (execmetadata.spo.io and nodedebuggingpod.spo.io). The webhook injects the exec requestUID as an environment variable into the exec session. When the administrator enables audit logging on the API server, the webhooks add the SPO_EXEC_REQUEST_UID audit annotation. The API server audit log contains this information. This request ID is also available in the JSON lines produced by the Audit JSON log enricher, specifically within the requestUID field.

By default, these webhooks are enabled for all namespaces with the Audit JSON log enricher enabled. To reduce the scope of this webhook you can disable it for certain namespaces.

Procedure
  1. Edit the spod security profile by running the following command:

    $ oc edit spod spod -n openshift-security-profiles
  2. Add webhookOptions to the spec. Locate the spec section and add the following webhookOptions block to instruct the webhook to apply to a specific namespace.

    spec:
      webhookOptions:
        - name: execmetadata.spo.io # or nodedebuggingpod.spo.io
          namespaceSelector:
          #...add rules

    After saving your changes, the Operator reconfigures the mutating webhook, allowing request details to be passed into oc exec sessions cluster-wide.

Using the mutating webhook

This webhook injects the environment variable SPO_EXEC_REQUEST_UID into your exec request. If a container in your pod already defines an environment variable with this exact name, the webhook injected value will override it for this exec session.

When you use kubectl debug node/<node_name>, the nodedebuggingpod.spo.io webhook automatically injects the SPO_EXEC_REQUEST_UID environment variable into the debug pod.

The Debug Pod

This webhook primarily identifies kubectl debug pods by the label app.kubernetes.io/managed-by: kubectl-debug, which is added by the kubectl client. Because this label might vary across different Kubernetes client implementations, such as how oc debug in OpenShift uses debug.openshift.io/managed-by: oc-debug, you might need to configure additional webhookOptions to ensure the webhook catches all relevant debug pods.

For example, to add oc debug pods, use the following yaml:

# ... (rest of your spod configuration)
spec:
  webhookOptions:
    - name: nodedebuggingpodmetada.spo.io
      objectSelector:
        matchLabels: # Use matchLabels for exact matching
          debug.openshift.io/managed-by: "oc-debug"
# ... (other webhook rule details such as rules, clientConfig, etc.)

Disabling Advanced Audit Logging

You can disable advanced audit logging and revert all configurations by deleting the test pod, the seccompProfile, the JSON Log Enricher and resetting all spod pod options.

Procedure
  1. Delete the test pod with the following command:

    oc delete pod my-pod
  2. Delete the seccompProfile using this command:

    oc delete seccompprofile profile1 -n openshift-security-profiles
  3. Disable the JSON Log Enricher and reset all options:

    oc patch spod spod -n openshift-security-profiles --type merge -p '{ "spec": { "enableJsonEnricher": false, "jsonEnricherOptions": { "auditLogPath": "", "auditLogMaxSize": 0, "auditLogMaxBackups": 0, "auditLogMaxAge": 0, "auditLogIntervalSeconds": 0 } }}'
  4. Wait for spod pods to restart. Run the following command to check:

    oc get pods -n openshift-security-profiles -l name=spod -w

    Wait until all spod pods show Running.

  5. Revert the ConfigMap volume patch with the following command:

    oc patch configmap security-profiles-operator-profile -n openshift-security-profiles --type merge -p '{"data":{"patch-volume-source.json":""}}'
  6. Verify that the configuration has been successfully updated:

    oc get spod spod -n openshift-security-profiles -o jsonpath='{.spec.enableJsonEnricher}'

    Expected output:

    false