Skip to content

antony@notes:~/security$ cat "實作-Validating-Admission-Policy.md"

實作 Validating Admission Policy

2025-07-26· security

認識與實作 Kubernetes Validating Admission Policy

:::spoiler 先備知識

What is Admission Control in K8s

admission controller 是一段程式碼,它會在請求經過認證 (authenticated) 與授權 (authorized) 之後,但在資源物件被永存到 etcd 之前,攔截傳送到 Kubernetes API server 的請求。

Kubernetes 的許多重要功能都必須啟用 admission controller 才能獲得妥善的支援。因此,如果一個 Kubernetes API server 沒有配置一組正確的 admission controllers,那它就是一個不完整的伺服器,而且無法支援您所期望的所有功能。

它們是什麼?

Admission controllersKubernetes API server 內的一段程式碼,它會檢查為了修改資源而傳入的請求中的資料。

Admission controllers 適用於建立 (create)、刪除 (delete) 或修改 (modify) 物件的請求。Admission controllers 也可以阻擋自訂的動詞 (verb),例如透過 API server proxy 連接到一個 pod 的請求。Admission controllers 不會(也無法)阻擋讀取(getwatchlist)物件的請求,因為讀取操作會繞過准入控制層 (admission control layer)。

准入控制機制 (Admission control mechanisms) 可能是驗證型 (validating)、變更型 (mutating),或兩者皆是。變更型 (Mutating) 的 controller 可以修改正在被變更的資源資料;驗證型 (validating) 的 controller 則不行。

Kubernetes 1.33 中,admission controllers 包含列表中的項目,它們被編譯進 kube-apiserver 的二進位檔中,並且只能由叢集管理員進行設定。

准入控制擴充點 (Admission control extension points)

在完整的清單中,有三個特殊的 controller

  1. MutatingAdmissionWebhook
  2. ValidatingAdmissionWebhook
  3. ValidatingAdmissionPolicy

這兩個 webhook controller 會(分別)執行在 API 中設定好的變更型 (mutating) 和驗證型 (validating) 的 admission control webhooks。而 ValidatingAdmissionPolicy 提供了一種方法,可以將宣告式的驗證碼嵌入到 API 之中,而無需依賴任何外部的 HTTP 呼叫。

您可以使用這三個 admission controller,在准入階段客製化叢集的行為。

准入控制階段 (Admission control phases)

准入控制的過程分為兩個階段 :

  1. 第一個階段會執行變更型 (mutating) 的 admission controllers
  2. 第二個階段則執行驗證型 (validating) 的 admission controllers

請再次注意,有些 controller 同時具備這兩種功能。如果在任一階段中有任何一個 controller 拒絕了請求,則整個請求會被立即駁回,並將錯誤回傳給終端使用者。

最後,admission controllers 除了有時會變更目標物件之外,也可能產生副作用 (side effects);也就是說,在處理請求的過程中變更相關的資源。增加配額 (quota) 的用量,就是說明為何需要此機制的典型範例。任何這類的副作用都需要一個對應的回收 (reclamation) 或調節 (reconciliation) 過程,因為任何一個特定的 admission controller 都無法確信該請求最終會通過所有其他的 admission controllers

這些呼叫的順序可參考下方說明 :

image

:::

What is Validating Admission Policy?

Validating admission policies 使用 Common Expression Language(CEL)來宣告 policy 的驗證規則。Validating admission policies 具有高度的可配置性,使 policy 撰寫者能夠定義可參數化並依照叢集管理員需求套用到特定資源的 policies。

Validating admission policies 用以取代 validating admission webhooks。

構成一個 VAP 策略需要哪些資源

一個策略 (policy) 通常由三種資源組成:

  • ValidatingAdmissionPolicy 描述了一個策略的抽象邏輯(可以想成:「這個策略確保某個特定的 label 被設定為一個特定的值」)。
  • 一個參數資源 (parameter resource) 提供資訊給 ValidatingAdmissionPolicy,使其成為一個具體的陳述(可以想成:「owner 這個 label 的值必須以 .company.com 結尾」)。一個原生型別(例如 ConfigMapCRD)定義了參數資源的結構 (schema)。ValidatingAdmissionPolicy 物件會指明它們期望使用哪種 Kind 作為其參數資源。
  • ValidatingAdmissionPolicyBinding 將上述的資源連結在一起,並定義其作用範圍。如果您只想要求 Pods 必須設定 owner 這個 label,那麼 binding 就是用來指定此限制的地方。

