Azure Policy for Kubernetes now supports Gatekeeper’s integration with native Kubernetes Validating Admission Policy (VAP) using Common Expression Language (CEL)! This integration leverages the new VAP feature introduced in Kubernetes 1.30, providing a more efficient, reliable and in-process way to enforce policies.
This integration brings lower latency for admission decisions, simpler constraint template authoring—for the first time – allows you to enable stronger fail-close behavior to prevent non-compliant components getting created or updated in your environment . And you keep all the Azure Policy benefits you already rely on like centralized assignment, scope management, safe rollout control, and governance at scale.
Previously, Azure Policy for Kubernetes only supported on OPA Rego-based evaluation through an admission webhook flow:
- A request is sent to the Kubernetes API server.
- The request is forwarded to Gatekeeper.
- Gatekeeper enforces resources using constraint template written in Rego.
- The result is returned to the API server.
Native Kubernetes Validation with Common Expression Language (CEL)
Policy expressions can be written in CEL syntax, a lightweight and expressive language that Kubernetes designed specifically for this validation context. Here's what changes:
- In-tree evaluation: Policy rules run inside the Kubernetes API server itself, not in an external webhook service. This means:
- Lower latency: No round-trip delay to an external service. Admission decisions are made faster because evaluation happens in-process.
- Better reliability: Validation doesn't depend on a separate service remaining healthy. If the VAP controller finds a violating resource, the PUT request will be denied, resulting in a fail-close scenario.
Getting Azure Policy Benefits with CEL
Kubernetes-native enforcement does not replace Azure Policy governance capabilities. It strengthens them. Azure Policy becomes the governance and deployment layer, while CEL becomes the validation logic. Here's what that means:
- CEL handles the validation: You write lightweight, readable expressions that run natively in Kubernetes. CEL is simpler than Rego and aligns with Kubernetes' own validation framework.
- Azure Policy handles the governance: Assignments, versioning, compliance tracking, safe rollouts, overrides, and multi-cluster management all happen through Azure Policy. You get enterprise governance without extra operational overhead.
Your First CEL Policy with Azure Policy
Here's the key insight: you don't write Azure Policy definitions in CEL. Instead, you write a CEL constraint template, package it inside an Azure Policy definition, and deploy it through Azure Policy.
Think of it as two layers:
- Layer 1: CEL Constraint Template — The Kubernetes validation logic you write
- Layer 2: Azure Policy Definition — The wrapper that adds assignments, versioning, compliance tracking, and safe deployment
Real Example: Limit Deployment Replicas
Let's walk through a concrete scenario. Your platform team wants to prevent developers from creating Deployments with more than 5 replicas—a common guard rail for dev/test environments to control resource consumption.
- replicas: 1 through replicas: 5 — allowed
- replicas: 6 or higher — denied
Step 1: Write the CEL constraint template
You write a Gatekeeper ConstraintTemplate using the K8sNativeValidation engine. The CEL expression itself is a single, readable line:
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8se2etestcelmaxdeployreplicas
spec:
crd:
spec:
names:
kind: K8sE2ETestCelMaxDeployReplicas
validation:
# Schema for the `parameters` field
openAPIV3Schema:
type: object
properties:
message:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
code:
- engine: K8sNativeValidation
source:
validations:
- expression: "object.spec.replicas <= 5"
message: "message example"
The key part is the engine: K8sNativeValidation block. This tells Gatekeeper to generate a Kubernetes ValidatingAdmissionPolicy resource from this template, so evaluation runs inside the API server rather than through the Gatekeeper webhook. The CEL expression object.spec.replicas <= 5 is evaluated natively at admission time.
Step 2: Package the CEL template into an Azure Policy definition
You then will need to base64-encode the constraint template (you can use an online tool or a local tool to do this) and embed the encoded content in an Azure Policy custom definition using sourceType: Base64Encoded. The full custom policy definition structure, matching the real format Azure Policy expects:
{
"policyType": "Custom",
"mode": "Microsoft.Kubernetes.Data",
"displayName": "Ensure deployment replicas are less than or equal to 5 in Kubernetes cluster",
"policyRule": {
"if": {
"field": "type",
"in": [
"Microsoft.ContainerService/managedClusters"
]
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"templateInfo": {
"sourceType": "Base64Encoded",
"content": "<BASE64_ENCODED_CONSTRAINT_TEMPLATE>"
},
"apiGroups": [
"apps"
],
"kinds": [
"Deployment"
],
"namespaces": "[parameters('namespaces')]",
"excludedNamespaces": "[parameters('excludedNamespaces')]",
"labelSelector": "[parameters('labelSelector')]",
"values": {
"message": "[parameters('message')]"
}
}
}
},
"parameters": {
"effect": {
"type": "String",
"allowedValues": [
"audit",
"deny",
"disabled"
],
"defaultValue": "audit"
},
"namespaces": {
"type": "Array",
"defaultValue": []
},
"labelSelector": {
"type": "Object",
"defaultValue": {}
},
"message": {
"type": "String"
}
}
}
A few things worth noting in this structure:
- sourceType: Base64Encoded - Azure Policy stores your constraint template as base64 content inline in the policy definition. When Azure Policy deploys to your cluster, it decodes and installs the template automatically.
- apiGroups: ["apps"] and kinds: ["Deployment"] - These scope the policy to only evaluate Kubernetes Deployment resources in the apps API group. Pods, Services, and other resources are unaffected.
- excludedNamespaces - System namespaces like kube-system and gatekeeper-system are excluded by default, so the policy doesn't interfere with cluster infrastructure.
- effect: audit (default) - The policy starts in audit mode, flagging violations without blocking them. Switch to deny when you're ready to enforce.
Right now only audit, deny, and disabled Policy effects are supported.
You can create the policy definition via the Azure portal, Azure CLI, or the Azure Policy VS Code extension.
Step 3: Assign the policy to your AKS clusters
Now you can assign this policy through Azure Policy to your clusters:
- In the Azure portal, go to Azure Policy > Definitions.
- Find your policy by name (e.g., "Ensure deployment replicas are less than or equal to 5").
- Click Assign.
- Set the Scope to the management group, subscription, or resource group containing your AKS clusters.
- Set the effect parameter to audit to start, then graduate to deny once you've validated the policy behavior.
- Click Create.
Azure Policy deploys the CEL-based constraint template to all clusters in scope. Within a few minutes, the Azure Policy add-on decodes the template, installs it on each cluster, and Gatekeeper generates the corresponding ValidatingAdmissionPolicy resource. From that point on, the Kubernetes API server evaluates every new Deployment admission request against your CEL rule directly. You can target different clusters or namespaces with different assignments and apply overrides for exceptions.
Step 4: Monitor compliance through Azure Policy
In the Azure Policy console, you see real-time compliance across all your clusters:
- Non-compliant Deployments (those with replicas > 5) appear in the Compliance view.
- You can drill down by policy, cluster, or namespace to see which Deployments are violating the limit.
- While in audit mode, existing violations are surfaced without blocking anything—giving you a clear picture before switching to deny.
Availability and prerequisites
- Supported Kubernetes version: AKS clusters running Kubernetes v1.30 or later (VAP became generally available in K8s v1.30).
- Gatekeeper version: Azure Policy add-on includes Gatekeeper v3.17.0 or later, which supports VAP and CEL policy generation.
- Azure Policy Add-on: The Azure Policy add-on for Kubernetes must be installed on your clusters. See Azure Policy for Kubernetes documentationfor installation instructions.
This is currently generally available and can be used to enforce policies in your Kubernetes clusters today.
Roadmap
We are actively working to include more built in Azure Policies for Azure Kubernetes service with the constraint template built with CEL.
Resources
- Azure Policy for Kubernetes: Full documentation on how Azure Policy integrates with Kubernetes, including built-in definitions and assignment workflows.
- Common Expression Language in Kubernetes: Reference guide for authoring CEL expressions used in Validating Admission Policies.
Conclusion
Azure Policy for Kubernetes now lets you bring Kubernetes-native CEL validation into your enterprise governance workflow.
The mental model is simple: CEL handles what to validate, Azure Policy handles how to govern it. You write clean, readable CEL expressions that run natively in your Kubernetes API server. Azure Policy wraps those expressions and handles the hard parts of enterprise governance—assignments across management hierarchies, versioning, compliance tracking, safe rollouts, and overrides.
Whether you're enforcing container registries, requiring security contexts, or validating resource configurations, you now have a path to do it natively in Kubernetes with enterprise governance backing it up.