〔CKS 筆記整理〕K8S Admission Control 完全攻略:從原理到 OPA Gatekeeper 範例

更新 發佈閱讀 26 分鐘

在 Kubernetes 的 Security Model 中,許多人誤以為只要設定好 Authentication (身分認證) 和 RBAC (權限控制),Cluster 就安全了。然而,真正決定一個 Object 能否被寫入 etcd 的關鍵檢查點,是 Admission Controllers。即便 User 通過了 Authentication 且擁有 RBAC 寫入權限,如果 Request 內容不符合 Admission Control 的規則,API Server 依然會拒絕該請求。

本文將帶您深入剖析 Admission Control 的 Core Process、Policy Engine 的實作方式,以及在 Production Environment 中的配置建議。

1. 核心流程:先 Mutate,再 Validate

Kubernetes 對於 Request 的處理順序有著嚴格的邏輯設計,理解這個順序是設計 Webhook 的基礎。整個流程遵循著一個基本原則:先 Mutate (變更),再 Validate (驗證)

Phase 1: Mutation Phase (變更階段)

當一個 Request 進入 API Server 並通過 Schema 驗證前,首先會觸發變更階段。

  • 對應物件MutatingWebhookConfiguration
  • 目的:修改 Request 的內容 (Patch)。
  • 邏輯理由:此順序的必要性在於,若等到驗證完才修改物件,修改後的內容可能再次違反規則,導致邏輯矛盾。因此,系統必須先完成所有的 Mutation,確認最終狀態後再進行檢查。
  • 實務應用
    • Istio Sidecar Injector:在 Pod 被持久化之前,自動將 istio-proxy 的容器定義注入到 Pod 中。

Phase 2: Validation Phase (驗證階段)

當所有 Mutation 都完成,且通過了 Schema 結構驗證後,請求就會進入驗證階段。

  • 對應物件ValidatingWebhookConfiguration
  • 目的:進行最終的決策 (Accept or Reject)。
  • 邏輯理由:在這個階段,系統檢查物件的最終狀態是否合法,我們無法再對物件進行任何修改。
  • 實務應用
    • OPA Gatekeeper:檢查 Pod 是否包含了必要的 Label、映像檔來源是否合法等。

2. Policy Engine 整合:OPA Gatekeeper

隨著 Cluster 規模擴大,單靠原生的檢查機制往往不足以應對複雜的合規需求。這時,我們通常會引入 Open Policy Agent (OPA) 這類通用的策略引擎,實現「策略即程式碼 (Policy as Code)」。

Gatekeeper 與 OPA 的關係:OPA 是一個通用的策略引擎,而 Gatekeeper 是 OPA 在 Kubernetes 上的 Controller 實作。Gatekeeper 透過 CRD (Custom Resource Definition) 讓 OPA 能以 Kubernetes 原生的方式進行管理與整合,解決了原生 OPA 難以與 Kubernetes API 互動的問題。

具體的架構是建立一個 ValidatingWebhookConfiguration 作為橋樑。當 API Server 收到 CREATE 或 UPDATE 請求時,會根據設定將請求暫停,並將內容轉發給 OPA Service 的 /validate 端點。OPA 接著會執行預先定義的 Rego Policy 進行評估。如果 OPA 回傳 Allow: true,API Server 才會將資料寫入 etcd;反之則會回傳錯誤訊息給使用者,達到強制執行的效果。

在選擇策略引擎時,Rego 語言有其特性與考量。Rego 的優點在於極度靈活,能夠處理非常複雜的邏輯,例如比對 Ingress Hostname 是否與現有服務衝突。然而,其學習曲線也相對較高。如果您的需求相對單純,例如僅需檢查 Label 或 Annotation,使用 YAML 編寫策略的 Kyverno 會是更容易上手的替代方案。

但若您的目標是跨平台統一策略管理(涵蓋 K8s, Terraform, Envoy 等),OPA 仍然是目前業界最常見的選擇。

3. 生產環境配置最佳實踐:Webhook 設定

