Linux provides powerful kernel-level security mechanisms, seccomp, SELinux, and AppArmor, that restrict what containerized workloads can do. Each uses profiles that define permitted behavior, but writing, distributing, and maintaining those profiles by hand is tedious and error-prone. The Security Profiles Operator (SPO) solves this by letting you manage security profiles as Kubernetes custom resources, record profiles from live workloads, and bind them to pods declaratively.

With v1.0.0, the Security Profiles Operator graduates all eight of its Custom Resource Definition (CRD) APIs to v1. This is the project’s first stable release, backed by a third-party security audit, a full cycle of hardening work, and a zero-downtime migration path from every previous API version.

Six years of API evolution

SPO started in April 2020 as a seccomp-only operator. Over the following years, the project grew to cover SELinux (late 2020), AppArmor (late 2021), profile recording via audit logs and eBPF, OCI-based profile distribution, and more. Each feature introduced new CRDs, and those CRDs stayed at alpha or beta while the APIs matured through real-world use.

Some of these APIs have been stable in practice for years: SeccompProfile shipped at v1beta1 for over four years, SPOD at v1alpha1 for over five. Downstream consumers needed a stable version label to commit to long-term support. The SPO has been available on OperatorHub since 2022 and has shipped as part of Red Hat OpenShift since version 4.12. The window before v1 was the last chance to make breaking changes, and the team used it.

The cleanup involved many pull requests:

The one deliberate exception: seccomp’s SCMP_ACT_* and SCMP_CMP_* constants keep their uppercase names to match the OCI runtime spec and Linux kernel headers verbatim.

Security audit and hardening

Before graduating to v1, SPO underwent a security code audit. The audit found zero critical vulnerabilities. It confirmed that file paths written to the host are derived from object metadata (not from user-controlled spec fields), that commands are constructed as argument arrays (no shell injection surface), and that RBAC defaults do not grant unnecessary privileges to non-admin users.

The audit identified areas for hardening, especially around the boundary where a tenant’s custom resource gets translated into kernel-level LSM state. The v1.0.0 release addresses these findings:

RawSelinuxProfile: gating and validation. RawSelinuxProfile lets users write arbitrary SELinux CIL policy, which the operator installs on the node. The audit flagged this as the highest-risk path. In v1.0.0, a new enableRawSelinuxProfiles field on the SPOD configuration lets cluster admins disable raw SELinux profile support entirely. A validating admission webhook now rejects invalid raw policies instead of letting them fail at reconciliation.

SelinuxProfile: permissive mode control. The permissive boolean on SelinuxProfile was replaced with a mode enum (Enforcing or Permissive), removing the risk that an unset field could accidentally enable permissive mode.

AppArmor input sanitization. AppArmor profiles accept template inputs for profile names, executable paths, and capabilities. The audit noted that these inputs were loaded without content validation. SPO now applies strict regex validation on all of them and prevents overwriting profiles that are already loaded in the kernel.

Field size limits and validation markers. RawSelinuxProfile.spec.policy now carries a maxLength of 500 KB, limiting the input size before it reaches the SELinux CIL compiler on the node. Validation markers were added across all CRD types.

Additional hardening beyond the audit scope

Zero-downtime migration

Upgrading to v1.0.0 requires no manual migration steps. Conversion webhooks handle translation between old and new API versions transparently:

Here’s how a ProfileRecording looks before and after:

# Before (v1alpha1)
apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
kind: ProfileRecording
metadata:
  name: my-recording
spec:
  kind: SeccompProfile
  recorder: logs
  mergeStrategy: none
  podSelector:
    matchLabels:
      app: my-app


# After (v1)
apiVersion: security-profiles-operator.x-k8s.io/v1
kind: ProfileRecording
metadata:
  name: my-recording
spec:
  kind: SeccompProfile
  recorder: Logs
  mergeStrategy: None
  podSelector:
    matchLabels:
      app: my-app

For CRDs without enum changes, only the apiVersion line changes. A full migration guide covers Go API consumer updates, enum constant changes, and scheme registration. Old API versions will remain available for backward compatibility and will be removed in a future release.

From operator to upstream Kubernetes

SPO has always been closely connected to upstream security profile work in Kubernetes. The project builds on the seccomp GA API surface (Kubernetes 1.19) and grew alongside related proposals like ConfigMap-based seccomp profiles and built-in seccomp profiles with complain mode.

The latest example of this connection is KEP 6061: OCI Artifact-Based Security Profile Distribution, proposed for an upcoming Kubernetes release as alpha. SPO pioneered OCI-based profile distribution years ago, allowing users to push seccomp, SELinux, and AppArmor profiles to OCI registries and reference them directly from pod specs. KEP 6061 brings this concept into the kubelet natively, adding a PullSecurityProfileArtifact CRI API call so container runtimes can fetch profiles from OCI registries on demand.

The KEP follows the same trust model as localhost profiles: a deny-by-default allowlist at the kubelet, with Pod Security Admission treating OCI profiles like localhost. SPO will continue to provide the higher-level features that the kubelet does not cover: profile recording from live workloads, structured SELinux policy authoring, profile binding to container images, and audit log enrichment.

What’s next

Now that v1 has shipped, the project’s priorities are:

Try v1.0.0, read the migration guide, and join the conversation in #security-profiles-operator on Kubernetes Slack.

SPO is built by over 70 contributors across multiple organizations. Thanks to everyone who contributed code, filed issues, tested pre-releases, and participated in the security audit. v1 is yours as much as ours.