Skip to content

Admission Control Security — Enforcement Bằng Policy

Vì sao admission control là control plane bảo mật

Mọi cơ chế ở các file trước — securityContext (file 06), Network Policy (file 07), Workload Identity (file 04) — chỉ có tác dụng nếu workload thực sự được cấu hình đúng. Nhưng ai đảm bảo điều đó? Dựa vào kỷ luật developer là chiến lược thất bại ở quy mô (file 06 đã lập luận). Câu trả lời là admission control: cổng cuối cùng mà mọi object phải đi qua trước khi được lưu vào etcd, nơi bạn có thể từ chối hoặc sửa bất kỳ thứ gì không đạt chuẩn bảo mật — tự động, trên mọi deploy, không thể lách.

Admission control biến chính sách bảo mật từ "tài liệu hướng dẫn mà mọi người nên theo" thành "luật được enforce bởi máy". Một Pod chạy root bị từ chối tại admission, không phải bị phát hiện sau đó. Một image từ registry lạ bị chặn trước khi chạy, không phải bị điều tra sau sự cố. Đây là điểm chuyển từ "hy vọng đúng" sang "đảm bảo đúng".

Quan trọng: cơ chế chi tiết của admission pipeline — thứ tự mutating/validating, webhook configuration, certificate management, failure modes, CEL/ValidatingAdmissionPolicy — đã được trình bày sâu ở Chương 10. File này không lặp lại cơ chế; nó tập trung vào cách dùng admission control như một công cụ enforcement bảo mật, các trường hợp dùng security cụ thể, rủi ro bảo mật của chính admission, và so sánh các policy engine cho mục đích bảo mật. Khi cần hiểu cách webhook hoạt động, tham chiếu Chương 10; ở đây ta hỏi enforce policy bảo mật gì và bằng công cụ nào.

Internal model: admission như cổng enforcement bảo mật

Một deploy request đi qua hai loại admission (đã chi tiết ở Chương 10): mutating (sửa object) chạy trước, rồi validating (chấp nhận/từ chối) chạy sau. Từ góc bảo mật, hai loại này phục vụ hai mục đích khác nhau:

  • Validating cho enforcement (chặn): "Pod này có chạy root không? Image từ registry tin cậy không? Có securityContext bắt buộc không?" — nếu không đạt, từ chối. Đây là phần lớn use case bảo mật.
  • Mutating cho remediation (sửa): "Tự thêm securityContext mặc định, tự inject sidecar, tự gắn label" — sửa object cho đúng chuẩn trước khi lưu. Mạnh nhưng nguy hiểm hơn (xem phần rủi ro).

Các use case enforcement bảo mật điển hình mà admission control giải quyết:

Mục tiêu bảo mậtLoạiMô tả
Chặn image từ registry không tin cậyValidatingChỉ cho image từ REGION-docker.pkg.dev/PROJECT/...
Cấm tag latest / bắt pin digestValidatingImage phải dùng @sha256:..., không :latest
Bắt buộc securityContext (non-root, drop ALL)ValidatingTừ chối Pod thiếu hardening (bổ sung PSA)
Cấm privileged, hostPath, host namespaceValidatingEnforce baseline ngoài PSA cho rule tùy biến
Bắt buộc label/annotation (owner, cost-center)Validating/MutatingGovernance + truy vết
Tự thêm securityContext mặc địnhMutatingRemediation cho workload thiếu cấu hình
Inject sidecar (service mesh, logging)MutatingTự động hóa hạ tầng

Quan hệ với Pod Security Admission (file 06): PSA enforce ba chuẩn cố định (Privileged/Baseline/Restricted) ở cấp namespace. Admission control bằng policy engine bổ sung cho PSA khi bạn cần: rule vượt ngoài ba chuẩn (ví dụ chặn registry cụ thể), ngoại lệ theo workload, hoặc logic tùy biến. PSA là sàn chuẩn hóa; policy engine là phần mở rộng linh hoạt.

Rủi ro bảo mật của chính admission control

Admission webhook là một thanh kiếm hai lưỡi — nó nằm trên đường đi của mọi request tới API server, nên một webhook cấu hình sai có thể làm chết cluster hoặc tạo lỗ hổng. Đây là góc bảo mật mà Chương 10 đề cập về stability; ở đây ta nhấn mạnh hệ quả an ninh.