在生產環境中配置 Webhook 時,最重要的參數之一是 failurePolicy。這個參數決定了:「當 Webhook Service (如 OPA) 故障或回應超時的時候,API Server 該怎麼辦?」

這裡存在著安全性與可用性的權衡。若設定為 Ignore (Fail-open),代表當 Webhook 故障時允許請求通過,這能確保服務的高可用性,但也意味著在維修期間,違規的資源可能繞過檢查進入叢集。相反地,若設定為 Fail (Fail-closed),則採取嚴格阻擋策略,直接拒絕請求。這雖然安全性最高,但也帶來風險:一旦 Webhook Service 出問題,與該 Webhook 相關的部署作業可能會受影響。

為了在確保安全的前提下避免系統無法運作,我們必須特別防範死鎖 (Deadlock) 的發生。試想一個場景:您的 OPA Pod 故障了,而您將 failurePolicy 設為 Fail,且沒有設定排除規則。此時 Kubernetes 嘗試重啟 OPA Pod,這會產生一個新的 Pod 建立請求;API Server 收到請求後,發現需要經過 Webhook 檢查,於是嘗試呼叫 OPA;但 OPA 尚未啟動,呼叫失敗;根據 Fail 策略,API Server 拒絕了 OPA Pod 的建立請求。結果就是:OPA 因為需要通過自己的檢查才能啟動,導致無法成功啟動。

因此,在啟用嚴格模式 (Fail) 時,建議務必配合 NamespaceSelectorObjectSelector 進行精確過濾。

除了透過 namespaceSelector 進行粗粒度的排除(例如排除 kube-system),實務上我們強烈建議同時使用 objectSelector。這對於高負載叢集尤為重要:如果您只想檢查帶有特定 Label 的 Pod,或者想明確豁免某些自動生成的 Pod(例如大量且頻繁變動的 CI/CD Runner),使用 objectSelector 可以大幅減少 Webhook 的負載,避免不必要的網路呼叫,這也是防止誤殺關鍵維運工具的第二道防線。

以下是一個安全的配置範本,展示了如何結合 namespaceSelectorobjectSelector

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: policy-enforcement-webhook
webhooks:
- name: validate.policy.example.com
admissionReviewVersions: ["v1"]

# 現代 K8s Best Practice,確保 Webhook 無副作用
sideEffects: None

# 避免讓 API Server 等待過久導致累積大量的 pending requests,產生效能的雪崩效應
timeoutSeconds: 5

# 嚴格模式:Webhook 連不上就拒絕請求
failurePolicy: Fail

clientConfig:
service:
name: my-webhook-service
namespace: security-tools
path: "/validate"
# 必須注入 CA Bundle,通常由 cert-manager 自動處理
caBundle: "Ci0tLS0tQk..."

rules:
- operations: ["CREATE", "UPDATE"]
apiGroups: ["*"]
apiVersions: ["*"]
resources: ["pods", "deployments", "services"]

# ========================================================
# 關鍵設定 1:排除 kube-system 與 Webhook 自身的 Namespace
# ========================================================
namespaceSelector:
matchExpressions:
# 使用 K8s 自動注入的 Label: kubernetes.io/metadata.name
# 邏輯:選取名稱 "不是" 以下列表的 Namespace
- key: kubernetes.io/metadata.name
operator: NotIn
values:
- "kube-system" # 排除系統核心組件,避免影響叢集運作
- "security-tools" # 排除 OPA 自己,防止重啟時發生死鎖

# ========================================================
# 關鍵設定 2:使用 ObjectSelector 進行精準過濾
# ========================================================
# 場景:豁免帶有特定標籤的 Pod (如緊急救援 Pod 或 CI Runner)
# 這能減少 Webhook Load,避免不必要的網路呼叫
objectSelector:
matchExpressions:
- key: app.kubernetes.io/exclude-webhook
operator: NotIn
values:
- "true"

4. K8S 原生機制:ImagePolicyWebhook 與 Cloud Provider 的限制

