Skip to content

Chương 10: GKE Admission Control & Policy Enforcement — Securing the API

Vì sao chương này là ranh giới sống còn của cluster

Admission control là lớp cuối cùng mà mọi yêu cầu ghi (write) phải đi qua trước khi được lưu vào etcd. Authentication trả lời "bạn là ai", authorization (RBAC) trả lời "bạn được phép làm gì với loại tài nguyên nào", nhưng cả hai đều không nhìn vào nội dung của đối tượng. Admission control là chỗ duy nhất trong đường đi của request có thể đọc, sửa, và từ chối một đối tượng dựa trên chính nội dung của nó: "Pod này có chạy privileged không?", "image có đến từ registry được duyệt không?", "namespace này còn quota không?", "container có thiếu requests không?". Nếu không có admission control, RBAC chỉ cho bạn nói "team A được tạo Pod" — nó không thể nói "team A được tạo Pod nhưng không được privileged".

Đó là lý do admission control vừa là cửa ngõ security mạnh nhất, vừa là điểm đơn lỗi nguy hiểm nhất của một cluster GKE. Hai mặt của cùng một đồng xu:

  • Mặt tốt: một ValidatingAdmissionWebhook hoặc một constraint Gatekeeper được cấu hình đúng có thể chặn đứng toàn bộ một lớp lỗ hổng — privilege escalation, image không đáng tin, workload thiếu resource limit — ngay tại thời điểm kubectl apply, trước khi nó kịp chạy.
  • Mặt chết người: một webhook cấu hình sai có thể đánh sập toàn bộ khả năng ghi của cluster. Đây không phải lý thuyết. Một webhook với failurePolicy: Fail trỏ tới một service đã chết, và namespaceSelector không loại trừ kube-system, sẽ làm API server từ chối mọi request CREATE/UPDATE khớp rule của nó — kể cả các Pod hệ thống cần để khôi phục chính webhook đó. Bạn rơi vào deadlock: không thể tạo Pod để sửa webhook, vì webhook đang chặn việc tạo Pod. Toàn bộ section "anti-pattern" của tài liệu Kubernetes về dynamic admission control tồn tại chính vì kiểu sự cố này (Dynamic Admission Control — best practices).

Điểm mấu chốt mà chương này nhấn mạnh xuyên suốt: admission control là một pipeline tuần tự, không phải một bộ lọc đơn lẻ. Request đi qua một chuỗi cố định — built-in mutating plugins → mutating webhooks → built-in validating plugins → validating webhooks → object schema validation → ValidatingAdmissionPolicy — và mỗi mắt xích đều có thể từ chối hoặc làm chậm toàn bộ chuỗi. Trên GKE, một phần chuỗi này do Google quản lý (vị trí trong API server, các built-in plugin được bật), nhưng phần mở rộng (webhook, PSA labels, Gatekeeper, CEL policy) là trách nhiệm hoàn toàn của bạn — và cũng là chỗ phát sinh gần như mọi sự cố admission trong production.

Điều kiện tiên quyết

  • Chương 5 (GKE Control Plane Internals): admission control là một pha trong vòng đời request của API server (Authentication → Authorization → Admission → Schema validation → etcd). Phải hiểu API server xử lý request thế nào, API Priority and Fairness ảnh hưởng ra sao đến request bị webhook làm chậm, và Chương 5 đã giới thiệu admission control pipeline ở mức tổng quan — chương này đi sâu vào vận hành và policy enforcement.
  • Kubernetes API fundamentals: GroupVersionResource (GVR), sự khác biệt giữa resource và subresource, các operation CREATE/UPDATE/DELETE/CONNECT, và mô hình declarative reconcile. Webhook rule khớp theo chính các trục này.
  • Mô hình resource & QoS (Chương 8): ResourceQuota và LimitRange thao tác trực tiếp trên requests/limitsQoS class. Hiểu sai resource model dẫn đến quota và limit range hoạt động ngược ý đồ.
  • TLS/PKI cơ bản: webhook là một HTTPS server; toàn bộ phần certificate management (CA bundle, serving cert, rotation) yêu cầu nắm chuỗi tin cậy X.509.

