Managing seccomp profiles

Create and manage seccomp profiles and bind them to workloads.

The Security Profiles Operator supports only Red Hat Enterprise Linux CoreOS (RHCOS) worker nodes. Red Hat Enterprise Linux (RHEL) nodes are not supported.

Creating seccomp profiles

Use the SeccompProfile object to create profiles.

SeccompProfile objects can restrict syscalls within a container, limiting the access of your application.

Procedure

  1. Create a project by running the following command:

    1. $ oc new-project my-namespace
  2. Create the SeccompProfile object:

    1. apiVersion: security-profiles-operator.x-k8s.io/v1beta1
    2. kind: SeccompProfile
    3. metadata:
    4. namespace: my-namespace
    5. name: profile1
    6. spec:
    7. defaultAction: SCMP_ACT_LOG

The seccomp profile will be saved in /var/lib/kubelet/seccomp/operator/<namespace>/<name>.json.

An init container creates the root directory of the Security Profiles Operator to run the Operator without root group or user ID privileges. A symbolic link is created from the rootless profile storage /var/lib/openshift-security-profiles to the default seccomp root path inside of the kubelet root /var/lib/kubelet/seccomp/operator.

Applying seccomp profiles to a pod

Create a pod to apply one of the created profiles.

Procedure

  1. Create a pod object that defines a securityContext:

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: test-pod
    5. spec:
    6. securityContext:
    7. seccompProfile:
    8. type: Localhost
    9. localhostProfile: operator/my-namespace/profile1.json
    10. containers:
    11. - name: test-container
    12. image: quay.io/security-profiles-operator/test-nginx-unprivileged:1.21
  2. View the profile path of the seccompProfile.localhostProfile attribute by running the following command:

    1. $ oc -n my-namespace get seccompprofile profile1 --output wide

    Example output

    1. NAME STATUS AGE SECCOMPPROFILE.LOCALHOSTPROFILE
    2. profile1 Installed 14s operator/my-namespace/profile1.json
  3. View the path to the localhost profile by running the following command:

    1. $ oc get sp profile1 --output=jsonpath='{.status.localhostProfile}'

    Example output

    1. operator/my-namespace/profile1.json
  4. Apply the localhostProfile output to the patch file:

    1. spec:
    2. template:
    3. spec:
    4. securityContext:
    5. seccompProfile:
    6. type: Localhost
    7. localhostProfile: operator/my-namespace/profile1.json
  5. Apply the profile to any other workload, such as a Deployment object, by running the following command:

    1. $ oc -n my-namespace patch deployment myapp --patch-file patch.yaml --type=merge

    Example output

    1. deployment.apps/myapp patched

Verification

  • Confirm the profile was applied correctly by running the following command:

    1. $ oc -n my-namespace get deployment myapp --output=jsonpath='{.spec.template.spec.securityContext}' | jq .

    Example output

    1. {
    2. "seccompProfile": {
    3. "localhostProfile": "operator/my-namespace/profile1.json",
    4. "type": "localhost"
    5. }
    6. }

Binding workloads to profiles with ProfileBindings

You can use the ProfileBinding resource to bind a security profile to the SecurityContext of a container.

Procedure

  1. To bind a pod that uses a quay.io/security-profiles-operator/test-nginx-unprivileged:1.21 image to the example SeccompProfile profile, create a ProfileBinding object in the same namespace with the pod and the SeccompProfile objects:

    1. apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
    2. kind: ProfileBinding
    3. metadata:
    4. namespace: my-namespace
    5. name: nginx-binding
    6. spec:
    7. profileRef:
    8. kind: SeccompProfile (1)
    9. name: profile (2)
    10. image: quay.io/security-profiles-operator/test-nginx-unprivileged:1.21
    1The kind: variable refers to the name of the profile.
    2The name: variable refers to the name of the profile.
  2. Label the namespace with enable-binding=true by running the following command:

    1. $ oc label ns my-namespace spo.x-k8s.io/enable-binding=true
  3. Define a pod named test-pod.yaml:

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: test-pod
    5. spec:
    6. containers:
    7. - name: test-container
    8. image: quay.io/security-profiles-operator/test-nginx-unprivileged:1.21
  4. Create the pod:

    1. $ oc create -f test-pod.yaml

    If the pod already exists, you must re-create the pod for the binding to work properly.

Verification

  • Confirm the pod inherits the ProfileBinding by running the following command:

    1. $ oc get pod test-pod -o jsonpath='{.spec.containers[*].securityContext.seccompProfile}'

    Example output

    1. {"localhostProfile":"operator/my-namespace/profile.json","type":"Localhost"}

Recording profiles from workloads

The Security Profiles Operator can record system calls with ProfileRecording objects, making it easier to create baseline profiles for applications.

When using the log enricher for recording seccomp profiles, verify the log enricher feature is enabled. See Additional resources for more information.