除了通用的 Webhook 機制,Kubernetes 還有一個專門針對 Image Compliance 的傳統機制,稱為 ImagePolicyWebhook。它專注於檢查 Image 的屬性,例如是否擁有 Cosign Signature、是否來自內部的 Harbor Registry,或是掃描後是否存在 Critical Vulnerability。

值得注意的是,ImagePolicyWebhook 與前述的 ValidatingWebhookConfiguration 在架構上有顯著差異。前者屬於 API Server 的 Startup Flag 配置 (Flag-based),需要透過 --admission-control-config-file 來掛載 Config File。這在自建的 K8s Cluster 中或許不是問題( 需有修改 /etc/kubernetes/manifests/kube-apiserver.yaml 的權限),但在 Managed K8s Service (如 EKS, AKS, GKE) 中,Cloud Provider 通常不允許 User 修改 Master Node (雲端環境使用者不會有 Control Plane 的權限)的 Startup Flag。

因此,在 Cloud Environment 中,我們幾乎無法使用原生的 ImagePolicyWebhook。現代化的替代方案是全面轉向基於 K8s Object (CRD) 動態配置的工具,如 OPA Gatekeeper 或 Kyverno。

這也是為什麼在討論定義 Validation 或 Mutation Rule 的標準 K8s Object 時,標準答案通常是 ValidatingWebhookConfigurationMutatingWebhookConfiguration,而非那些依賴 Static Config 的傳統機制。

5. 實戰演練:使用 OPA Gatekeeper 實作 Mutation 與 Validation

Gatekeeper 不僅是 Validating Webhook,近年也引入了 Mutation 功能,讓我們能透過 CRD 定義變更邏輯。

情境模擬: 接下來,我們將模擬一間公司的合規需求。公司規定所有新建立的 Namespace 都必須自動標示安全等級為 Baseline,以確保預設的安全性;同時,為了確保成本可追蹤,所有部署的 Pod 都必須包含 billing 標籤,否則應予以拒絕。

我們將透過以下步驟實現此需求:

  1. Mutate (變更):自動將所有新建立的 Namespace 加上 PSS 標籤 pod-security.kubernetes.io/enforce: baseline
  2. Validate (驗證):強制所有 Pod 必須包含 billing Label。

Step 1: 安裝 OPA Gatekeeper

在 Production Environment 中,我們強烈建議使用 Helm 進行安裝,以便於日後的版本升級與參數管理。

方法 A:使用 Helm 安裝 (推薦)

# 1. 新增 Gatekeeper Helm Repo
helm repo add gatekeeper <https://open-policy-agent.github.io/gatekeeper/charts>

# 2. 更新 Repo 資訊
helm repo update

# 3. 安裝 Gatekeeper (預設會開啟 Mutation 功能)
# 安裝至 gatekeeper-system namespace
helm install gatekeeper gatekeeper/gatekeeper \\
--namespace gatekeeper-system \\
--create-namespace

方法 B:使用 Prebuilt Manifest (快速測試)

若您只是想在本機 (如 Minikube) 快速驗證,可以直接使用 Manifest 安裝。

kubectl apply -f <https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/deploy/gatekeeper.yaml>

安裝完成後,請檢查 gatekeeper-controller-manager Deployment 是否已成功啟動。

Step 2: 實作 Mutation (使用 AssignMetadata CRD)

我們希望在 Namespace 建立時,自動注入 Pod Security Standards (PSS) 的標籤。因為我們要修改的是 Object 的 Metadata (Labels),所以必須使用 AssignMetadata CRD,而非 Assign

# 1-mutation-namespace-pss.yaml
apiVersion: mutations.gatekeeper.sh/v1beta1
kind: AssignMetadata
metadata:
name: force-pss-baseline
spec:
match:
scope: Cluster
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
# 排除 kube-system 以避免影響系統組件 (可選)
excludedNamespaces: ["kube-system"]

# Location: 指定要修改的 Metadata 路徑
# 注意:因為 key 包含斜線 '/',必須使用引號包起來
location: metadata.labels."pod-security.kubernetes.io/enforce"

parameters:
assign:
value: "baseline"