Mức độ sâu

5/5 — Chương đi tới mức thứ tự chính xác của các pha admission, cơ chế reinvocationPolicy: IfNeeded và vì sao một mutating webhook có thể bị gọi lại, ngữ nghĩa failurePolicy × timeoutSeconds (mặc định 10s, tối đa 30s) và tác động timeout lên độ trễ p99 của API server, sự khác biệt sideEffects: None vs NoneOnDryRun trong dry-run, từng control cụ thể của profile baseline/restricted trong Pod Security Standards, mô hình ConstraintTemplate→Constraint của Gatekeeper với enforcementAction: deny/dryrun/warn và audit loop, scope selector của ResourceQuota theo PriorityClass, maxLimitRequestRatio của LimitRange, biến CEL (object, oldObject, params, namespaceObject) trong ValidatingAdmissionPolicy (GA từ Kubernetes 1.30), và CEL custom constraint của Organization Policy cho container.googleapis.com/Cluster. Mọi tuyên bố kỹ thuật đối chiếu trực tiếp tài liệu Kubernetes và Google Cloud.


Cấu trúc chapter

1. Admission Pipeline & Built-in Plugins — Bản Đồ Cửa Ngõ API

Vị trí của admission trong vòng đời request và các plugin nội tại.

  • Hai pha cố định: Mutating phase (sửa được object) → Validating phase (chỉ đọc, từ chối được)
  • Vì sao thứ tự này bất biến và hệ quả: validating luôn thấy object đã được mutate
  • Danh sách plugin bật mặc định (Kubernetes 1.36): NamespaceLifecycle, LimitRanger, ServiceAccount, DefaultStorageClass, Priority, PodSecurity, ResourceQuota, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ValidatingAdmissionPolicy...
  • Bốn plugin then chốt: LimitRanger (mutating+validating), ResourceQuota (validating), PodSecurity (validating), NodeRestriction (validating — chống node tự nâng quyền)
  • Trên GKE bạn không sửa --enable-admission-plugins: Google chốt danh sách; đòn bẩy của bạn là webhook, PSA, Gatekeeper, CEL policy

2. Mutating & Validating Webhooks — Cơ Chế Gọi & Dry-Run

Hợp đồng giữa API server và webhook server của bạn.

  • MutatingWebhookConfiguration / ValidatingWebhookConfiguration: rules, clientConfig, admissionReviewVersions
  • Vòng AdmissionReview: request (uid, object, oldObject, userInfo, dryRun) ↔ response (allowed, patch base64 JSONPatch, status, warnings)
  • reinvocationPolicy: IfNeeded — vì sao mutating webhook có thể bị gọi lại sau khi webhook khác sửa object, và đòi hỏi idempotency
  • matchPolicy: Equivalent vs Exact, objectSelector/namespaceSelector để thu hẹp phạm vi
  • sideEffects (None/NoneOnDryRun/Unknown) và quan hệ với dry-run; vì sao dry-run là công cụ rollout an toàn
  • Audit vs enforce: dùng webhook chỉ-cảnh-báo để quan sát trước khi bật chặn

3. Webhook Failure Modes, Performance & Stability — Chống Sập Control Plane

Phần dễ gây outage nhất của cả chương.

  • failurePolicy: Fail vs Ignore — đánh đổi security với availability, ma trận quyết định
  • timeoutSeconds (mặc định 10s, tối đa 30s): webhook chậm làm tăng p99 latency mọi request khớp rule
  • Vì sao webhook nằm trên đường ghi nóng: mỗi CREATE/UPDATE khớp rule phải chờ một round-trip HTTP
  • Anti-pattern chí mạng: webhook bắt kube-system, webhook tự validate chính nó (deadlock), failurePolicy: Fail không có namespaceSelector loại trừ
  • Chiến lược ổn định: HA webhook server, loại trừ namespace hệ thống, caching, latency budget, fail-open cho path không-bảo-mật-tới-hạn

