Policy as Code trên Kubernetes với Kyverno: Tự Động Hóa Kiểm Tra Cấu Hình và Bảo Mật

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

Lúc 2 giờ 47 sáng, cảnh báo kích hoạt. Một developer vừa đẩy deployment lên mà không có resource limits — lại một lần nữa. Pod đó chạy loạn, ngốn hết CPU trên node và kéo sập ba service khác. Chúng tôi đã có cuộc trò chuyện này sáu lần trong tháng qua. Post-mortem nào cũng kết thúc như nhau: “Chúng ta cần có guardrail tốt hơn.”

Đêm đó tôi ngồi xuống và triển khai thứ mình đã trì hoãn suốt nhiều tuần: Policy as Code với Kyverno. Sáu tháng sau, không còn bất kỳ sự cố nào lặp lại kiểu đó. Đây là những gì thực tế vận hành production dạy cho tôi.

Tại Sao Review Thủ Công Không Thể Mở Rộng Được

Hầu hết các team đều bắt đầu bằng code review như một mạng lưới an toàn. Ai đó nhìn qua YAML trước khi merge. Cách đó hoạt động khi bạn có hai kỹ sư và một cluster. Nhưng nó sụp đổ nhanh chóng khi có mười lăm kỹ sư deploy lên bốn môi trường khác nhau.

Vấn đề cốt lõi là: việc kiểm tra policy tại thời điểm review chỉ mang tính tư vấn, không phải bắt buộc. Ai đó approve PR lúc nửa đêm vì CI xanh và họ đã mệt. Cái securityContext bị thiếu lọt qua. Pod chạy với quyền root trên production.

Policy as Code chuyển việc kiểm tra xuống chính cluster. API server sẽ từ chối các resource không tuân thủ trước khi chúng được lên lịch chạy. Không có ngoại lệ, không có sự mệt mỏi, không có bất ngờ lúc 2 giờ sáng.

So Sánh Phương Pháp: OPA/Gatekeeper vs Kyverno vs Admission Webhooks

Khi bắt đầu đánh giá các lựa chọn, có ba hướng tiếp cận chính được đề cập. Mỗi cách giải quyết cùng một vấn đề theo cách khác nhau.

Open Policy Agent (OPA) + Gatekeeper

OPA là lựa chọn lâu đời hơn, đã được kiểm chứng nhiều hơn. Nó dùng Rego — một ngôn ngữ chính sách được xây dựng riêng — và Gatekeeper làm lớp tích hợp Kubernetes. Hệ sinh thái policy đã trưởng thành, và các tổ chức lớn có đội platform chuyên trách rất ưa chuộng nó.

Rego có đường cong học tập khá dốc. Viết một rule yêu cầu resource limits có thể mất khoảng 20 dòng logic mà hầu hết kỹ sư thấy không trực quan. Debug policy thất bại đồng nghĩa với việc đọc Rego traces. Với các team không có platform engineer chuyên trách, nó nhanh chóng trở thành nút cổ chai.

Custom Admission Webhooks

Bạn có thể tự viết webhook bằng Go hoặc bất kỳ ngôn ngữ nào hỗ trợ HTTP. Linh hoạt hoàn toàn, không phụ thuộc bên ngoài. Nhưng bạn cũng sở hữu mọi dòng code đó — bao gồm bug, việc xoay vòng TLS certificate, và yêu cầu về tính sẵn sàng. Một webhook bị hỏng có thể chặn toàn bộ deployment.

Tôi đã thấy cách tiếp cận này hoạt động tốt đúng một lần, tại một công ty có đội platform sáu người. Mọi nơi khác, nó trở thành nợ kỹ thuật mà không ai muốn đụng vào.

Kyverno

Kyverno là Kubernetes-native. Policy là các Kubernetes resource — CRD viết bằng YAML. Nếu team của bạn có thể đọc một Deployment manifest, họ có thể đọc một Kyverno policy. Không cần học ngôn ngữ mới.

Nó bao gồm ba trường hợp sử dụng đáp ứng 90% nhu cầu thực tế của các team: validation (từ chối cấu hình sai), mutation (tự động sửa hoặc bổ sung resource), và generation (tự động tạo resource liên quan).

Ưu và Nhược Điểm: Đánh Giá Thẳng Thắn

