本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

Kubernetes 1.30:多 Webhook 和模組化授權變得更加容易

在 Kubernetes 1.30 中,我們(SIG Auth)將結構化授權配置(Structured Authorization Configuration)升級到 Beta 階段。

今天的文章是關於**授權**(Authorization):決定某人可以訪問什麼和不可以訪問什麼。可以檢視昨天的一篇文章,瞭解 Kubernetes v1.30 在**身份驗證**(Authentication,即確定誰在執行任務並檢查他們是否是其聲稱的身份)方面的新功能。

引言

Kubernetes 持續演進以滿足系統管理員和開發人員的複雜需求。確保叢集安全性和完整性的一個關鍵方面是 API 伺服器授權。直到最近,kube-apiserver 中的授權鏈配置還相當僵化,僅限於一組命令列標誌,並且在授權鏈中只允許一個 Webhook。這種方法雖然功能可用,但限制了叢集管理員定義複雜、細粒度授權策略所需的靈活性。最新的結構化授權配置功能(KEP-3221)旨在透過引入一種更結構化、更通用的方式來配置授權鏈,從而徹底改變這一方面,重點是啟用多個 Webhook 並提供顯式的控制機制。

改進的必要性

叢集管理員長期以來一直希望能夠在 API 伺服器處理鏈中指定多個授權 Webhook,並能控制每個 Webhook 的詳細行為,如超時和失敗策略。這種需求源於建立分層安全策略的願望,其中請求可以按特定順序根據多個標準或規則集進行驗證。以前的限制也使得動態配置授權鏈變得困難,無法有效地管理複雜的授權場景。

結構化授權配置功能透過引入一種配置檔案格式來配置 Kubernetes API 伺服器授權鏈,從而解決了這些限制。這種格式允許在授權鏈中指定多個 Webhook(所有其他授權型別最多指定一次)。每個 Webhook 授權器都有明確定義的引數,包括超時設定、失敗策略以及使用 CEL 規則的呼叫條件,以便在請求被分派到 Webhook 之前進行預過濾,幫助你防止不必要的呼叫。該配置還支援自動重新載入,確保更改可以動態應用,而無需重新啟動 kube-apiserver。此功能不僅解決了當前的限制,還為更有效地保護和管理 Kubernetes 叢集開闢了新的可能性。

配置示例

以下是一個結構化授權配置示例,並附有所有欄位、其預設值和可能值的說明。