4. Webhook Certificate Management — CA Bundle & cert-manager

Vì sao webhook "tự nhiên hỏng" sau vài tháng.

  • Webhook là HTTPS server: serving cert phải hợp lệ cho <service>.<namespace>.svc
  • caBundle trong clientConfig: API server dùng nó để verify; cert hết hạn = webhook chết = (nếu Fail) cluster chết
  • cert-manager: Certificate + CA Injector tự bơm caBundle vào WebhookConfiguration
  • Rotation không downtime, self-signed CA nội bộ vs CA tổ chức, các lỗi x509 thường gặp

5. PodSecurity Admission (PSA) — Modes & Profiles

Cơ chế bảo mật Pod tích hợp sẵn, thay thế PodSecurityPolicy.

  • Ba mode: enforce (chặn), audit (ghi log), warn (cảnh báo người dùng) — cấu hình bằng label namespace
  • Version pinning: pod-security.kubernetes.io/enforce-version để cố định ngữ nghĩa qua các bản nâng cấp
  • Ba profile: privileged / baseline / restricted — từng control chi tiết (host namespaces, privileged, capabilities, hostPath, runAsNonRoot, seccompProfile, drop ALL)
  • Enforce chỉ áp lên Pod object, audit/warn áp lên cả workload resource — vì sao điều này quan trọng khi rollout
  • Exemptions (username/runtimeClass/namespace), giới hạn của PSA và khi nào cần Gatekeeper

6. Gatekeeper / Policy Controller (OPA) — ConstraintTemplate & Constraint

Policy engine khả lập trình khi PSA không đủ.

  • Kiến trúc Gatekeeper: webhook + audit controller; OPA/Rego bên dưới
  • ConstraintTemplate (định nghĩa logic + schema tham số) → Constraint (instance áp dụng giá trị cụ thể)
  • enforcementAction: deny / dryrun / warn; audit loop định kỳ (--audit-interval, mặc định 60s) phát hiện vi phạm tồn tại sẵn
  • Referential constraints (cross-object, ví dụ ingress host trùng nhau) và Config sync; constraint template library, policy bundles (PCI-DSS, NIST, CIS)
  • Policy Controller trên GKE: Gatekeeper được Google đóng gói, tích hợp Config Sync/fleet, dashboard
  • Gatekeeper vs PSA: ma trận quyết định khi nào dùng cái nào, dùng cả hai theo lớp

7. ResourceQuota & LimitRange — Quản Trị Tài Nguyên Namespace

Hai admission plugin chống một tenant nuốt cả cluster.

  • ResourceQuota: compute (requests.cpu/limits.memory...), storage (theo StorageClass), object count (pods, services, count/<resource>)
  • Scoped quota: scopeSelector theo PriorityClass, Terminating/BestEffort — vì sao quota theo priority là nền cho multi-tenancy
  • Quy tắc bắt buộc: khi có quota CPU/memory thì mọi Pod phải khai báo requests/limits, nếu không bị từ chối
  • LimitRange: default/defaultRequest (tự điền), min/max, maxLimitRequestRatio — vì sao LimitRange là cặp bài trùng giải cứu ResourceQuota
  • Thứ tự tương tác: LimitRanger (mutating) điền default → ResourceQuota (validating) kiểm tra tổng

8. ValidatingAdmissionPolicy (CEL) — Policy In-Process Không Cần Webhook

Hướng đi mới: policy chạy trong API server, không round-trip HTTP.

  • ValidatingAdmissionPolicy (GA Kubernetes 1.30) + ValidatingAdmissionPolicyBinding + paramRef
  • CEL: biến object, oldObject, request, params, namespaceObject; matchConstraints, matchConditions, variables
  • validationActions: Deny/Warn/Audit (Deny và Warn không dùng chung), failurePolicy
  • Vì sao CEL policy loại bỏ phần lớn failure mode của webhook (không có cert, không có service chết, không round-trip) — nhưng kém biểu cảm hơn Rego
  • MutatingAdmissionPolicy (mới hơn) cho mutation bằng CEL; ma trận chọn giữa webhook / Gatekeeper / CEL policy