執行:kubectl apply -f 1-mutation-namespace-pss.yaml

Step 3: 實作 Validation (使用 ConstraintTemplate 與 Constraint)

Mutation 完成後,進入 Validation 階段。我們需要定義邏輯 (Template) 與參數 (Constraint) 來檢查 Pod Label。

3.1 定義邏輯 (ConstraintTemplate)

這是「規則的定義檔」,使用 Rego 語言撰寫。我們定義一個通用的 K8sRequiredLabels 模板。

# 2-template.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema:
properties:
labels:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels

# 定義 violation 規則:若此規則成立 (return true),則代表違反策略
# 回傳值包含 msg (錯誤訊息)details (額外資訊)
violation[{"msg": msg, "details": {"missing_labels": missing}}] {

# 1. 取得 Request 物件中現有的 Labels 集合
# input.review.object 是被驗證的 Kubernetes 物件
provided := {label | input.review.object.metadata.labels[label]}

# 2. 取得 Constraint 參數中要求的 Labels 集合
# input.parameters 是來自 Constraint YAML 的參數
required := {label | label := input.parameters.labels[_]}

# 3. 計算缺少的 Labels (集合相減)
missing := required - provided

# 4. 如果缺少的數量大於 0,則違反規則成立
count(missing) > 0

# 5. 格式化錯誤訊息
msg := sprintf("you must provide labels: %v", [missing])
}

執行:kubectl apply -f 2-template.yaml

3.2 實例化策略 (Constraint) 與 Dry Run

這是「規則的執行檔」,傳入具體參數。在直接強制執行 (Enforce) 之前,SRE 的最佳實踐是先開啟 Dry Run 模式。這允許我們觀察現有環境中有多少違規資源,而不實際阻擋請求。

# 3-constraint.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: require-billing-label
spec:
# Dry Run 設定:只記錄違規,不拒絕請求
# 若確認無誤後,可移除此行或改為 "deny" (預設值)
enforcementAction: dryrun

match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces: ["default"]
parameters:
labels: ["billing"]

執行:kubectl apply -f 3-constraint.yaml

註:在 dryrun 模式下,違規資訊會顯示在 Constraint 物件的 status.violations 欄位中。確認無誤後,請將 enforcementAction 移除或改為 deny 以正式啟用阻擋功能。

Step 4: 驗證 (Verification)

現在,我們同時具備了 Namespace Mutation 和 Pod Validation 能力。讓我們來測試這兩個機制。

驗證 Mutation (Namespace Label 自動注入)

  1. 建立一個乾淨的 Namespace:
    kubectl create ns project-alpha
  2. 檢查 Label 是否被自動加上:
    kubectl get ns project-alpha -o jsonpath='{.metadata.labels}'
    預期結果:您應該會看到 "pod-security.kubernetes.io/enforce":"baseline" 出現在輸出中,證明 Mutation 成功。

驗證 Validation (Pod Label 強制檢查)

假設您已將 enforcementAction 改回 deny

  1. 嘗試建立一個不合規的 Pod (缺少 billing label):
    kubectl run test-pod --image=nginx --restart=Never
    預期結果:被 Gatekeeper 拒絕。

    Error from server (Forbidden): admission webhook "validation.gatekeeper.sh" denied the request: [require-billing-label] you must provide labels: {"billing"}

  2. 建立合規的 Pod:
    kubectl run test-pod --image=nginx --restart=Never --labels=billing=finance
    預期結果:Pod 成功建立。