failurePolicy: trade-off giữa an toàn và sẵn sàng

failurePolicy của một ValidatingWebhook quyết định điều gì xảy ra khi webhook không phản hồi (down, timeout):

  • failurePolicy: Fail: nếu webhook không trả lời, từ chối request. An toàn về bảo mật (không có gì lọt qua khi policy engine down) nhưng nguy hiểm cho availability: nếu policy engine chết, không ai deploy được gì, kể cả việc sửa chính policy engine — một deadlock có thể làm tê liệt cluster.
  • failurePolicy: Ignore: nếu webhook không trả lời, cho qua request. An toàn cho availability nhưng tạo lỗ hổng bảo mật: kẻ tấn công (hoặc một sự cố) làm webhook down rồi deploy thứ mà policy đáng lẽ chặn.

Đây là một quyết định bảo mật có chủ đích, không có đáp án phổ quát. Khuyến nghị thực hành: với policy bảo mật quan trọng (Binary Authorization, chặn privileged), nghiêng về Fail nhưng phải đảm bảo policy engine có tính sẵn sàng cao (nhiều replica, PodDisruptionBudget, chạy trên node ổn định) và exclude các namespace hệ thống (kube-system) khỏi webhook để tránh deadlock khi sửa chữa. Với policy không quan trọng, Ignore để tránh làm vỡ cluster.

Mutating webhook: rủi ro của việc sửa ngầm

Mutating webhook thay đổi object — và một mutating webhook bị compromise hoặc cấu hình sai có thể là vector tấn công nghiêm trọng: nó có thể inject một sidecar độc hại vào mọi Pod, gắn thêm capability, mount một volume nhạy cảm, hoặc đổi image sang một image của kẻ tấn công. Vì mutation xảy ra ngầm (developer không thấy), thay đổi độc hại có thể không bị phát hiện.

Hệ quả bảo mật:

  • Bảo vệ webhook configuration như tài nguyên đặc quyền: quyền tạo/sửa MutatingWebhookConfiguration gần như tương đương quyền sửa mọi workload trong cluster. RBAC cho object này phải cực kỳ hạn chế.
  • Audit mutation: dùng audit log để theo dõi webhook nào mutate gì. Một mutating webhook lạ xuất hiện là cờ đỏ.
  • Ưu tiên validating hơn mutating khi có thể: validating chỉ từ chối, không sửa, nên ít rủi ro hơn. Dùng mutating chỉ khi remediation tự động thực sự cần (sidecar injection của service mesh là use case chính đáng).

CEL policy in-tree: bớt phụ thuộc webhook

Một xu hướng quan trọng (chi tiết ở Chương 10): ValidatingAdmissionPolicy dùng CEL (Common Expression Language) cho phép viết policy validation ngay trong API server, không cần webhook ngoài. Từ góc bảo mật, đây là một cải thiện đáng kể:

  • Loại bỏ một thành phần có thể down/compromise: không có webhook ngoài nghĩa là không có failurePolicy deadlock, không có certificate để quản lý, không có service ngoài để bảo vệ.
  • Giảm attack surface: ít thành phần hơn trên đường request = ít chỗ sai và ít chỗ bị tấn công.
  • Hiệu năng và độ tin cậy cao hơn: chạy in-process trong API server.

Trade-off: CEL phù hợp cho validation logic theo object (kiểm tra field của Pod), nhưng kém linh hoạt hơn webhook cho logic phức tạp cần state ngoài (gọi API khác, tra cứu database). Với phần lớn policy bảo mật phổ biến (chặn privileged, bắt securityContext, cấm latest), CEL/ValidatingAdmissionPolicy là lựa chọn hiện đại nên ưu tiên; webhook dành cho logic thực sự cần sức mạnh lập trình đầy đủ. Tương tự có MutatingAdmissionPolicy (CEL) cho mutation đơn giản, giảm nhu cầu mutating webhook.

OPA/Gatekeeper vs Kyverno: chọn policy engine cho bảo mật