apiVersion: apiserver.config.k8s.io/v1beta1
kind: AuthorizationConfiguration
authorizers:
  - type: Webhook
    # Name used to describe the authorizer
    # This is explicitly used in monitoring machinery for metrics
    # Note:
    #   - Validation for this field is similar to how K8s labels are validated today.
    # Required, with no default
    name: webhook
    webhook:
      # The duration to cache 'authorized' responses from the webhook
      # authorizer.
      # Same as setting `--authorization-webhook-cache-authorized-ttl` flag
      # Default: 5m0s
      authorizedTTL: 30s
      # The duration to cache 'unauthorized' responses from the webhook
      # authorizer.
      # Same as setting `--authorization-webhook-cache-unauthorized-ttl` flag
      # Default: 30s
      unauthorizedTTL: 30s
      # Timeout for the webhook request
      # Maximum allowed is 30s.
      # Required, with no default.
      timeout: 3s
      # The API version of the authorization.k8s.io SubjectAccessReview to
      # send to and expect from the webhook.
      # Same as setting `--authorization-webhook-version` flag
      # Required, with no default
      # Valid values: v1beta1, v1
      subjectAccessReviewVersion: v1
      # MatchConditionSubjectAccessReviewVersion specifies the SubjectAccessReview
      # version the CEL expressions are evaluated against
      # Valid values: v1
      # Required, no default value
      matchConditionSubjectAccessReviewVersion: v1
      # Controls the authorization decision when a webhook request fails to
      # complete or returns a malformed response or errors evaluating
      # matchConditions.
      # Valid values:
      #   - NoOpinion: continue to subsequent authorizers to see if one of
      #     them allows the request
      #   - Deny: reject the request without consulting subsequent authorizers
      # Required, with no default.
      failurePolicy: Deny
      connectionInfo:
        # Controls how the webhook should communicate with the server.
        # Valid values:
        # - KubeConfigFile: use the file specified in kubeConfigFile to locate the
        #   server.
        # - InClusterConfig: use the in-cluster configuration to call the
        #   SubjectAccessReview API hosted by kube-apiserver. This mode is not
        #   allowed for kube-apiserver.
        type: KubeConfigFile
        # Path to KubeConfigFile for connection info
        # Required, if connectionInfo.Type is KubeConfigFile
        kubeConfigFile: /kube-system-authz-webhook.yaml
        # matchConditions is a list of conditions that must be met for a request to be sent to this
        # webhook. An empty list of matchConditions matches all requests.
        # There are a maximum of 64 match conditions allowed.
        #
        # The exact matching logic is (in order):
        #   1. If at least one matchCondition evaluates to FALSE, then the webhook is skipped.
        #   2. If ALL matchConditions evaluate to TRUE, then the webhook is called.
        #   3. If at least one matchCondition evaluates to an error (but none are FALSE):
        #      - If failurePolicy=Deny, then the webhook rejects the request
        #      - If failurePolicy=NoOpinion, then the error is ignored and the webhook is skipped
      matchConditions:
      # expression represents the expression which will be evaluated by CEL. Must evaluate to bool.
      # CEL expressions have access to the contents of the SubjectAccessReview in v1 version.
      # If version specified by subjectAccessReviewVersion in the request variable is v1beta1,
      # the contents would be converted to the v1 version before evaluating the CEL expression.
      #
      # Documentation on CEL: https://kubernetes.club.tw/docs/reference/using-api/cel/
      #
      # only send resource requests to the webhook
      - expression: has(request.resourceAttributes)
      # only intercept requests to kube-system
      - expression: request.resourceAttributes.namespace == 'kube-system'
      # don't intercept requests from kube-system service accounts
      - expression: "!('system:serviceaccounts:kube-system' in request.groups)"
  - type: Node
    name: node
  - type: RBAC
    name: rbac
  - type: Webhook
    name: in-cluster-authorizer
    webhook:
      authorizedTTL: 5m
      unauthorizedTTL: 30s
      timeout: 3s
      subjectAccessReviewVersion: v1
      failurePolicy: NoOpinion
      connectionInfo:
        type: InClusterConfig

以下配置示例說明了需要能夠指定具有不同設定、優先順序和失敗模式的多個 Webhook 的真實場景。

保護已安裝的 CRD

確保自定義資源定義(CRD)在叢集啟動時的可用性一直是一個關鍵需求。讓控制器協調這些 CRD 的一個障礙是為它們提供一種保護機制,這可以透過多個授權 Webhook 來實現。這在以前是不可能的,因為在 Kubernetes API 伺服器授權鏈中指定多個授權 Webhook 是不允許的。現在,藉助結構化授權配置功能,管理員可以指定多個 Webhook,提供了一種在 RBAC 不足時(特別是在拒絕“非系統”使用者對某些 CRD 的許可權時)的解決方案。

在此場景中假設以下情況

  • 已安裝“受保護的”CRD。
  • 它們只能由 `admin` 組中的使用者修改。
apiVersion: apiserver.config.k8s.io/v1beta1
kind: AuthorizationConfiguration
authorizers:
  - type: Webhook
    name: system-crd-protector
    webhook:
      unauthorizedTTL: 30s
      timeout: 3s
      subjectAccessReviewVersion: v1
      matchConditionSubjectAccessReviewVersion: v1
      failurePolicy: Deny
      connectionInfo:
        type: KubeConfigFile
        kubeConfigFile: /files/kube-system-authz-webhook.yaml
      matchConditions:
      # only send resource requests to the webhook
      - expression: has(request.resourceAttributes)
      # only intercept requests for CRDs
      - expression: request.resourceAttributes.resource.resource = "customresourcedefinitions"
      - expression: request.resourceAttributes.resource.group = ""
      # only intercept update, patch, delete, or deletecollection requests
      - expression: request.resourceAttributes.verb in ['update', 'patch', 'delete','deletecollection']
  - type: Node
  - type: RBAC

防止不必要的巢狀 Webhook

系統管理員希望在使用 Open Policy Agent 等框架將請求交給 Webhook 之前,對請求應用特定的驗證。過去,這需要在新增到授權鏈的 Webhook 內部執行巢狀的 Webhook 才能實現所需的效果。結構化授權配置功能簡化了此過程,提供了一個結構化的 API,可在需要時選擇性地觸發額外的 Webhook。它還使管理員能夠為每個 Webhook 設定不同的失敗策略,確保響應更加一致和可預測。

