🎯 Lesson Objective_
Understand ValidatingAdmissionPolicy GA K8s 1.30, write CEL policies without a webhook server, and know when you still need OPA/Gatekeeper.
1. Problems with Traditional Admission Webhooks
Webhook-based admission (OPA/Gatekeeper, Kyverno) has disadvantages:
- Network overhead: each API request needs to make an HTTP call to the webhook service
- Availability dependency: if webhook service down → API requests fail
- Operational burden: must maintain webhook deployment, TLS certs
- Latency: adds latency to all API calls
2. ValidatingAdmissionPolicy — Built-in, No Webhook
ValidatingAdmissionPolicy GA from K8s 1.30 allows writing validation policies directly in the API server, using CEL (Common Expression Language).
- Runs in API server process — zero network overhead
- No need to deploy additional service
- There is no single point of failure__HTMLTAG_105___
- Faster than webhooks ~10x
3. CEL Basics
CEL is a simple, safe expression language (no loops, no side effects).
# Truy cập object fields object.spec.replicas < 10Check field exists
has(object.spec.template.spec.containers)
Array operations
object.spec.template.spec.containers.all(c, has(c.resources) && has(c.resources.limits) )
String operations
!object.spec.template.spec.containers.exists(c, c.image.endsWith(":latest") )
Comparison với quantities
object.spec.template.spec.containers.all(c, c.resources.limits.memory <= resource.Quantity("2Gi") )
4. ValidatingAdmissionPolicy Structure
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: my-policy
spec:
failurePolicy: Fail # Fail hoặc Ignore nếu policy error
matchConstraints: # áp dụng cho objects nào
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments"]
validations: # danh sách expressions
- expression: "object.spec.replicas <= 10"
message: "Deployment không được có quá 10 replicas"
reason: Invalid
- expression: "has(object.metadata.labels) && has(object.metadata.labels.team)"
message: "Deployment phải có label 'team'"
5. ValidatingAdmissionPolicyBinding
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: my-policy-binding
spec:
policyName: my-policy # reference đến ValidatingAdmissionPolicy
validationActions:
- Deny # reject request nếu vi phạm
# - Audit # log nhưng không reject
# - Warn # warning nhưng không reject
matchResources:
namespaceSelector:
matchLabels:
environment: production # chỉ apply trong production namespaces
6. Common Policies
6.1 Block Images with Tag "latest"
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: no-latest-tag
spec:
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments", "statefulsets", "daemonsets"]
validations:
- expression: |
object.spec.template.spec.containers.all(c,
!c.image.contains(":latest") &&
c.image.contains(":")
)
message: "Images phải có specific tag, không được dùng :latest hoặc không có tag"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: no-latest-tag-binding
spec:
policyName: no-latest-tag
validationActions: [Deny]
6.2 Required Resource Limits
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: require-resource-limits
spec:
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments"]
validations:
- expression: |
object.spec.template.spec.containers.all(c,
has(c.resources) &&
has(c.resources.limits) &&
has(c.resources.limits.cpu) &&
has(c.resources.limits.memory)
)
message: "Tất cả containers phải có resource limits (CPU và Memory)"
- expression: |
object.spec.template.spec.initContainers.all(c,
has(c.resources) &&
has(c.resources.limits) &&
has(c.resources.limits.cpu) &&
has(c.resources.limits.memory)
)
message: "Tất cả init containers phải có resource limits"
6.3 Require Labels
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: require-labels
spec:
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE"]
resources: ["deployments"]
validations:
- expression: "has(object.metadata.labels.team)"
message: "Deployment phải có label 'team'"
- expression: "has(object.metadata.labels.app)"
message: "Deployment phải có label 'app'"
- expression: |
object.metadata.labels.environment in ["dev", "staging", "production"]
message: "Label 'environment' phải là: dev, staging, hoặc production"
6.4 Limit Replicas
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: limit-replicas
spec:
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments"]
validations:
- expression: "object.spec.replicas <= 20"
message: "Deployment không được có quá 20 replicas"
- expression: "object.spec.replicas >= 1"
message: "Deployment phải có ít nhất 1 replica"
6.5 Prevent Privilege Escalation__HTMLTAG_128___
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: no-privileged
spec:
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["pods"]
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments", "statefulsets", "daemonsets"]
validations:
- expression: |
!object.spec.template.spec.containers.exists(c,
has(c.securityContext) &&
has(c.securityContext.privileged) &&
c.securityContext.privileged == true
)
message: "Privileged containers không được phép"
- expression: |
!object.spec.template.spec.containers.exists(c,
has(c.securityContext) &&
has(c.securityContext.allowPrivilegeEscalation) &&
c.securityContext.allowPrivilegeEscalation == true
)
message: "allowPrivilegeEscalation phải là false"
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: no-privileged
spec:
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["pods"]
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments", "statefulsets", "daemonsets"]
validations:
- expression: |
!object.spec.template.spec.containers.exists(c,
has(c.securityContext) &&
has(c.securityContext.privileged) &&
c.securityContext.privileged == true
)
message: "Privileged containers không được phép"
- expression: |
!object.spec.template.spec.containers.exists(c,
has(c.securityContext) &&
has(c.securityContext.allowPrivilegeEscalation) &&
c.securityContext.allowPrivilegeEscalation == true
)
message: "allowPrivilegeEscalation phải là false"
7. Policy with Parameters
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: max-replicas-param
spec:
paramKind:
apiVersion: v1
kind: ConfigMap
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments"]
validations:
- expression: "object.spec.replicas <= int(params.data.maxReplicas)"
message: "Vượt quá số replicas tối đa"
---
# Parameter ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: max-replicas-config
data:
maxReplicas: "5"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: max-replicas-binding
spec:
policyName: max-replicas-param
paramRef:
name: max-replicas-config
namespace: default
validationActions: [Deny]
8. Comparison: ValidatingAdmissionPolicy vs OPA/Gatekeeper
Feature ValidatingAdmissionPolicy OPA/Gatekeeper
────────────────────────────────────────────────────────────────
Deploy required ❌ Built-in ✅ Yes (webhook)
Language CEL Rego
Mutating policies ❌ No ✅ Yes
Complex logic Limited Full Rego
Performance Excellent (in-process) Good (HTTP call)
Vendor support Kubernetes core CNCF project
K8s version 1.30+ (GA) Any
OPA/Gatekeeper is still needed when: need mutating policies (automatically inject fields), more complex policy logic than CEL support, or need mutation webhooks.
Summary
- ValidatingAdmissionPolicy GA K8s 1.30: built-in, no webhook needed
- CEL: safe expression language for policy logic
- Need binding to activate: ValidatingAdmissionPolicyBinding
- Actions: Deny, Audit, Warn
- Use params (ConfigMap) to reuse policy
- OPA/Gatekeeper: still needed for mutating and complex rego logic