Khi cần một policy engine đầy đủ (vượt ngoài PSA và CEL cơ bản), hai lựa chọn chủ đạo trong hệ sinh thái Kubernetes là OPA/GatekeeperKyverno. So sánh từ góc bảo mật và vận hành:

Tiêu chíOPA/GatekeeperKyverno
Ngôn ngữ policyRego (ngôn ngữ riêng, mạnh nhưng học khó)YAML (Kubernetes-native, dễ tiếp cận)
Mô hìnhConstraintTemplate + Constraint (constraint framework)Policy/ClusterPolicy declarative
ValidationMạnh, linh hoạtMạnh
MutationCó (hạn chế hơn)Mạnh, trực quan
Generation (tạo resource)Không phải thế mạnhMạnh (tự tạo NetworkPolicy, default config...)
Đường cong họcDốc (Rego)Thoải hơn (YAML)
Hệ sinh thái GCPNền của Policy Controller (managed)Cộng đồng

Tóm tắt quyết định:

  • Kyverno thắng về khả năng tiếp cận: policy viết bằng YAML, đội ngũ Kubernetes đọc hiểu ngay, đặc biệt mạnh cho mutation và generation. Lựa chọn tốt nếu ưu tiên tốc độ áp dụng và không muốn học Rego.
  • OPA/Gatekeeper thắng về tính chuẩn hóa và tích hợp GCP: Rego mạnh cho logic phức tạp, constraint framework có cấu trúc tốt cho governance quy mô lớn, và quan trọng nhất — nó là nền của GKE Policy Controller managed. Nếu dùng Policy Controller (phần dưới), bạn đang dùng Gatekeeper.

Policy Controller: Gatekeeper managed của GKE

GKE Policy Controller (một phần của GKE Enterprise/Anthos Config Management) là một bản Gatekeeper được Google quản lý, tích hợp sâu vào GKE. Giá trị bảo mật của nó:

  • Constraint framework với policy library sẵn: Google cung cấp một thư viện constraint template sẵn dùng (chặn privileged, bắt registry, enforce label, áp CIS benchmark...) — bạn không phải viết Rego từ đầu cho các policy phổ biến.
  • Quản lý vòng đời policy bởi Google: cài đặt, nâng cấp, vận hành Gatekeeper được Google lo, giảm gánh nặng vận hành một thành phần admission quan trọng.
  • Tích hợp Config Sync (GitOps): policy được đồng bộ từ Git tới mọi cluster trong fleet, đảm bảo nhất quán policy bảo mật trên toàn tổ chức — một cluster mới tự động nhận policy chuẩn.
  • Audit và compliance reporting: Policy Controller có thể audit các resource đang chạy so với constraint (không chỉ chặn lúc admission), surfacing vi phạm hiện hữu — tích hợp với góc Security Posture (file 10).

Với tổ chức chạy nhiều cluster cần policy bảo mật nhất quán, Policy Controller + Config Sync là mô hình mạnh: định nghĩa policy một lần trong Git, enforce tự động khắp fleet, audit liên tục.

Production architecture patterns

Pattern: phân tầng enforcement — PSA + CEL + Policy Controller

Một kiến trúc enforcement trưởng thành dùng nhiều lớp đúng vai trò: PSA cho ba chuẩn cơ bản (sàn nhanh, không phụ thuộc thành phần ngoài); CEL/ValidatingAdmissionPolicy cho các rule object-level phổ biến (chặn latest, bắt label) — in-tree, nhẹ; và Policy Controller cho governance phức tạp đa cluster (registry whitelist, CIS compliance, policy tùy biến) — managed, GitOps. Không dồn mọi thứ vào một engine; dùng công cụ nhẹ nhất đủ cho từng loại policy.

Pattern: policy-as-code trong CI trước khi tới cluster

Shift-left enforcement: chạy chính các policy (Gatekeeper/Kyverno/Conftest) trong CI pipeline trên manifest trước khi deploy. Developer nhận phản hồi sớm (PR bị fail vì Pod chạy root) thay vì deploy bị từ chối lúc runtime. Cluster admission vẫn là cổng cuối (defense-in-depth), nhưng phần lớn vi phạm bị bắt sớm ở CI — giảm ma sát và tăng tốc độ sửa.