留言
avatar-img
留言分享你的想法!
avatar-img
Marcos的方格子
25會員
52內容數
歡迎來到「Marcos的方格子」!目前在「Marcos談科技」撰寫在職涯上學習到的知識,在「Marcos談書」分享我在日常的閱讀和心得,歡迎您的到來!!
Marcos的方格子的其他內容
2025/12/11
本文深入了解 Kubernetes Pod 安全性演進。內容涵蓋從 PSP 到 PSA 的轉變歷程、PSA 架構原理、Pod Security Standards (PSS) 安全標準解析,以及生產環境的遷移與配置實戰建議。
Thumbnail
2025/12/11
本文深入了解 Kubernetes Pod 安全性演進。內容涵蓋從 PSP 到 PSA 的轉變歷程、PSA 架構原理、Pod Security Standards (PSS) 安全標準解析,以及生產環境的遷移與配置實戰建議。
Thumbnail
2025/12/11
這篇文章將帶您回顧 Kubernetes CRI 的演進歷史,理解為何我們需要 RuntimeClass,並深入解析如何在生產環境中正確配置與管理多租戶與多元業務場景。
Thumbnail
2025/12/11
這篇文章將帶您回顧 Kubernetes CRI 的演進歷史,理解為何我們需要 RuntimeClass,並深入解析如何在生產環境中正確配置與管理多租戶與多元業務場景。
Thumbnail
2025/12/11
這篇文章將帶您從最上層的「多租戶治理策略」開始,一路向下挖掘,直到最底層的 Container Runtime 與 Linux Kernel Cgroups 是如何協同運作,來確保這些限制生效的。
Thumbnail
2025/12/11
這篇文章將帶您從最上層的「多租戶治理策略」開始,一路向下挖掘,直到最底層的 Container Runtime 與 Linux Kernel Cgroups 是如何協同運作,來確保這些限制生效的。
Thumbnail
看更多
你可能也想看
Thumbnail
不是每個人都適合自己操盤,懂得利用「專業」,才是績效拉開差距的開始
Thumbnail
不是每個人都適合自己操盤,懂得利用「專業」,才是績效拉開差距的開始
Thumbnail
生產力爆發帶來的過剩,會讓過去的「還可以啦」成為最低標準。市場需求對於出類拔萃、獨一無二的需求還是存在,但是對於那些價格高度敏感,或是只需要穩定、便宜、還可以啦的需求端來說,AI 正在迅速取代這部分的供給,中間長尾的服務提供者被 AI 替換。
Thumbnail
生產力爆發帶來的過剩,會讓過去的「還可以啦」成為最低標準。市場需求對於出類拔萃、獨一無二的需求還是存在,但是對於那些價格高度敏感,或是只需要穩定、便宜、還可以啦的需求端來說,AI 正在迅速取代這部分的供給,中間長尾的服務提供者被 AI 替換。
Thumbnail
年末總有一種莫名的魔力,讓人特別容易感到孤單。 聖誕節、跨年、緊接著農曆新年……滑開社群,不是甜蜜放閃,就是一群人早早訂好跨年行程。 明明日子算得上順遂,工作穩定無憂,生活也按部就班地往前走着,可總在萬籟俱寂的夜晚,獨自對着空蕩的房間時,心底會悄悄冒出一個念頭:今年,是不是可以不一樣?不再獨自抵
Thumbnail
年末總有一種莫名的魔力,讓人特別容易感到孤單。 聖誕節、跨年、緊接著農曆新年……滑開社群,不是甜蜜放閃,就是一群人早早訂好跨年行程。 明明日子算得上順遂,工作穩定無憂,生活也按部就班地往前走着,可總在萬籟俱寂的夜晚,獨自對着空蕩的房間時,心底會悄悄冒出一個念頭:今年,是不是可以不一樣?不再獨自抵
Thumbnail
本文闡述了Kubernetes內部網路通訊的基本概念,從容器到服務的溝通流程,並討論了Kubernetes使用的各種技術。重要的是,管理Kubernetes叢集時理解這些基本概念是極其重要的。
Thumbnail
本文闡述了Kubernetes內部網路通訊的基本概念,從容器到服務的溝通流程,並討論了Kubernetes使用的各種技術。重要的是,管理Kubernetes叢集時理解這些基本概念是極其重要的。
Thumbnail
本文章將說明如果您想要從頭建置一組具有Loadbalancer HA架構的Kubernetes Cluster時,你可能會需要做的事前準備工作。
Thumbnail
本文章將說明如果您想要從頭建置一組具有Loadbalancer HA架構的Kubernetes Cluster時,你可能會需要做的事前準備工作。
Thumbnail
本文將說明在安裝完Kubernetes Cluster之後,接下來必須要進行的CNI Plugin安裝建置方式,同時也透過這篇文章進行基本的CNI說明與比較。 1. Container Network Interface (CNI)
Thumbnail
本文將說明在安裝完Kubernetes Cluster之後,接下來必須要進行的CNI Plugin安裝建置方式,同時也透過這篇文章進行基本的CNI說明與比較。 1. Container Network Interface (CNI)
Thumbnail
今天跟大家分享在地端資料中心內建立Kubernetes叢集之後,如何針對網路進行更進一步的優化。除了CNI(容器網路接口)的設定,實務上我還會再另行建立Loadbalancer的機制。
Thumbnail
今天跟大家分享在地端資料中心內建立Kubernetes叢集之後,如何針對網路進行更進一步的優化。除了CNI(容器網路接口)的設定,實務上我還會再另行建立Loadbalancer的機制。
Thumbnail
在現今快速發展的數據應用環境之下,Kubernetes已經成為部署和管理容器化應用的首選平台。但是隨著應用服務愈來愈複雜、被攻擊的風險也愈來愈高。為了保護Kubernetes環境的安全性,跟大家介紹一個針對Kubernetes安全合規掃描的工具,幫助確保您的 Kubernetes 叢集設置和應用程序
Thumbnail
在現今快速發展的數據應用環境之下,Kubernetes已經成為部署和管理容器化應用的首選平台。但是隨著應用服務愈來愈複雜、被攻擊的風險也愈來愈高。為了保護Kubernetes環境的安全性,跟大家介紹一個針對Kubernetes安全合規掃描的工具,幫助確保您的 Kubernetes 叢集設置和應用程序
Thumbnail
「課程網站從來都沒修好」- 這是某年台大畢業歌的徵選的歌詞。 台大課程網是每個台大學生的必經之路,還記得我剛進台大的時候就被課程網這傢伙嚇得半死,選課還要加入購物車,而且購物車就算了,這個加入購物車的過程還會跳出新視窗,實在搞不清楚這個流程是幾年前的產物。
Thumbnail
「課程網站從來都沒修好」- 這是某年台大畢業歌的徵選的歌詞。 台大課程網是每個台大學生的必經之路,還記得我剛進台大的時候就被課程網這傢伙嚇得半死,選課還要加入購物車,而且購物車就算了,這個加入購物車的過程還會跳出新視窗,實在搞不清楚這個流程是幾年前的產物。
Thumbnail
本文針對Kubernetes內最基本的資源(cpu, ram, disk)的計算單位與一些實務操作,分享給自已與大家做參考。
Thumbnail
本文針對Kubernetes內最基本的資源(cpu, ram, disk)的計算單位與一些實務操作,分享給自已與大家做參考。
Thumbnail
在 Kubernetes 裡,Secret 就像是一個保險箱,可以放你任何不想公開的東西。比如說密碼、API 金鑰、憑證等,這樣的資料可能會被放在 Pod 裡,但你可以用 Secret 來避免直接在應用程式的程式碼中暴露這些機密資料。
Thumbnail
在 Kubernetes 裡,Secret 就像是一個保險箱,可以放你任何不想公開的東西。比如說密碼、API 金鑰、憑證等,這樣的資料可能會被放在 Pod 裡,但你可以用 Secret 來避免直接在應用程式的程式碼中暴露這些機密資料。
Thumbnail
Nephio是一個基於 Kubernetes(K8s) 的雲原生工具,它解決 NF 自動化 和 O-Cloud Infra 設置的問題。支援 K8s 的協調(Reconciliation),以確保當網路出現 如:故障、Scaling Events、分散式雲改變時。
Thumbnail
Nephio是一個基於 Kubernetes(K8s) 的雲原生工具,它解決 NF 自動化 和 O-Cloud Infra 設置的問題。支援 K8s 的協調(Reconciliation),以確保當網路出現 如:故障、Scaling Events、分散式雲改變時。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News