Skip to main content
5 min read·811 words

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

References​

This article is based on information from the following official sources:

  1. Security Profiles Operator - Kubernetes SIG Security GitHub Repository
  2. Restrict a Container's Syscalls with seccomp - Kubernetes Documentation
  3. Restrict a Container's Access to Resources with AppArmor - Kubernetes Documentation
  4. Security Profiles Operator Installation Guide - Kubernetes SIG Security Documentation