Kousa4 Stack
ArticlesCategories
Programming

Kubernetes v1.36 Introduces Immutable Admission Policies via Disk-Based Manifests

Published 2026-05-12 02:44:34 · Programming

Closing the Bootstrap Gap in Kubernetes Policy Enforcement

Managing security policies across multiple Kubernetes clusters often feels like a balancing act. Administrators rely on admission controllers to enforce rules—but those controllers themselves are API objects that don't exist until created and can be deleted by anyone with sufficient permissions. This creates a dangerous window during cluster bootstrap when policies are inactive, and leaves critical configurations vulnerable to removal. The Kubernetes v1.36 release addresses this with an alpha feature: manifest-based admission control.

Kubernetes v1.36 Introduces Immutable Admission Policies via Disk-Based Manifests

The Problem: Policies That Can Be Undone

Most Kubernetes policy enforcement operates through the API. You create a ValidatingAdmissionPolicy or a webhook configuration as an API object, and the admission controller picks it up. While this works well in steady state, it has two fundamental limitations:

  • Bootstrap vulnerability: When the API server starts, there's a gap between when it begins serving requests and when your policies are created and active. During cluster recovery from etcd failure or backup restore, this gap can be significant—leaving the cluster unprotected.
  • Self-protection issue: Admission webhooks cannot intercept operations on their own configuration resources (e.g., ValidatingWebhookConfiguration) to avoid circular dependencies. This means a privileged user can delete critical admission policies without any check from the admission chain.

As a member of Kubernetes SIG API Machinery put it, "We wanted a way to say 'these policies are always on, full stop.'"

How Manifest-Based Admission Control Works

The new feature allows you to define admission webhooks and Common Expression Language (CEL)-based policies as files on disk. The API server loads these files at startup—before it serves any requests. This ensures policies are active from the moment the cluster becomes available.

To use it, you add a staticManifestsDir field to your existing AdmissionConfiguration file—the same one passed to the API server via the --admission-control-config-file flag. Point it at a directory containing your policy YAML files, and the API server loads them automatically.

apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: ValidatingAdmissionPolicy
  configuration:
    apiVersion: apiserver.config.k8s.io/v1
    kind: ValidatingAdmissionPolicyConfiguration
    staticManifestsDir: "/etc/kubernetes/admission/validating-policies/"

The manifest files are standard Kubernetes resource definitions with one requirement: all objects defined in these manifests must have names ending in .static.k8s.io. This reserved suffix prevents collisions with API-based configurations and makes it easy to identify the source of an admission decision in metrics or audit logs.

Example: Denying Privileged Containers Outside kube-system

Here's a complete example that denies privileged containers except in the kube-system namespace:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: "deny-privileged.static.k8s.io"
  annotations:
    kubernetes.io/description: "Deny launching privileged pods, anywhere this policy is applied"
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups: [""]
      apiVersions: ["v1"]
      operations: ["CREATE", "UPDATE"]
      resources: ["pods"]
  validations:
  - expression: "object.spec.containers.all(c, !has(c.securityContext) || !has(c.securityContext.privileged) || !c.securityContext.privileged) && object.spec.initContainers.all(c, !has(c.securityContext) || !has(c.securityContext.privileged) || !c.securityContext.privileged) && object.spec.ephemeralContainers.all(c, !has(c.securityContext) || !has(c.securityContext.privileged) || !c.securityContext.privileged)"
    message: "Privileged containers are not allowed in this namespace"
  matchConditions:
  - name: "not-kube-system"
    expression: "namespaceObject.metadata.name != 'kube-system'"

This policy is loaded from disk before the API server starts, so it's active immediately—even if no one has yet created it through the API. And because it's defined as a manifest, it cannot be deleted by any user; it only exists as long as the file remains on disk.

Benefits and Considerations

This approach offers two key advantages:

  • Guaranteed availability: Policies are present from the very first API request, closing the bootstrap gap.
  • Protection from deletion: Since the policies are not API objects, they cannot be removed via API calls—even by cluster admins. This provides a new layer of defense for critical security rules.

However, there are considerations for adoption. As an alpha feature, it requires enabling the AdmissionWebhookMatchConditions or appropriate feature gate. Also, because these policies are file-based, updates require modifying the file on disk and restarting the API server—no live updates via kubectl apply. This trade-off may suit environments where policy changes are infrequent and require deliberate review.

For further details, refer to the official Kubernetes documentation on admission control.

Conclusion

Manifest-based admission control in Kubernetes v1.36 addresses a long-standing gap in policy enforcement. By loading critical policies from disk before the API server starts, administrators can ensure baseline security rules are always active and cannot be accidentally or maliciously deleted. This feature is especially valuable for organizations running multiple clusters or requiring strict compliance controls. As it matures beyond alpha, it promises to become an essential tool in the Kubernetes security toolbox.