How to Implement Immutable Admission Policies in Kubernetes v1.36 Using Manifest Files

By ● min read

Introduction

Securing a Kubernetes cluster often means enforcing admission policies that prevent misconfigurations or malicious actions. But traditional admission policies have a fundamental flaw: they are API objects, meaning they can be deleted by anyone with sufficient permissions, and they don't exist until created—leaving a window of vulnerability during cluster bootstrap. Kubernetes v1.36 addresses this with an alpha feature called manifest-based admission control. This guide will walk you through the process of defining admission policies as files on disk that the API server loads before serving any requests—policies that literally cannot be deleted or bypassed.

How to Implement Immutable Admission Policies in Kubernetes v1.36 Using Manifest Files

What You Need

Step-by-Step Guide

Step 1: Prepare the Admission Configuration File

The API server already uses an AdmissionConfiguration file to configure plugins. If you don't have one, create it. This file will be referenced later by the --admission-control-config-file flag.

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/"

Save this as admission-config.yaml. The staticManifestsDir field points to a directory where you'll drop your policy files.

Step 2: Create the Policy Manifest Directory

On each API server node, create the directory specified in the configuration. Ensure the API server process (usually running under a user like kube-apiserver) has read permissions.

sudo mkdir -p /etc/kubernetes/admission/validating-policies/

Make sure the directory is secure—only root or the API server user should be able to write to it.

Step 3: Write Your Policy Manifest Files

Create YAML files with standard Kubernetes resource definitions—any admission policy type supported by the plugin (e.g., ValidatingAdmissionPolicy, ValidatingAdmissionPolicyBinding, or custom webhook configurations). The only requirement: each resource's name must end with .static.k8s.io. This suffix prevents name collisions with API-object-based policies and helps identify static policies in metrics and audit logs.

Example: deny-privileged.static.k8s.io

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: "!has(object.spec.containers) || object.spec.containers.all(c, !has(c.securityContext) || !has(c.securityContext.privileged) || c.securityContext.privileged != true)"
    message: "Privileged containers are not allowed"

Save this as deny-privileged.yaml in the directory created earlier.

Step 4: Configure the API Server to Load Static Manifests

Ensure your API server is started with the --admission-control-config-file flag pointing to the configuration file from Step 1. If you're using kubeadm or a managed control plane, adjust accordingly. For self-managed clusters, modify the API server manifest (e.g., /etc/kubernetes/manifests/kube-apiserver.yaml for static pods) to include:

--admission-control-config-file=/etc/kubernetes/admission-config.yaml

Restart the API server to pick up the changes. The API server will load all YAML files from the staticManifestsDir before it starts serving requests.

Step 5: Verify the Policies Are Active

Check that the policy is listed as a static resource. You can't delete it via the API, but you can see it in the list of policies using kubectl get validatingadmissionpolicy. The name will include the .static.k8s.io suffix.

kubectl get validatingadmissionpolicy
NAME                                  AGE
deny-privileged.static.k8s.io         5m

Test the policy by attempting to create a privileged pod:

kubectl run test --image=nginx --privileged
Error from server: admission webhook "deny-privileged.static.k8s.io" denied the request: Privileged containers are not allowed

Step 6: Confirm the Policy Cannot Be Deleted

Try to delete the static policy via kubectl:

kubectl delete validatingadmissionpolicy deny-privileged.static.k8s.io
Error from server (Forbidden): ...

The API server will reject the deletion because the resource is loaded from disk and is considered immutable. Even a cluster admin cannot remove it through the API. To remove or modify a static policy, you must edit the file on disk and restart the API server.

Tips

With manifest-based admission control, you can close the bootstrap gap and prevent privileged users from removing critical policies. This feature marks a significant step toward truly immutable cluster security.

Tags:

Recommended

Discover More

Kubernetes SELinux Volume Changes Go GA: Prepare for v1.37 Default10 Ways Google Health Transforms Fitbit for the Better (and What It Means for You)The Future of Bespoke Medicines: 10 Key Insights from Julia Vitarello's Journey with Mila and a New Biotech VentureElevating Utility Software: A Guide to Designing Maintenance Tools Users Actually EnjoyNvidia's Jensen Huang to Join Trump on China Trip After President Flags Missing CEO in Media Reports