9. Organization Policies for GKE & Admission Debugging

Guardrail tầng GCP và cách gỡ lỗi admission.

  • Organization Policy cho GKE: managed constraints + custom constraints với CEL trên container.googleapis.com/ClusterNodePool
  • Khác biệt then chốt: Org Policy chặn ở GCP API layer (cấu hình cluster: bật Autopilot, release channel, private nodes) — không phải Kubernetes admission (cấu hình Pod). Hai lớp khác nhau, bổ trợ nhau
  • Ví dụ custom constraint: bắt buộc private nodes, cấm Autopilot tắt, ràng node service account
  • Debugging admission: audit log (Policy Denied), dry-run (kubectl --dry-run=server), đọc log webhook và Gatekeeper, metric apiserver_admission_*

Bản đồ tinh thần: pipeline admission từ trái sang phải

Trước khi đi vào từng file, hãy ghim sơ đồ tuần tự này. Một request ghi đi qua đúng thứ tự sau bên trong API server (Admission Controllers Reference):

kubectl apply


[Authentication]  →  bạn là ai


[Authorization / RBAC]  →  bạn được làm gì với loại tài nguyên này


┌─────────────────────── ADMISSION ───────────────────────┐
│  1. MUTATING PHASE (sửa được object)                     │
│     • Built-in mutating: ServiceAccount, LimitRanger...  │
│     • MutatingAdmissionWebhook (của bạn)                 │
│       └─ reinvocation nếu webhook sau sửa object         │
│  2. Object schema validation                             │
│  3. VALIDATING PHASE (chỉ đọc, từ chối được)             │
│     • Built-in validating: ResourceQuota, PodSecurity... │
│     • ValidatingAdmissionPolicy (CEL, in-process)        │
│     • ValidatingAdmissionWebhook (của bạn)               │
└──────────────────────────────────────────────────────────┘


[Ghi vào etcd]

Ba quan sát quyết định mọi thứ trong chương:

  1. Mutating chạy trước validating, luôn luôn. Hệ quả: validating webhook và PSA luôn thấy object đã được mutate (ví dụ sidecar đã được inject, default request đã được LimitRanger điền). Khi debug "vì sao policy chặn object của tôi", phải nhớ object lúc validating khác object lúc bạn apply.

  2. Webhook nằm trên đường ghi nóng (hot write path). Mỗi CREATE/UPDATE khớp rule là một round-trip HTTP đồng bộ. Webhook chậm/chết không chỉ ảnh hưởng object của bạn — nó làm chậm hoặc chặn mọi request khớp rule trên toàn cluster. Đây là gốc của file 3.

  3. Có ba "engine" enforcement song song: webhook (linh hoạt, ngoài process, nhiều failure mode), Gatekeeper (Rego, mạnh nhưng nặng), và CEL policy (in-process, ít failure mode, kém biểu cảm hơn). Phần lớn quyết định kiến trúc của chương là chọn engine nào cho loại policy nào.


Cách đọc chapter theo mục tiêu công việc

Nếu bạn đang điều tra "cluster không tạo được Pod / mọi apply bị treo"

  1. File 3: gần như chắc chắn là webhook failurePolicy: Fail trỏ tới service chết, hoặc bắt nhầm kube-system.
  2. File 4: hoặc cert webhook hết hạn → API server không verify được → timeout → (nếu Fail) chặn.
  3. File 9: dùng audit log và kubectl --dry-run=server để xác định webhook/policy nào đang từ chối.

