🎯 Mục tiêu bài học
Hiểu ValidatingAdmissionPolicy GA K8s 1.30, viết CEL policies không cần webhook server, và biết khi nào vẫn cần OPA/Gatekeeper.
1. Vấn đề với Admission Webhooks Truyền thống
Webhook-based admission (OPA/Gatekeeper, Kyverno) có nhược điểm:
- Network overhead: mỗi API request cần gọi HTTP đến webhook service
- Availability dependency: nếu webhook service down → API requests fail
- Operational burden: phải maintain webhook deployment, TLS certs
- Latency: thêm latency cho mọi API call
2. ValidatingAdmissionPolicy — Built-in, No Webhook
ValidatingAdmissionPolicy GA từ K8s 1.30 cho phép viết validation policies trực tiếp trong API server, dùng CEL (Common Expression Language).
- Chạy trong API server process — zero network overhead
- Không cần deploy thêm service
- Không có single point of failure
- Nhanh hơn webhook ~10x
3. CEL Basics
CEL là một expression language đơn giản, an toàn (không có loops, không có 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 Chặn Image với 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 Yêu cầu 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
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 với 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. So sánh: 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
Vẫn cần OPA/Gatekeeper khi: cần mutating policies (tự động inject fields), policy logic phức tạp hơn CEL support, hoặc cần mutation webhooks.
Tóm tắt
- ValidatingAdmissionPolicy GA K8s 1.30: built-in, không cần webhook
- CEL: safe expression language cho policy logic
- Cần binding để activate: ValidatingAdmissionPolicyBinding
- Actions: Deny, Audit, Warn
- Dùng params (ConfigMap) để policy reusable
- OPA/Gatekeeper: vẫn cần cho mutating và complex rego logic