Kubernetes Policy as Code với Kyverno: Hướng dẫn thực hành không cần Rego

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

Bắt đầu nhanh: Triển khai Kyverno trong 5 phút

Sáu tháng trước, đội ngũ platform của chúng tôi cần triển khai admission control trên 14 production cluster đang chạy khoảng 600 microservices. Các kỹ sư vốn đã phải xoay xở với Helm, Kustomize và Terraform. Việc buộc họ phải học thêm ngôn ngữ Rego DSL của Open Policy Agent ngay lập tức vấp phải sự phản đối. Chúng tôi đã chuyển sang Kyverno, một policy engine mã nguồn mở coi các policy như những Kubernetes manifest tiêu chuẩn.

Việc triển khai Kyverno chỉ mất chưa đầy hai phút bằng Helm:

# Thêm Helm repository chính thức của Kyverno
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update

# Cài đặt admission controllers với cấu hình high-availability
helm install kyverno kyverno/kyverno \
  --namespace kyverno \
  --create-namespace \
  --set admissionController.replicas=3

Khi cả ba controller pod đều chuyển sang trạng thái Running, bạn đã có thể áp dụng quy tắc bảo mật đầu tiên. Dưới đây là một cluster-wide policy dùng để chặn các container chạy quyền root:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-run-as-non-root
spec:
  validationFailureAction: Enforce
  background: true
  rules:
  - name: check-run-as-non-root
    match:
      any:
      - resources:
          kinds:
          - Pod
    validate:
      message: "Không cho phép chạy container bằng quyền root. Hãy đặt securityContext.runAsNonRoot thành true."
      pattern:
        spec:
          securityContext:
            runAsNonRoot: true

Lưu manifest này thành require-non-root.yaml và áp dụng bằng lệnh kubectl apply -f require-non-root.yaml. Kyverno sẽ từ chối bất kỳ deployment nào thiếu trường này ngay tại giai đoạn admission của API server.

Kiến trúc: Vì sao Policy thuần YAML lại chiếm ưu thế

Gatekeeper coi các tài nguyên Kubernetes như những tài liệu JSON tùy ý và phân tích chúng qua các truy vấn Rego. Kyverno chọn một hướng đi khác. Nó mô hình hóa các policy dưới dạng Kubernetes Custom Resource Definitions (CRD) khớp với schema của các workload chuẩn.

Cách thức hoạt động của Admission Webhook

Kyverno gắn trực tiếp vào vòng đời admission của kube-apiserver thông qua dynamic webhook:

  • Mutating Webhook: Tiêm các giá trị mặc định trước khi kiểm tra schema validation. Nó có thể tự động thêm các label bắt buộc, inject sidecar proxy, hoặc thiết lập security context an toàn.
  • Validating Webhook: Đánh giá payload gửi đến dựa trên các quy tắc đang hoạt động. Nó sẽ cho phép các đối tượng hợp lệ đi qua hoặc trả về thông báo lỗi chi tiết, dễ hiểu trực tiếp cho lập trình viên.
  • Background Controller: Quét trạng thái hiện tại của cluster định kỳ mỗi 60 phút để so khớp với các quy tắc mới áp dụng. Nó tạo ra các đối tượng PolicyReport giúp đội ngũ bảo mật kiểm tra độ sai lệch (drift) mà không làm gián đoạn các workload đang chạy.

4 Loại Quy Tắc Cốt Lõi

Kyverno xử lý bốn kịch bản vận hành riêng biệt:

  1. Validate: Kiểm tra các trường dữ liệu của tài nguyên bằng overlay pattern hoặc biểu thức Common Expression Language (CEL).
  2. Mutate: Chỉnh sửa các đối tượng thông qua Strategic Merge Patch hoặc RFC 6902 JSON patch.
  3. Generate: Nhân bản hoặc tự động tạo các tài nguyên phụ trợ—chẳng hạn như manifest NetworkPolicy hoặc ResourceQuota mặc định—khi xuất hiện tài nguyên kích hoạt (trigger).
  4. Verify Images: Xác thực chữ ký chuỗi cung ứng của Cosign và Sigstore dựa trên public key đáng tin cậy trước khi container runtime thực hiện pull image.

Tự Động Hóa Nâng Cao: Mutation và Tự Động Tạo Tài Nguyên