Nếu bạn đang thiết kế hardening bảo mật cho cluster mới

  1. File 5: bật PSA restricted (audit/warn trước, enforce sau) cho mọi namespace ứng dụng.
  2. File 6: thêm Gatekeeper/Policy Controller cho policy mà PSA không biểu đạt được (image registry, label bắt buộc, ràng buộc tham chiếu).
  3. File 9: dùng Organization Policy chặn ở tầng cluster (private nodes, release channel) — guardrail không thể bị bỏ qua từ trong cluster.

Nếu bạn đang xây multi-tenancy / chia hạn ngạch theo team

  1. File 7: ResourceQuota theo namespace + scoped quota theo PriorityClass; LimitRange điền default để quota không từ chối Pod thiếu request.
  2. File 5: PSA theo namespace để mỗi tenant bị giới hạn quyền Pod.
  3. File 6/8: policy bắt buộc label team/cost-center để quy trách nhiệm và tính chi phí.

Nếu bạn đang chọn cơ chế enforcement cho một policy mới

  1. File 8: nếu policy biểu đạt được bằng CEL đơn giản (so sánh field, regex label) → ValidatingAdmissionPolicy, ít failure mode nhất.
  2. File 6: nếu cần logic phức tạp, cross-object, hoặc thư viện policy chuẩn (CIS/PCI) → Gatekeeper.
  3. File 2/3: chỉ dùng webhook tự viết khi cần mutation phức tạp hoặc gọi hệ thống ngoài — và chấp nhận gánh nặng vận hành cert + HA.

Khung quyết định production (tóm tắt)

Quyết địnhTác động chínhRủi ro nếu làm saiFile nên đọc
failurePolicy Fail hay IgnoreSecurity vs availabilityFail + service chết → outage toàn cluster3
Loại trừ kube-system khỏi webhookTránh deadlock control planeKhông loại trừ → không khôi phục được3
Quản lý cert webhookWebhook sống được dài hạnCert hết hạn → webhook chết âm thầm4
PSA level (baseline/restricted)Mức hardening PodRestricted ngay → vỡ hàng loạt workload cũ5
PSA enforce ngay hay audit trướcAn toàn rolloutEnforce ngay không audit → từ chối Pod hợp lệ5
Webhook / Gatekeeper / CEL policyEngine enforcementChọn webhook cho policy đơn giản → gánh nặng vô ích2, 6, 8
ResourceQuota + LimitRangeCông bằng tài nguyênQuota không kèm LimitRange → Pod thiếu request bị từ chối7
Org Policy tầng GKEGuardrail không bỏ qua đượcThiếu → cluster sai cấu hình lọt lưới9

Năm sai lầm xuyên suốt thường gặp ở cấp chương

  1. failurePolicy: Fail mà không loại trừ namespace hệ thống. Đây là nguyên nhân số một của outage liên quan admission. Khi webhook service chết (deploy lỗi, node mất, cert hết hạn), API server từ chối mọi request khớp rule — kể cả Pod cần để khôi phục webhook. Luôn loại trừ kube-system (và các managed namespace của GKE) qua namespaceSelector, và cân nhắc Ignore cho policy không-bảo-mật-tới-hạn (file 3).
  2. Coi mutating webhook là idempotent mà không thiết kế cho reinvocation. Với reinvocationPolicy: IfNeeded, một mutating webhook có thể bị gọi nhiều lần nếu webhook khác sửa object sau nó. Webhook "luôn thêm một sidecar" sẽ thêm hai sidecar. Mọi mutation phải kiểm tra trạng thái hiện tại trước khi sửa (file 2).
  3. Bật PSA restricted enforce thẳng trên cluster đang chạy. Workload cũ gần như chắc chắn vi phạm (runAsNonRoot, drop ALL capabilities). Phải warn+audit trước, sửa workload, rồi mới enforce. Và phải pin version để bản nâng cấp Kubernetes không âm thầm siết thêm control (file 5).
  4. Dùng webhook cho mọi thứ thay vì chọn đúng engine. Webhook có cert để hết hạn, service để chết, round-trip để timeout. Phần lớn policy "field này phải bằng giá trị kia" nên là ValidatingAdmissionPolicy (CEL, in-process, không cert, không round-trip). Webhook chỉ dành cho mutation phức tạp hoặc tích hợp ngoài (file 8 vs 2).
  5. Đặt ResourceQuota mà quên LimitRange. Khi namespace có quota CPU/memory, mọi Pod buộc phải khai báo requests/limits — Pod thiếu sẽ bị từ chối thẳng. LimitRange tự điền defaultRequest/default để Pod hợp lệ. Quên LimitRange = developer liên tục bị từ chối Pod mà không hiểu vì sao (file 7).