Ưu Điểm của Kyverno

  • Rào cản gia nhập thấp — policy chỉ là YAML, ai trong team cũng đọc được
  • Chế độ Audit — chạy ở chế độ Audit trước để xem cái gì sẽ fail trước khi áp dụng thực tế
  • Hỗ trợ Mutation — tự động inject sidecar, thêm label, đặt giá trị mặc định
  • Policy reports — CRD tích hợp sẵn hiển thị trạng thái tuân thủ trên các namespace
  • Phát triển tích cực — dự án đang được CNCF ươm tạo với các bản phát hành thường xuyên

Nhược Điểm của Kyverno

  • Logic phức tạp khá vụng về — các điều kiện lồng nhau sâu trở nên lộn xộn trong YAML
  • Rego biểu đạt tốt hơn — nếu policy cần logic nâng cao, OPA vượt trội về khả năng biểu đạt
  • Tính sẵn sàng của webhook quan trọng — Kyverno chạy như một webhook; bạn cần triển khai HA trên production
  • Tương đối mới hơn — ít nội dung policy từ cộng đồng hơn OPA, dù khoảng cách này đang thu hẹp nhanh

Quan Điểm Cá Nhân

Với hầu hết các team — đặc biệt những team không có platform engineering chuyên trách — Kyverno là lựa chọn mặc định đúng đắn. Chúng tôi chạy nó trên bốn cluster xử lý ~200 deployment mỗi tuần. Việc triển khai mất hai ngày. Trong sáu tháng, tôi chưa phải đụng vào cấu hình cốt lõi một lần nào. Đó là sự ổn định nhàm chán mà bạn muốn có từ các công cụ bảo mật.

Cấu Hình Khuyến Nghị Cho Production

Trước khi viết một policy nào, hãy làm đúng phần triển khai. Một Kyverno webhook bị ngừng hoạt động sẽ chặn toàn bộ request đến API server trong phạm vi của nó. Điều đó rất thảm khốc.

Chạy ít nhất ba replica trên production:

# Cài đặt qua Helm (khuyến nghị cho production)
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update

helm install kyverno kyverno/kyverno \
  --namespace kyverno \
  --create-namespace \
  --set replicaCount=3 \
  --set admissionController.replicas=3 \
  --set backgroundController.replicas=2 \
  --set cleanupController.replicas=2

Kiểm tra cấu hình webhook sau khi cài đặt. Mặc định Kyverno đặt failurePolicy: Fail — nếu Kyverno không tiếp cận được, toàn bộ việc tạo resource sẽ thất bại. Trong quá trình triển khai ban đầu, hãy cân nhắc chuyển sang failurePolicy: Ignore, sau đó thắt chặt lại khi đã xác nhận Kyverno ổn định.

# Xác minh tất cả pod đang chạy
kubectl get pods -n kyverno

# Kiểm tra cấu hình webhook
kubectl get validatingwebhookconfigurations | grep kyverno
kubectl get mutatingwebhookconfigurations | grep kyverno

Hướng Dẫn Triển Khai: Bắt Đầu Với Audit, Rồi Mới Enforce

Bật thẳng chế độ enforcement là cách nhanh nhất để đánh mất lòng tin của team. Một policy chặn deployment quan trọng vào thời điểm sai có thể phá hỏng cả sáng kiến. Hãy bắt đầu với Audit.

Bước 1: Yêu Cầu Resource Limits (sự cố đã khởi động tất cả điều này)

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-limits
  annotations:
    policies.kyverno.io/title: Yêu Cầu Resource Limits
    policies.kyverno.io/description: Tất cả container phải định nghĩa giới hạn CPU và memory.
spec:
  validationFailureAction: Audit  # Bắt đầu ở đây, sau đó đổi sang Enforce
  background: true
  rules:
    - name: check-resource-limits
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "CPU và memory limits là bắt buộc cho tất cả container."
        pattern:
          spec:
            containers:
              - name: "*"
                resources:
                  limits:
                    memory: "?*"
                    cpu: "?*"
kubectl apply -f require-resource-limits.yaml

# Kiểm tra những gì sẽ thất bại (chế độ audit)
kubectl get policyreport -A
kubectl get clusterpolicyreport

Bước 2: Chặn Privileged Containers