A container with privileged: true security context restraints prevents log-based recording. Privileged containers are not subject to seccomp policies, and log-based recording makes use of a special seccomp profile to record events.

Procedure

  1. Create a project by running the following command:

    1. $ oc new-project my-namespace
  2. Label the namespace with enable-recording=true by running the following command:

    1. $ oc label ns my-namespace spo.x-k8s.io/enable-recording=true
  3. Create a ProfileRecording object containing a recorder: logs variable:

    1. apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
    2. kind: ProfileRecording
    3. metadata:
    4. namespace: my-namespace
    5. name: test-recording
    6. spec:
    7. kind: SeccompProfile
    8. recorder: logs
    9. podSelector:
    10. matchLabels:
    11. app: my-app
  4. Create a workload to record:

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. namespace: my-namespace
    5. name: my-pod
    6. labels:
    7. app: my-app
    8. spec:
    9. containers:
    10. - name: nginx
    11. image: quay.io/security-profiles-operator/test-nginx-unprivileged:1.21
    12. ports:
    13. - containerPort: 8080
    14. - name: redis
    15. image: quay.io/security-profiles-operator/redis:6.2.1
  5. Confirm the pod is in a Running state by entering the following command:

    1. $ oc -n my-namespace get pods

    Example output

    1. NAME READY STATUS RESTARTS AGE
    2. my-pod 2/2 Running 0 18s
  6. Confirm the enricher indicates that it receives audit logs for those containers:

    1. $ oc -n openshift-security-profiles logs --since=1m --selector name=spod -c log-enricher

    Example output

    1. I0523 14:19:08.747313 430694 enricher.go:445] log-enricher "msg"="audit" "container"="redis" "executable"="/usr/local/bin/redis-server" "namespace"="my-namespace" "node"="xiyuan-23-5g2q9-worker-eastus2-6rpgf" "pid"=656802 "pod"="my-pod" "syscallID"=0 "syscallName"="read" "timestamp"="1684851548.745:207179" "type"="seccomp"

Verification

  1. Remove the pod:

    1. $ oc -n my-namepace delete pod my-pod
  2. Confirm the Security Profiles Operator reconciles the two seccomp profiles:

    1. $ oc get seccompprofiles -lspo.x-k8s.io/recording-id=test-recording -n my-namespace

    Example output for seccompprofile

    1. NAME STATUS AGE
    2. test-recording-nginx Installed 2m48s
    3. test-recording-redis Installed 2m48s

Merging per-container profile instances

By default, each container instance records into a separate profile. The Security Profiles Operator can merge the per-container profiles into a single profile. Merging profiles is useful when deploying applications using ReplicaSet or Deployment objects.

Procedure

  1. Edit a ProfileRecording object to include a mergeStrategy: containers variable:

    1. apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
    2. kind: ProfileRecording
    3. metadata:
    4. # The name of the Recording is the same as the resulting SeccompProfile CRD
    5. # after reconciliation.
    6. name: test-recording
    7. namespace: my-namespace
    8. spec:
    9. kind: SeccompProfile
    10. recorder: logs
    11. mergeStrategy: containers
    12. podSelector:
    13. matchLabels:
    14. app: sp-record
  2. Label the namespace by running the following command:

    1. $ oc label ns my-namespace security.openshift.io/scc.podSecurityLabelSync=false pod-security.kubernetes.io/enforce=privileged pod-security.kubernetes.io/audit=privileged pod-security.kubernetes.io/warn=privileged --overwrite=true
  3. Create the workload with the following YAML:

    1. apiVersion: apps/v1
    2. kind: Deployment
    3. metadata:
    4. name: nginx-deploy
    5. namespace: my-namespace
    6. spec:
    7. replicas: 3
    8. selector:
    9. matchLabels:
    10. app: sp-record
    11. template:
    12. metadata:
    13. labels:
    14. app: sp-record
    15. spec:
    16. serviceAccountName: spo-record-sa
    17. containers:
    18. - name: nginx-record
    19. image: quay.io/security-profiles-operator/test-nginx-unprivileged:1.21
    20. ports:
    21. - containerPort: 8080
  4. To record the individual profiles, delete the deployment by running the following command:

    1. $ oc delete deployment nginx-deploy -n my-namespace
  5. To merge the profiles, delete the profile recording by running the following command:

    1. $ oc delete profilerecording test-recording -n my-namespace
  6. To start the merge operation and generate the results profile, run the following command:

    1. $ oc get seccompprofiles -lspo.x-k8s.io/recording-id=test-recording -n my-namespace

    Example output for seccompprofiles

    1. NAME STATUS AGE
    2. test-recording-nginx-record Installed 55s
  7. To view the permissions used by any of the containers, run the following command:

    1. $ oc get seccompprofiles test-recording-nginx-record -o yaml

Additional resources