Cross-reference với Google Cloud Architecture Framework

  • Security pillar: admission control là cơ chế "shift-left" cốt lõi — chặn cấu hình không an toàn tại thời điểm tạo, không phải phát hiện sau khi chạy (Security pillar). PSA, Gatekeeper, Binary Authorization (Chương 34) là các lớp bổ trợ.
  • Reliability pillar: nghịch lý là cơ chế security này lại là rủi ro reliability lớn nhất nếu cấu hình sai. Latency budget của webhook, failurePolicy, và loại trừ namespace hệ thống là quyết định reliability (Reliability pillar).
  • Operational excellence: dùng dry-run/audit trước enforce, version pinning cho PSA, và GitOps (Config Sync) cho policy là các thực hành vận hành chuẩn (Operational excellence pillar).

References chung của chapter


Bảng thuật ngữ then chốt của chương

Thuật ngữÝ nghĩa ngắn gọn
Mutating phasePha admission đầu, sửa được object (file 1, 2)
Validating phasePha admission sau, chỉ đọc và từ chối (file 1)
reinvocationPolicyCờ cho phép gọi lại mutating webhook sau khi object bị sửa (file 2)
failurePolicyHành vi khi webhook lỗi: Fail (chặn) hay Ignore (cho qua) (file 3)
sideEffectsKhai báo webhook có tác dụng phụ không, ảnh hưởng dry-run (file 2)
caBundleCA để API server verify cert webhook (file 4)
PSAPodSecurity Admission — bảo mật Pod tích hợp sẵn (file 5)
ConstraintTemplate / ConstraintCặp định nghĩa-logic / instance-áp-dụng của Gatekeeper (file 6)
enforcementActiondeny/dryrun/warn của constraint Gatekeeper (file 6)
scopeSelectorBộ lọc Pod cho ResourceQuota theo PriorityClass/Terminating (file 7)
maxLimitRequestRatioGiới hạn tỷ lệ limit/request trong LimitRange (file 7)
ValidatingAdmissionPolicyPolicy CEL in-process, không cần webhook (file 8)
Custom org policy constraintCEL chặn ở tầng GCP API trên cấu hình cluster (file 9)

Kết luận của chapter

Admission control là nơi security và reliability gặp nhau ở thế đối nghịch trực tiếp: cơ chế mạnh nhất để bảo vệ cluster cũng là cơ chế dễ làm sập cluster nhất. Mọi quyết định trong chương đều là một điểm cân bằng giữa hai cực này — Fail hay Ignore, enforce ngay hay audit trước, webhook ngoài-process hay CEL in-process. Người vận hành giỏi không phải người bật nhiều policy nhất, mà là người hiểu chính xác mỗi mắt xích trong pipeline làm gì, chạy ở đâu, hỏng thế nào, và do đó biết đặt enforcement ở đúng tầng với đúng engine.

Cách dùng chương hiệu quả nhất là biến nó thành một quy trình rollout policy có kỷ luật: bắt đầu bằng dry-run/audit để đo tác động, chọn engine nhẹ nhất biểu đạt được policy (CEL trước webhook), luôn loại trừ namespace hệ thống, luôn quản lý vòng đời cert, và luôn có đường thoát (break-glass) khi enforcement chặn nhầm. Khi đó admission control chuyển từ "quả bom hẹn giờ trong control plane" thành một hệ thống guardrail mà bạn có thể tin tưởng giao phó cả cluster.