Các container chạy với quyền root hoặc ở chế độ privileged là vector tấn công điển hình — và phổ biến hơn bạn nghĩ trên production. Policy này sẽ chặn chúng:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-privileged-containers
spec:
  validationFailureAction: Audit
  background: true
  rules:
    - name: check-privileged
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "Không cho phép container chạy ở chế độ privileged."
        pattern:
          spec:
            containers:
              - =(securityContext):
                  =(privileged): "false"

Bước 3: Tự Động Inject Label Bằng Mutation

Mutation là nơi Kyverno thể hiện giá trị vượt ra ngoài validation. Thay vì từ chối Deployment vì thiếu label, chỉ cần tự động thêm chúng vào:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: add-default-labels
spec:
  rules:
    - name: add-team-label
      match:
        any:
          - resources:
              kinds:
                - Deployment
      mutate:
        patchStrategicMerge:
          metadata:
            labels:
              +(managed-by): "kyverno"
              +(environment): "production"

Bước 4: Xem Xét Policy Reports

# Xem tất cả vi phạm trên toàn cluster
kubectl get policyreport -A -o wide

# Báo cáo chi tiết cho một namespace cụ thể
kubectl describe policyreport -n default

# Lọc chỉ những lỗi thất bại
kubectl get policyreport -A -o json | \
  jq '.items[].results[] | select(.result == "fail")'

Hãy dành một tuần xem audit report trước khi đụng vào enforcement. Sửa các vi phạm hiện có trong workload của bạn. Sau đó chuyển từng policy sang Enforce một — không bao giờ chuyển tất cả cùng một lúc:

# Patch một policy từ Audit sang Enforce
kubectl patch clusterpolicy require-resource-limits \
  --type=merge \
  -p '{"spec":{"validationFailureAction":"Enforce"}}'

Bước 5: Sử Dụng Kyverno Policy Library

Trước khi viết policy tùy chỉnh, hãy kiểm tra thư viện chính thức. Nó đã bao gồm Pod Security Standards, CIS benchmarks và các best practice phổ biến:

# Duyệt và áp dụng policy từ cộng đồng
kubectl apply -f https://raw.githubusercontent.com/kyverno/policies/main/pod-security/baseline/disallow-host-namespaces/disallow-host-namespaces.yaml

Xử Lý Ngoại Lệ Mà Không Làm Suy Yếu Policy

Một số workload thực sự cần ngoại lệ. Một monitoring agent cấp node cần quyền truy cập privileged là ví dụ thực tế. Kyverno xử lý điều này gọn gàng với các block exclude và resource PolicyException (có từ Kyverno 1.9+).

apiVersion: kyverno.io/v2beta1
kind: PolicyException
metadata:
  name: allow-monitoring-privileged
  namespace: monitoring
spec:
  exceptions:
    - policyName: disallow-privileged-containers
      ruleNames:
        - check-privileged
  match:
    any:
      - resources:
          kinds:
            - Pod
          namespaces:
            - monitoring
          names:
            - node-exporter-*

Ngoại lệ là Kubernetes resource — được quản lý version, có thể review và audit. Không còn những quyết định bypass không có tài liệu được đưa ra lúc 2 giờ sáng bởi người trực ca.

Kết Quả Sau Sáu Tháng Vận Hành

Cái deployment gốc đó? Nó sẽ không bao giờ đến được API server nữa. Developer nhận được thông báo lỗi rõ ràng giải thích chính xác những gì còn thiếu. Họ sửa, đẩy lại, và nó hoạt động. Hai phút thay vì ba giờ ngừng hoạt động và một buổi post-mortem.

Policy reports cũng thay đổi cách chúng tôi xử lý kiểm tra tuân thủ. Câu hỏi “Tất cả workload trên production có đang chạy mà không có quyền root không?” giờ đây mất ba mươi giây để trả lời thay vì một tuần review thủ công.

Vận hành Kubernetes trên production với code review là lớp kiểm tra duy nhất của bạn là một rủi ro tiềm ẩn. Hãy cài Kyverno ở chế độ audit ngay tuần này — việc cài đặt chỉ mất mười phút, và báo cáo policy đầu tiên gần như chắc chắn sẽ chỉ cho bạn thấy điều gì đó bạn chưa ngờ tới.

Share: