Skip to main content

Security Profiles Operator

Required knowledge for the CKS certification.

What is the Security Profiles Operator?

The Security Profiles Operator (SPO) is a Kubernetes-native tool developed by the Kubernetes Security Special Interest Group (SIG Security) that manages seccomp, AppArmor, and SELinux profiles at scale. It provides a unified approach to defining, recording, and applying security profiles across Kubernetes clusters.

Issue: Managing security profiles manually across multiple nodes is error-prone, time-consuming, and difficult to maintain as workloads scale.
Fix: The Security Profiles Operator automates profile distribution, recording, and lifecycle management using Kubernetes Custom Resources.

By using the Security Profiles Operator, you can enforce security policies consistently, reduce manual configuration errors, and record profiles from running workloads for baseline policy creation.


1. Install the Security Profiles Operator

Issue: Deploying security profiles manually requires creating files on each node and managing synchronization.
Fix: Install the Security Profiles Operator to centrally manage profiles as Kubernetes resources.

Install via Manifest

# Install cert-manager (required for webhook certificates)
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.2/cert-manager.yaml
kubectl --namespace cert-manager wait --for condition=ready pod -l app.kubernetes.io/instance=cert-manager

# Install the Security Profiles Operator
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/security-profiles-operator/main/deploy/operator.yaml

# Verify installation
kubectl -n security-profiles-operator get pods

Install via Helm

# Create namespace
kubectl create ns security-profiles-operator

# Label namespace for pod security
kubectl label ns security-profiles-operator \
pod-security.kubernetes.io/enforce=privileged \
--overwrite=true

# Download and install the Helm chart
wget https://github.com/kubernetes-sigs/security-profiles-operator/releases/download/v0.10.0/security-profiles-operator-0.10.0.tgz
helm install security-profiles-operator \
--namespace security-profiles-operator \
./security-profiles-operator-0.10.0.tgz

Enable Log Enricher for Profile Recording

The log enricher enables recording profiles by analyzing audit logs.

kubectl -n security-profiles-operator patch spod spod --type=merge \
-p '{"spec":{"enableLogEnricher":true}}'

Enable eBPF Recorder for Advanced Recording

The eBPF recorder provides more efficient profile recording without requiring audit logs.

kubectl -n security-profiles-operator patch spod spod --type=merge \
-p '{"spec":{"enableBpfRecorder":true}}'

2. Create and Apply Seccomp Profiles

Issue: Creating seccomp profiles requires understanding JSON syntax and manually distributing files to nodes.
Fix: Define seccomp profiles as Kubernetes Custom Resources that are automatically synchronized across nodes.

Example: Create a Seccomp Profile

apiVersion: security-profiles-operator.x-k8s.io/v1beta1
kind: SeccompProfile
metadata:
name: restricted-workload
namespace: production
spec:
defaultAction: SCMP_ACT_ERRNO
architectures:
- SCMP_ARCH_X86_64
syscalls:
- action: SCMP_ACT_ALLOW
names:
- read
- write
- exit
- exit_group
- fstat
- openat
- close
- mmap
- mprotect
- brk

Apply the profile:

kubectl apply -f restricted-workload-seccomp.yaml

# Verify profile status
kubectl get seccompprofile -n production

Apply the Profile to a Pod

apiVersion: v1
kind: Pod
metadata:
name: secure-app
namespace: production
spec:
securityContext:
seccompProfile:
type: Localhost
localhostProfile: operator/production/restricted-workload.json
containers:
- name: app
image: nginx:1.21

The operator automatically creates the profile at /var/lib/kubelet/seccomp/operator/production/restricted-workload.json on all nodes.


3. Record Seccomp Profiles from Running Workloads

Issue: Determining the exact syscalls required by an application is difficult without runtime analysis.
Fix: Use ProfileRecording to automatically capture syscalls from running containers.

Enable Recording for a Namespace

kubectl label ns production spo.x-k8s.io/enable-recording=

Create a ProfileRecording

apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
kind: ProfileRecording
metadata:
name: record-nginx
namespace: production
spec:
kind: SeccompProfile
recorder: logs
podSelector:
matchLabels:
app: nginx

Deploy the Workload to Record

apiVersion: v1
kind: Pod
metadata:
name: nginx-test
namespace: production
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21

Capture and Review the Profile

After running typical workload operations, delete the pod to finalize recording:

# Allow workload to run and exercise all code paths
kubectl exec -n production nginx-test -- curl http://localhost

# Delete pod to trigger profile creation
kubectl delete pod -n production nginx-test

# View recorded profile
kubectl get seccompprofile -n production
kubectl get seccompprofile record-nginx-nginx -n production -o yaml

The operator creates a profile named record-nginx-nginx containing all syscalls used during execution.


4. Manage AppArmor Profiles

Issue: AppArmor profiles require manual installation on each node and lack version control.
Fix: Define AppArmor profiles as Kubernetes resources managed by the operator.

Enable AppArmor Support

kubectl -n security-profiles-operator patch spod spod --type=merge \
-p '{"spec":{"enableAppArmor":true}}'

Create an AppArmor Profile

apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
kind: ApparmorProfile
metadata:
name: nginx-apparmor
namespace: production
spec:
profile: |
profile nginx-apparmor flags=(attach_disconnected,mediate_deleted) {
capability net_bind_service,
capability setgid,
capability setuid,

network inet tcp,
network inet udp,

/usr/sbin/nginx mr,
/var/log/nginx/** w,
/var/cache/nginx/** rw,
/etc/nginx/** r,

deny /bin/bash rx,
deny /usr/bin/curl rx,
deny /usr/bin/wget rx,
}

Apply the Profile to a Pod

apiVersion: v1
kind: Pod
metadata:
name: nginx-apparmor-pod
namespace: production
spec:
containers:
- name: nginx
image: nginx:1.21
securityContext:
appArmorProfile:
type: Localhost
localhostProfile: nginx-apparmor

5. Manage SELinux Profiles

Issue: SELinux policies are complex to write and difficult to test without production workloads.
Fix: Use the operator to define, record, and apply SELinux profiles declaratively.

Enable SELinux Support

kubectl -n security-profiles-operator patch spod spod --type=merge \
-p '{"spec":{"enableSelinux":true}}'

Create a SELinux Profile

apiVersion: security-profiles-operator.x-k8s.io/v1alpha2
kind: SelinuxProfile
metadata:
name: nginx-selinux
namespace: production
spec:
allow:
"@self":
tcp_socket:
- listen
- accept
- bind
http_port_t:
tcp_socket:
- name_bind
http_cache_port_t:
tcp_socket:
- name_bind
node_t:
tcp_socket:
- node_bind
inherit:
- kind: System
name: container

Wait for Profile Installation

kubectl wait --for=condition=ready selinuxprofile nginx-selinux -n production

Apply the Profile to a Pod

apiVersion: v1
kind: Pod
metadata:
name: nginx-selinux-pod
namespace: production
spec:
containers:
- name: nginx
image: nginxinc/nginx-unprivileged:1.21
securityContext:
seLinuxOptions:
type: nginx-selinux.process

The SELinux type follows the format <ProfileName>.process.


6. Use Base Profiles for Container Runtimes

Issue: Container runtimes require specific syscalls to function, but manually determining them is time-consuming.
Fix: Reference base profiles for common runtimes to ensure compatibility.

Example: Extend the runc Base Profile

apiVersion: security-profiles-operator.x-k8s.io/v1beta1
kind: SeccompProfile
metadata:
name: app-with-network
namespace: production
spec:
defaultAction: SCMP_ACT_ERRNO
baseProfileName: runc-v1.4.0
syscalls:
- action: SCMP_ACT_ALLOW
names:
- socket
- connect
- sendto
- recvfrom

This profile inherits all syscalls from runc-v1.4.0 and adds networking syscalls.

Use OCI Artifacts for Base Profiles

apiVersion: security-profiles-operator.x-k8s.io/v1beta1
kind: SeccompProfile
metadata:
name: app-with-oci-base
namespace: production
spec:
defaultAction: SCMP_ACT_ERRNO
baseProfileName: oci://ghcr.io/security-profiles/runc:v1.4.0
syscalls:
- action: SCMP_ACT_ALLOW
names:
- socket

The operator automatically pulls and verifies signed base profiles from OCI registries.


7. Bind Profiles to Workloads Automatically

Issue: Modifying existing workload manifests to add security profiles is disruptive.
Fix: Use ProfileBinding to automatically apply profiles based on image matching.

Enable Profile Binding

kubectl label ns production spo.x-k8s.io/enable-binding=

Create a ProfileBinding

apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
kind: ProfileBinding
metadata:
name: nginx-binding
namespace: production
spec:
profileRef:
kind: SeccompProfile
name: restricted-workload
image: nginx:1.21

All pods in the production namespace using the nginx:1.21 image will automatically have the restricted-workload seccomp profile applied.


8. Monitor Profile Usage with Metrics

Issue: Without visibility into profile enforcement, detecting policy violations and tuning profiles is difficult.
Fix: Use the operator's Prometheus metrics to monitor profile operations.

Available Metrics

The operator exposes metrics at https://metrics.security-profiles-operator/metrics-spod:

  • security_profiles_operator_seccomp_profile_total - Total seccomp profile operations
  • security_profiles_operator_seccomp_profile_audit_total - Seccomp audit events
  • security_profiles_operator_seccomp_profile_error_total - Seccomp profile errors
  • security_profiles_operator_selinux_profile_total - Total SELinux profile operations
  • security_profiles_operator_selinux_profile_audit_total - SELinux audit events

Query Metrics

# Create a pod to query metrics
kubectl run metrics-client --rm -i --restart=Never \
--image=registry.fedoraproject.org/fedora-minimal:latest \
-n security-profiles-operator -- bash -c \
'curl -ks -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
https://metrics.security-profiles-operator/metrics-spod | grep security_profiles_operator'

9. Security Best Practices

Use Restrictive Default Actions

Always set defaultAction: SCMP_ACT_ERRNO for seccomp profiles to deny all syscalls by default:

spec:
defaultAction: SCMP_ACT_ERRNO
syscalls:
- action: SCMP_ACT_ALLOW
names:
- read
- write

Enable Profile Recording in Non-Production First

Record profiles in development or staging environments before applying them to production:

# Label development namespace for recording
kubectl label ns dev spo.x-k8s.io/enable-recording=

# Deploy ProfileRecording in dev
kubectl apply -f profile-recording.yaml -n dev

Restrict Allowed Syscalls

Configure the operator to reject profiles containing dangerous syscalls:

kubectl -n security-profiles-operator patch spod spod --type merge \
-p '{"spec":{"allowedSyscalls": ["read", "write", "exit", "exit_group", "fstat", "openat", "close"]}}'

Use RBAC to Control Profile Management

Create roles that limit who can create or modify security profiles:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: seccomp-profile-editor
namespace: production
rules:
- apiGroups: ["security-profiles-operator.x-k8s.io"]
resources: ["seccompprofiles"]
verbs: ["get", "list", "watch", "create", "update", "patch"]

Enable Memory Optimization for Large Clusters

In clusters with thousands of pods, enable memory optimization:

kubectl -n security-profiles-operator patch spod spod --type=merge \
-p '{"spec":{"enableMemoryOptimization":true}}'

When enabled, only pods labeled with spo.x-k8s.io/enable-recording=true are tracked.


Security Checklist

  • Install the Security Profiles Operator using signed releases
  • Enable log enricher or eBPF recorder for profile recording
  • Record profiles from running workloads in non-production environments
  • Use restrictive default actions in seccomp profiles
  • Apply profiles to pods via ProfileBinding for automation
  • Monitor profile metrics for audit events and errors
  • Restrict allowed syscalls at the operator level for high-security clusters
  • Use RBAC to control who can create and modify security profiles
  • Test profiles thoroughly before applying to production workloads
  • Use base profiles from trusted OCI registries