一個策略至少必須定義一個 ValidatingAdmissionPolicy 和一個對應的 ValidatingAdmissionPolicyBinding 才會生效。

如果一個 ValidatingAdmissionPolicy 不需要透過參數來設定,只要將其 spec.paramKind 欄位留空不指定即可。

Validating Admission Policy 快速開始

建立 ValidatingAdmissionPolicy

mkdir ~/validatingadmissionpolicy/; cd ~/validatingadmissionpolicy/
nano basic-example-policy.yaml

內容如下 :

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: "demo-policy.example.com"
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:   ["apps"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["deployments"]
  validations:
    - expression: "object.spec.replicas <= 5"

:::spoiler YAML 欄位詳解 📝

  • apiVersion: admissionregistration.k8s.io/v1
    • 這指定了該物件所使用的 Kubernetes API 版本。admissionregistration.k8s.io/v1ValidatingAdmissionPolicy 目前穩定的 API 群組與版本。
  • kind: ValidatingAdmissionPolicy
    • 這表明我們要建立的資源種類是 ValidatingAdmissionPolicy
  • metadata:
    • name: "demo-policy.example.com"
      • 這是此策略物件的唯一名稱。使用類似網域名稱的格式是一種很好的實踐,可以避免命名衝突。
  • spec:
    • 這是定義策略核心行為的地方。
    • failurePolicy: Fail
      • 這個欄位決定了當驗證表達式 (expression) 執行失敗或回傳結果為 false 時該如何處理。
      • Fail (目前設定):表示請求將被拒絕。這是最常見的設定,用來強制執行策略。
      • Ignore:表示如果驗證失敗,將忽略此策略並放行該請求。
    • matchConstraints:
      • 這個區塊用來定義此策略適用於哪些 API 請求。只有符合這裡所有條件的請求才會觸發後續的驗證。
      • resourceRules:
        • apiGroups: ["apps"]:指定目標資源所屬的 API 群組。Deployments 隸屬於 apps 群組。
        • apiVersions: ["v1"]:指定目標資源的 API 版本。
        • operations: ["CREATE", "UPDATE"]: 指定此策略僅在建立更新資源時觸發。它不會在 DELETE 操作時觸發。
        • resources: ["deployments"]:明確指定此規則只針對 deployments 這種資源。
    • validations:
      • 這個區塊包含了實際的驗證邏輯。
      • expression: "object.spec.replicas <= 5"
        • 這是一段使用 Common Expression Language (CEL) 撰寫的表達式。
        • object:代表正在被驗證的物件本身(在此情境下就是那個 Deployment)。
        • object.spec.replicas:存取該 Deployment 物件的 spec 欄位下的 replicas 數量。
        • <= 5:檢查 replicas 的值是否小於或等於 5。
        • 如果此表達式回傳 true,請求通過驗證。如果回傳 false,則根據 failurePolicy 的設定(Fail)來拒絕請求。

總結與效果

當你將這個 YAML 檔案應用到你的 Kubernetes 叢集後:

  • 允許的操作:任何使用者試圖建立或更新一個 Deployment,只要其 .spec.replicas 的值小於或等於 5,操作都會成功。

    # 這個會成功
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment-ok
    spec:
      replicas: 3 # <= 5
      ...
  • 被阻擋的操作:如果有人試圖將 replicas 設定為 6 或更高,kubectl applykubectl create 指令將會立即失敗,並收到來自 API 伺服器的錯誤訊息,說明該操作違反了 demo-policy.example.com 這條策略。

    # 這個會失敗
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment-bad
    spec:
      replicas: 10 # > 5
      ...

:::

可以在 CEL Playground 中快速測試 CEL 表達式。