Chặn các manifest lỗi mới chỉ giải quyết được một nửa vấn đề. Một giải pháp platform engineering tốt cần tự động sửa các lỗi cấu hình nhỏ để lập trình viên có thể triển khai ứng dụng một cách mượt mà nhất.

Tự Động Thiết Lập Cấu Hình An Toàn Mặc Định

Đừng bắt lập trình viên phải ghi nhớ từng cờ Linux capability. Hãy sử dụng một quy tắc mutation để tự động loại bỏ các quyền hạn nguy hiểm:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: mutate-pod-security-defaults
spec:
  rules:
  - name: drop-all-capabilities
    match:
      any:
      - resources:
          kinds:
          - Pod
    mutate:
      patchStrategicMerge:
        spec:
          containers:
          - (name): "*"
            securityContext:
              capabilities:
                drop:
                - ALL

Tự Động Hóa Cô Lập Multi-Tenant

Mỗi khi một kỹ sư tạo mới một namespace, cluster của chúng tôi sẽ tự động thiết lập các rào chắn cô lập. Kyverno tạo một network policy chặn toàn bộ traffic đến theo mặc định (default-deny) mà không cần viết thêm bất kỳ custom Go operator nào:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: auto-generate-namespace-security
spec:
  rules:
  - name: generate-default-deny-networkpolicy
    match:
      any:
      - resources:
          kinds:
          - Namespace
    generate:
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      name: default-deny-ingress
      namespace: "{{request.object.metadata.name}}"
      synchronize: true
      data:
        spec:
          podSelector: {}
          policyTypes:
          - Ingress

Nhờ kích hoạt synchronize: true, Kyverno đóng vai trò như một self-healing controller. Nếu ai đó vô tình xóa hoặc chỉnh sửa NetworkPolicy vừa được tạo, Kyverno sẽ khôi phục lại cấu hình chuẩn ban đầu chỉ trong vài giây.

4 Bài Học Đắt Giá Từ Thực Tế Triển Khai Production

Việc triển khai admission controller trên các production cluster đang hoạt động có thể gây ra sự cố nghiêm trọng nếu xử lý bất cẩn. Dưới đây là cách chúng tôi triển khai an toàn 45 policy trên 14 cluster:

1. Bắt Đầu Với Chế Độ Audit Trong 14 Ngày

Tuyệt đối không áp dụng policy ở chế độ Enforce ngay ngày đầu tiên. Hãy luôn đặt validationFailureAction: Audit trước:

# Kiểm tra các vi phạm được phát hiện bởi background scanner
kubectl get clusterpolicyreport -o wide
kubectl describe clusterpolicyreport cpolr-4bf9a

Việc audit giúp các product team có trọn vẹn hai sprint cycle để cập nhật manifest trước khi Kyverno bắt đầu chặn trực tiếp trên CI/CD pipeline.

2. Bảo Vệ Các System Namespace

Một lỗi cấu hình policy trong kube-system có thể làm hỏng quá trình khởi tạo node, CNI plugin hoặc CoreDNS. Hãy luôn loại trừ các namespace quan trọng này một cách rõ ràng:

spec:
  rules:
  - name: require-labels
    match:
      any:
      - resources:
          kinds:
          - Pod
    exclude:
      any:
      - resources:
          namespaces:
          - kube-system
          - kyverno
          - monitoring
          - ingress-nginx

3. Shift Left Với Kyverno CLI

Việc phát hiện vi phạm policy tại cluster gây nhiều ức chế cho lập trình viên. Hãy đưa bước đánh giá policy vào pre-commit hook và GitHub Actions bằng công cụ CLI độc lập:

# Chạy kiểm tra policy với các manifest local
kyverno apply ./policies/ --resource ./deployments/service.yaml

Trong CI pipeline của chúng tôi, bước kiểm tra này chỉ mất chưa đầy 400ms và phát hiện được 95% các vấn đề về policy trước khi mã nguồn được merge vào nhánh main.

4. Giám Sát Chặt Chẽ Độ Trễ Của Webhook

Mỗi admission request đều làm tăng thời gian round-trip đến API server. Trong các cluster của chúng tôi, độ trễ admission cơ sở duy trì ở mức dưới 15ms cho mỗi request. Hãy thiết lập cảnh báo Prometheus cho metric kyverno_admission_review_duration_seconds. Nếu độ trễ p99 vượt quá 200ms, hãy kiểm tra lại các quy tắc khớp wildcard chưa được tối ưu và scale tăng số lượng replica của admission controller.

Share: