Cấu hình Admission Webhook để tự động chọn Runtime dựa trên Label
Chúng ta cần thiết lập một Admission Webhook (Gatekeeper) để kiểm tra metadata của Pod trước khi nó được tạo. Nếu Pod có label chỉ định runtime cụ thể, hệ thống sẽ tự động điều chỉnh spec.runtimeClassName.
Triển khai Gatekeeper và Policy để mapping Label sang Runtime
Đầu tiên, chúng ta sẽ tạo một Custom Resource Definition (CRD) cho Policy, sau đó định nghĩa quy tắc: nếu Pod có label secure-ai.io/runtime=kata, thì bắt buộc set runtimeClassName thành kata. Tương tự cho gvisor.
Chạy lệnh để deploy Gatekeeper vào cluster (nếu chưa có từ Phần 4):
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/v3.13.0/deploy/gatekeeper.yaml
Kết quả mong đợi: Các Namespace và CRD của Gatekeeper được tạo, các Pod của Gatekeeper (gatekeeper-controller-manager, gatekeeper-audit) chuyển sang trạng thái Running.
Định nghĩa Policy Dynamic cho Kata Containers
Tạo file cấu hình Policy để ánh xạ label sang runtime Kata. Policy này sẽ can thiệp vào webhook admission request.
Đường dẫn file: /etc/k8s/policies/kata-runtime-policy.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: enforce-kata-runtime
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
labels:
- secure-ai.io/runtime=kata
# Logic: Nếu label này có mặt, chúng ta sẽ dùng một ConstrainTemplate khác để set runtimeClassName
# Tuy nhiên, Gatekeeper chỉ enforce, không mutate. Để mutate (thay đổi spec), ta dùng MutatingWebhook hoặc K8sValidatingPolicy với logic phức tạp.
# Ở đây, ta dùng một ConstraintTemplate kết hợp với Constraint để enforce logic và mutate spec nếu cần thiết thông qua AdmissionReview.
# Để đơn giản và chuẩn, ta dùng K8sValidatingPolicy để enforce label, và một MutatingWebhook riêng để set runtimeClassName.
# Nhưng trong ngữ cảnh Gatekeeper, ta sẽ tạo một ConstraintTemplate để validate và một MutatingWebhookConfig để thực hiện thay đổi.
# Dưới đây là phần Config MutatingWebhookConfig để tự động thêm runtimeClassName dựa trên label.
---
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: ai-runtime-selector-webhook
labels:
app: gatekeeper
webhooks:
- name: runtime-selector.gatekeeper.sh
clientConfig:
service:
name: gatekeeper-webhook-service
namespace: gatekeeper-system
path: "/v1/mutation"
rules:
- operations: ["CREATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
failurePolicy: Fail
sideEffects: None
admissionReviewVersions: ["v1", "v1beta1"]
reinvocationPolicy: IfNeeded
namespaceSelector:
matchLabels:
secure-ai.io/sandbox-enabled: "true"
Kết quả mong đợi: Resource MutatingWebhookConfiguration được tạo thành công.
Triển khai ConstraintTemplate và Constraint cho Logic động
Bây giờ, ta cần định nghĩa logic Rego (chính sách) bên trong Gatekeeper để đọc label và yêu cầu thay đổi runtimeClassName. Vì Gatekeeper mặc định chỉ Validate, ta cần cấu hình thêm Mutation policy (RegO) hoặc sử dụng K8sMutatingPolicy nếu version hỗ trợ. Tuy nhiên, cách phổ biến nhất là dùng MutatingWebhookConfig ở trên kết hợp với một Controller riêng hoặc dùng Gatekeeper để Validate, còn Mutation thì dùng một Custom Controller đơn giản hơn.
Để đảm bảo tính "Dynamic" và "Policy Engine" đúng nghĩa, ta sẽ dùng ConstraintTemplate của Gatekeeper để Validate, và một MutatingWebhook đơn giản (dùng kubectl run hoặc một deployment nhỏ) để thực hiện mutation. Nhưng để tối ưu, ta sẽ dùng tính năng rego của Gatekeeper để validate và một MutatingWebhook của Gatekeeper (nếu dùng version mới hỗ trợ mutation) hoặc dùng OPA Gatekeeper with Mutation.
Tạo file Policy để Validate và Mutation (Sử dụng ConstraintTemplate chuẩn):
Đường dẫn file: /etc/k8s/policies/ai-runtime-constraint.yaml
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8srequiredruntime
spec:
crd:
spec:
names:
kind: K8sRequiredRuntime
validation:
openAPIV3Schema:
properties:
runtimeName:
type: string
labelKey:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredruntime
violation[{
"msg": msg
}] {
input.review.object.spec.containers[_].name == "ai-model"
not input.review.object.metadata.labels[labelKey]
msg := sprintf("Pod %v requires label %v to use runtime %v", [input.review.object.metadata.name, labelKey, runtimeName])
}
# Logic để mutation (nếu Gatekeeper hỗ trợ hoặc dùng MutatingWebhook riêng)
# Ở đây ta tập trung vào Validation trước, Mutation sẽ được xử lý bởi webhook riêng bên dưới.
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredRuntime
metadata:
name: enforce-kata-label
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces: ["ai-production"]
parameters:
runtimeName: "kata"
labelKey: "secure-ai.io/runtime"
Kết quả mong đợi: Gatekeeper sẽ từ chối Pod trong namespace ai-production nếu thiếu label secure-ai.io/runtime khi container có tên ai-model.
Triển khai Mutating Webhook để tự động set RuntimeClassName
Vì Gatekeeper chủ yếu dùng để Validate, chúng ta sẽ tạo một Mutating Webhook đơn giản (dùng deployment nhỏ chạy code Go hoặc Python, hoặc dùng Kubelet admission) để tự động thêm runtimeClassName. Tuy nhiên, để đơn giản và tận dụng OPA, ta có thể dùng gatekeeper-mutation (plugin) hoặc viết một Deployment nhỏ chạy kubectl patch qua webhook.
Ở đây, ta dùng một Deployment nhỏ chạy webhook-mutator (giả lập bằng một container đơn giản đọc request và trả về patch) để minh họa luồng. Trong thực tế production, ta dùng k8s-admission-webhook hoặc OPA Gatekeeper with Mutation.
Tạo file Deployment cho Mutating Webhook:
Đường dẫn file: /etc/k8s/webhooks/runtime-mutator.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-runtime-mutator
namespace: gatekeeper-system
spec:
replicas: 2
selector:
matchLabels:
app: ai-runtime-mutator
template:
metadata:
labels:
app: ai-runtime-mutator
spec:
containers:
- name: mutator
image: ghcr.io/open-policy-agent/gatekeeper:v3.13.0
command:
- /ko-app/gatekeeper
- webhook
- --mutation-only
ports:
- containerPort: 443
resources:
limits:
cpu: 100m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: ai-runtime-mutator-service
namespace: gatekeeper-system
spec:
ports:
- port: 443
targetPort: 443
selector:
app: ai-runtime-mutator
---
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: ai-runtime-mutator-webhook
webhooks:
- name: ai-runtime-mutator.gatekeeper.sh
clientConfig:
service:
name: ai-runtime-mutator-service
namespace: gatekeeper-system
path: "/v1/mutation"
rules:
- operations: ["CREATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
failurePolicy: Fail
sideEffects: None
admissionReviewVersions: ["v1", "v1beta1"]
reinvocationPolicy: IfNeeded
Kết quả mong đợi: Deployment và Service được tạo. Webhook được đăng ký. Lưu ý: Code bên trong container phải xử lý logic đọc label và trả về JSON patch. (Giả định code đã được compile trong image).
Verify kết quả cấu hình Webhook
Đảm bảo các resource đã được tạo:
kubectl get mutatingwebhookconfiguration ai-runtime-mutator-webhook
kubectl get constrainttemplate k8srequiredruntime
kubectl get constraint k8srequiredruntime
Kết quả mong đợi: Tất cả các resource hiển thị trạng thái Available hoặc không có lỗi trong kubectl describe.
Triển khai Policy động (Dynamic Policy) dựa trên Metadata của Workload AI
Chúng ta sẽ mở rộng policy để không chỉ dựa vào label, mà còn dựa trên metadata khác như containerImage, resourceLimits, hoặc securityContext để quyết định sandbox nào phù hợp nhất.
Định nghĩa Policy động dựa trên Image và Resource
Policy này sẽ kiểm tra: Nếu image chứa từ "pytorch" và resource requests CPU > 4, thì bắt buộc dùng kata. Nếu image chứa "scikit" và CPU < 1, dùng gvisor.
Đường dẫn file: /etc/k8s/policies/dynamic-ai-policy.yaml
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8sdynamicruntime
spec:
crd:
spec:
names:
kind: K8sDynamicRuntime
validation:
openAPIV3Schema:
properties:
rules:
type: array
items:
type: object
properties:
condition:
type: string
runtime:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sdynamicruntime
violation[{
"msg": msg
}] {
container := input.review.object.spec.containers[_]
image := container.image
cpu := container.resources.requests.cpu
# Rule 1: High compute AI models -> Kata
rule := rules[_]
condition := rule.condition
runtime := rule.runtime
# Check condition (simplified logic for demo)
if condition == "high_compute" and contains(image, "pytorch") and cpu > 4 {
# If label doesn't match required runtime, violate
not input.review.object.metadata.labels["secure-ai.io/runtime"] == runtime
msg := sprintf("Workload %v with high compute requires runtime %v", [input.review.object.metadata.name, runtime])
}
# Rule 2: Light models -> gVisor
if condition == "light_model" and contains(image, "scikit") and cpu < 1 {
not input.review.object.metadata.labels["secure-ai.io/runtime"] == runtime
msg := sprintf("Workload %v with light model requires runtime %v", [input.review.object.metadata.name, runtime])
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDynamicRuntime
metadata:
name: enforce-dynamic-ai-runtime
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces: ["ai-production"]
parameters:
rules:
- condition: "high_compute"
runtime: "kata"
- condition: "light_model"
runtime: "gvisor"
Kết quả mong đợi: Policy được tạo. Khi tạo Pod vi phạm logic này, Gatekeeper sẽ trả về lỗi admission webhook "ai-runtime-mutator.gatekeeper.sh" denied the request kèm thông báo cụ thể.
Cấu hình Mutating Webhook để tự động áp dụng Runtime dựa trên Dynamic Policy
Vì Gatekeeper chỉ Validate, ta cần cập nhật Mutating Webhook (ở phần trên) để nó cũng đọc metadata và tự động thêm runtimeClassName nếu Pod chưa có.
Giả sử ta đã có một service ai-runtime-mutator chạy code Rego hoặc Go để xử lý mutation. Dưới đây là cấu hình giả lập logic mutation trong webhook (nếu dùng custom code):
Đường dẫn file: /etc/k8s/webhooks/dynamic-mutator-logic.yaml (File config cho custom webhook logic)
apiVersion: apps/v1
kind: Deployment
metadata:
name: dynamic-runtime-mutator
namespace: gatekeeper-system
spec:
replicas: 2
selector:
matchLabels:
app: dynamic-runtime-mutator
template:
metadata:
labels:
app: dynamic-runtime-mutator
spec:
containers:
- name: mutator
image: busybox:latest
command:
- /bin/sh
- -c
- |
# Mock logic: In real world, this would be a Go/Python app reading AdmissionReview
# Here we just echo the logic for documentation
echo "Checking image: $IMAGE"
if echo "$IMAGE" | grep -q "pytorch"; then
echo "Detected PyTorch, setting runtimeClassName: kata"
elif echo "$IMAGE" | grep -q "scikit"; then
echo "Detected Scikit, setting runtimeClassName: gvisor"
fi
env:
- name: IMAGE
value: "default-image"
resources:
limits:
cpu: 50m
memory: 64Mi
---
apiVersion: v1
kind: Service
metadata:
name: dynamic-runtime-mutator-service
namespace: gatekeeper-system
spec:
ports:
- port: 443
targetPort: 8080
selector:
app: dynamic-runtime-mutator
---
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: dynamic-runtime-mutator-webhook
webhooks:
- name: dynamic-runtime-mutator.gatekeeper.sh
clientConfig:
service:
name: dynamic-runtime-mutator-service
namespace: gatekeeper-system
path: "/mutate"
rules:
- operations: ["CREATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
failurePolicy: Fail
sideEffects: None
admissionReviewVersions: ["v1", "v1beta1"]
reinvocationPolicy: IfNeeded
Kết quả mong đợi: Webhook được cập nhật. Khi Pod được tạo, webhook sẽ can thiệp và thêm runtimeClassName vào spec của Pod dựa trên logic image.
Verify kết quả Dynamic Policy
Tạo một Pod với image PyTorch và CPU cao, không có label runtime:
cat
Kết quả mong đợi:
- Pod bị từ chối bởi Validating Webhook nếu chưa có label (do Policy
K8sRequiredRuntime).
- Nếu ta đã cấu hình Mutation đúng, Pod sẽ được tạo với
runtimeClassName: kata tự động.
- Chạy
kubectl describe pod pytorch-model -n ai-production để xem RuntimeClassName: kata.
Kiểm tra luồng xử lý: Từ Request đến việc chọn Sandbox phù hợp
Chúng ta sẽ thực hiện một test end-to-end để xác minh toàn bộ luồng: User tạo Pod -> Admission Controller (Gatekeeper) validate -> Mutating Webhook thêm runtimeClassName -> Kubelet chọn runtime (Kata/gVisor) -> Pod chạy trong sandbox.
Bước 1: Tạo Pod yêu cầu Sandbox Kata (High Security)
Tạo một Pod với label secure-ai.io/runtime=kata và image nặng.
cat
Kết quả mong đợi: Pod được tạo thành công. Kiểm tra trạng thái:
kubectl get pod secure-ai-kata-test -n ai-production -o jsonpath='{.spec.runtimeClassName}'
Output phải là: kata.
Bước 2: Tạo Pod yêu cầu Sandbox gVisor (Untrusted Library)
Tạo Pod với label secure-ai.io/runtime=gvisor và image nhẹ.
cat
Kết quả mong đợi: Pod được tạo thành công.
kubectl get pod secure-ai-gvisor-test -n ai-production -o jsonpath='{.spec.runtimeClassName}'
Output phải là: gvisor.
Bước 3: Kiểm tra Pod bị từ chối khi không có Runtime phù hợp
Tạo Pod trong namespace ai-production nhưng không có label secure-ai.io/runtime hoặc label sai.
cat
Kết quả mong đợi: Lỗi từ Gatekeeper.
kubectl get pod invalid-ai-test -n ai-production
Output hiển thị trạng thái ContainerCreating hoặc bị Failed với lý do:
admission webhook "k8srequiredruntime.gatekeeper.sh" denied the request: Pod invalid-ai-test requires label secure-ai.io/runtime to use runtime kata (hoặc tương tự tùy policy).
Bước 4: Xác minh Runtime thực tế đang chạy
Để chắc chắn Pod đang chạy trong sandbox đúng, ta cần kiểm tra process hoặc log của Kubelet/Runtime.
Đối với Kata Containers:
kubectl logs -n kata-system kata-runtime-controller | grep secure-ai-kata-test
Hoặc dùng kata-monitor (nếu cài đặt):
kata-monitor list | grep secure-ai-kata-test
Đối với gVisor:
kubectl logs -n gvisor-system runsc | grep secure-ai-gvisor-test
Kết quả mong đợi: Xuất hiện log khởi tạo sandbox tương ứng với tên Pod.
Bước 5: Kiểm tra Audit Log của Policy Engine
Để xem chi tiết quyết định của Policy Engine (Gatekeeper), ta kiểm tra audit log hoặc status của Constraint.
kubectl get auditreport -n gatekeeper-system -o json | jq '.items[] | select(.name | contains("secure-ai-kata-test"))'
Kết quả mong đợi: Xuất hiện báo cáo audit cho Pod đó, với trạng thái pass nếu policy đúng, hoặc fail nếu vi phạm.
Tổng kết luồng xử lý
1. User gửi request tạo Pod.
2. API Server nhận request và gọi Mutating Webhook.
3. Mutating Webhook đọc metadata (image, cpu) và thêm runtimeClassName nếu cần.
4. API Server gọi Validating Webhook (Gatekeeper).
5. Gatekeeper kiểm tra label và policy động.
6. Nếu pass, Pod được tạo. Kubelet nhận runtimeClassName và gọi runtime tương ứng (Kata/gVisor).
7. Sandbox được khởi tạo và workload chạy bên trong.
Điều hướng series:
Mục lục: Series: Xây dựng nền tảng Secure AI Sandbox với Kata Containers, gVisor và Policy Engine
« Phần 4: Xây dựng Policy Engine với OPA và Kubernetes Gatekeeper
Phần 6: Tối ưu hóa hiệu năng và bảo mật cho các mô hình Machine Learning »