apiVersion: apiserver.config.k8s.io/v1beta1
kind: AuthorizationConfiguration
authorizers:
  - type: Webhook
    name: system-crd-protector
    webhook:
      unauthorizedTTL: 30s
      timeout: 3s
      subjectAccessReviewVersion: v1
      matchConditionSubjectAccessReviewVersion: v1
      failurePolicy: Deny
      connectionInfo:
        type: KubeConfigFile
        kubeConfigFile: /files/kube-system-authz-webhook.yaml
      matchConditions:
      # only send resource requests to the webhook
      - expression: has(request.resourceAttributes)
      # only intercept requests for CRDs
      - expression: request.resourceAttributes.resource.resource = "customresourcedefinitions"
      - expression: request.resourceAttributes.resource.group = ""
      # only intercept update, patch, delete, or deletecollection requests
      - expression: request.resourceAttributes.verb in ['update', 'patch', 'delete','deletecollection']
  - type: Node
  - type: RBAC
  - name: opa
    type: Webhook
    webhook:
      unauthorizedTTL: 30s
      timeout: 3s
      subjectAccessReviewVersion: v1
      matchConditionSubjectAccessReviewVersion: v1
      failurePolicy: Deny
      connectionInfo:
        type: KubeConfigFile
        kubeConfigFile: /files/opa-default-authz-webhook.yaml
      matchConditions:
      # only send resource requests to the webhook
      - expression: has(request.resourceAttributes)
      # only intercept requests to default namespace
      - expression: request.resourceAttributes.namespace == 'default'
      # don't intercept requests from default service accounts
      - expression: "!('system:serviceaccounts:default' in request.groups)"

接下來是什麼?

從 Kubernetes 1.30 開始,該功能處於 Beta 階段並預設啟用。對於 Kubernetes v1.31,我們希望該功能在獲得更多使用者反饋的同時保持在 Beta 階段。一旦準備好進入 GA(正式釋出)階段,該功能標誌將被移除,配置檔案版本將提升到 v1。

請在 Kubernetes 文件網站的結構化授權配置頁面上了解有關此功能的更多資訊。你還可以透過 KEP-3221 跟蹤未來 Kubernetes 版本中的進展。

行動號召

在這篇文章中,我們介紹了 Kubernetes v1.30 中結構化授權配置功能的好處,以及一些針對真實場景的配置示例。要使用此功能,你必須使用 `--authorization-config` 命令列引數指定授權配置檔案的路徑。從 Kubernetes 1.30 開始,該功能處於 Beta 階段並預設啟用。如果你想繼續使用命令列標誌而不是配置檔案,這些標誌將繼續按原樣工作。同時指定 `--authorization-config` 和 `--authorization-modes`/`--authorization-webhook-*` 是行不通的。你需要從你的 kube-apiserver 命令中刪除舊的標誌。

以下 kind 叢集配置在 API 伺服器上設定該命令引數,以從檔案(`authorization_config.yaml`)中載入 AuthorizationConfiguration,該檔案位於 `files` 資料夾中。任何需要的 kubeconfig 和證書檔案也可以放在 `files` 目錄中。

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
  StructuredAuthorizationConfiguration: true  # enabled by default in v1.30
kubeadmConfigPatches:
  - |
    kind: ClusterConfiguration
    metadata:
      name: config
    apiServer:
      extraArgs:
        authorization-config: "/files/authorization_config.yaml"
      extraVolumes:
      - name: files
        hostPath: "/files"
        mountPath: "/files"
        readOnly: true    
nodes:
- role: control-plane
  extraMounts:
  - hostPath: files
    containerPath: /files

我們很樂意聽到你對這個功能的反饋。特別是,我們希望從 Kubernetes 叢集管理員和授權 Webhook 實現者那裡獲得反饋,因為他們正在構建與這個新 API 的整合。請在 Kubernetes Slack 上的 #sig-auth-authorizers-dev 頻道上與我們聯絡。

如何參與

如果你有興趣幫助開發此功能、分享反饋或參與任何其他正在進行的 SIG Auth 專案,請在 Kubernetes Slack 上的 #sig-auth 頻道上與我們聯絡。

也歡迎你參加每兩週一次的 SIG Auth 會議,會議在每隔一個星期三舉行。

致謝

此功能由來自多家公司的貢獻者共同推動。我們衷心感謝所有為實現這一目標而貢獻時間和精力的每一個人。