Common mistakes / anti-patterns

1. failurePolicy: Fail mà không exclude kube-system / không HA cho engine. Hệ quả: policy engine down → không deploy được gì → không sửa được engine → deadlock tê liệt cluster. Phòng tránh: HA cho policy engine, exclude namespace hệ thống, có break-glass quy trình.

2. Để quyền tạo MutatingWebhookConfiguration rộng. Hệ quả: ai có quyền này có thể inject mutation vào mọi Pod — gần như cluster-admin ngầm. Phòng tránh: RBAC cực hạn chế cho webhook configuration object; audit thay đổi.

3. Chỉ dựa vào admission, bỏ qua audit của resource đang chạy. Admission chỉ chặn lúc tạo mới; resource đã chạy trước khi áp policy vẫn vi phạm. Hệ quả: lỗ hổng tồn đọng không bị phát hiện. Phòng tránh: dùng audit mode của Policy Controller/Gatekeeper để quét resource hiện hữu (kết nối file 10).

4. Viết policy quá chặt làm vỡ deploy hợp lệ. Một constraint registry whitelist quên một registry hệ thống → Pod hệ thống không pull được image. Hệ quả: outage. Phòng tránh: rollout policy ở dryRun/audit trước, quan sát vi phạm, rồi mới enforce (giống pattern PSA file 06).

5. Dùng mutating webhook khi validating là đủ. Hệ quả: tăng rủi ro (mutation ngầm) cho thứ chỉ cần từ chối. Phòng tránh: ưu tiên validating; chỉ mutate khi remediation tự động thực sự cần.

GCP-native implementation guidance

Ví dụ một ValidatingAdmissionPolicy (CEL, in-tree) cấm container privileged — không cần webhook ngoài:

yaml
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: deny-privileged
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE"]
        resources: ["pods"]
  validations:
    - expression: >-
        !object.spec.containers.exists(c,
          has(c.securityContext) &&
          has(c.securityContext.privileged) &&
          c.securityContext.privileged == true)
      message: "Container privileged bị cấm bởi chính sách bảo mật."

Ví dụ một Gatekeeper Constraint (qua Policy Controller) chỉ cho image từ Artifact Registry của project:

yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
  name: only-internal-registry
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    excludedNamespaces: ["kube-system", "gke-system"]   # tránh tự khóa
  parameters:
    repos:
      - "REGION-docker.pkg.dev/PROJECT_ID/"

Lưu ý excludedNamespaces cho các namespace hệ thống trong cả hai ví dụ — đây là biện pháp chống tự-khóa quan trọng: nếu policy áp cả lên kube-system, một thành phần hệ thống không khớp policy có thể không khởi động được.

Operational implications

Admission control có một đặc tính vận hành định hình mọi quyết định về nó: nó nằm trên critical path của mọi thay đổi cluster, nên độ tin cậy của nó độ tin cậy của khả năng deploy. Một policy engine được thiết kế cho bảo mật nhưng vận hành kém (single replica, failurePolicy Fail, áp cả kube-system) biến chính nó thành single point of failure — và một sự cố policy engine có thể nghiêm trọng hơn sự cố mà nó định ngăn. Đây là lý do mọi triển khai admission bảo mật phải cân chính sách (failurePolicy), tính sẵn sàng (HA), và phạm vi (exclude system namespace) như một bài toán thống nhất, không phải bật policy rồi quên.

Hệ quả thứ hai: admission control chuyển chi phí bảo mật từ "điều tra sau sự cố" sang "đầu tư trước vào policy", và đây gần như luôn là đánh đổi đúng. Một policy chặn registry lạ viết một lần ngăn vô số sự cố supply chain tiềm tàng; một CEL rule cấm privileged enforce trên mọi deploy mãi mãi. Khi kết hợp với Binary Authorization (file 09) cho chuỗi cung ứng image và audit/posture (file 10) cho phát hiện, admission control hoàn thiện lớp phòng thủ supply chain: chỉ image đúng nguồn (Binary Authorization) với cấu hình đúng chuẩn (admission policy) mới chạy được, và mọi ngoại lệ đều để lại dấu vết.

References