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

Kubernetes 驗證性准入策略:一個實踐示例

准入控制是 Kubernetes 控制平面的重要組成部分,一些內部功能依賴於在 API 物件提交到伺服器時批准或更改該物件的能力。對於管理員來說,能夠定義關於哪些物件可以被准入到叢集中的業務邏輯或策略也很有用。為了更好地支援這一用例,Kubernetes 在 v1.7 中引入了外部准入控制

除了無數的自定義內部實現外,許多開源專案和商業解決方案也使用使用者指定的策略來實現准入控制器,包括 Kyverno 和 Open Policy Agent 的 Gatekeeper

雖然用於策略的准入控制器已得到採用,但其廣泛使用仍存在一些障礙。Webhook 基礎設施必須作為生產服務來維護,並承擔所有相關工作。准入控制 Webhook 的故障案例要麼是關閉的,從而降低叢集的可用性;要麼是開放的,從而使該功能在策略執行方面的作用失效。在處理例如為響應“無伺服器”環境中的網路請求而啟動的 Pod 時,網路跳轉和評估時間使得准入控制成為延遲的一個顯著組成部分。

驗證性准入策略和通用表示式語言

Kubernetes 的 1.26 版本引入了一個折衷的解決方案(處於 Alpha 階段)。驗證性准入策略是准入 Webhook 的一種宣告式、程序內替代方案。它們使用通用表示式語言(CEL)來宣告驗證規則。

CEL 是由 Google 針對安全和策略用例開發的,其基礎源於 Firebase 即時資料庫的經驗。其設計使其能夠安全地嵌入到應用程式中,並在微秒級執行,計算和記憶體影響有限。CRD 的驗證規則在 v1.23 中將 CEL 引入了 Kubernetes 生態系統,當時就有人指出,該語言將適用於更通用的准入控制驗證實現。

試用 CEL - 一個實踐示例

Kubescape 是一個 CNCF 專案,已成為使用者提高 Kubernetes 叢集安全狀況和驗證其合規性的最流行方式之一。它的控制項 — 針對 API 物件的測試組 — 是用 Rego 構建的,Rego 是 Open Policy Agent 的策略語言。

Rego 以其複雜性而聞名,這主要因為它是一種宣告式查詢語言(類似於 SQL)。它曾被考慮用於 Kubernetes,但它不提供與 CEL 相同的沙箱約束。

該專案的一個常見功能請求是能夠根據 Kubescape 的發現和輸出來實施策略。例如,在掃描 Pod 中是否存在已知的雲憑證檔案路徑後,使用者希望能夠強制執行策略,完全禁止這些 Pod 被准入。Kubescape 團隊認為這是一個絕佳的機會,可以嘗試將我們現有的控制項移植到 CEL,並將其作為準入策略來應用。

展示策略

我們沒花多長時間就轉換了許多控制項,並構建了一個驗證性准入策略庫。讓我們來看一個例子。

Kubescape 的控制項 C-0017 涵蓋了容器需要具有不可變(只讀)根檔案系統的要求。根據 NSA Kubernetes 強化指南,這是一種最佳實踐,但目前並不作為任何Pod 安全標準的一部分要求。

以下是我們如何在 CEL 中實現它

apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
  name: "kubescape-c-0017-deny-resources-with-mutable-container-filesystem"
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:   [""]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["pods"]
    - apiGroups:   ["apps"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["deployments","replicasets","daemonsets","statefulsets"]
    - apiGroups:   ["batch"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["jobs","cronjobs"]
  validations:
    - expression: "object.kind != 'Pod' || object.spec.containers.all(container, has(container.securityContext) && has(container.securityContext.readOnlyRootFilesystem) &&  container.securityContext.readOnlyRootFilesystem == true)"
      message: "Pods having containers with mutable filesystem not allowed! (see more at https://hub.armosec.io/docs/c-0017)"
    - expression: "['Deployment','ReplicaSet','DaemonSet','StatefulSet','Job'].all(kind, object.kind != kind) || object.spec.template.spec.containers.all(container, has(container.securityContext) && has(container.securityContext.readOnlyRootFilesystem) &&  container.securityContext.readOnlyRootFilesystem == true)"
      message: "Workloads having containers with mutable filesystem not allowed! (see more at https://hub.armosec.io/docs/c-0017)"
    - expression: "object.kind != 'CronJob' || object.spec.jobTemplate.spec.template.spec.containers.all(container, has(container.securityContext) && has(container.securityContext.readOnlyRootFilesystem) &&  container.securityContext.readOnlyRootFilesystem == true)"
      message: "CronJob having containers with mutable filesystem not allowed! (see more at https://hub.armosec.io/docs/c-0017)"

為三種可能的 API 組提供了匹配約束:用於 Pod 的 core/v1 組,用於工作負載控制器的 apps/v1 組,以及用於作業控制器的 batch/v1 組。

validations 包含了物件的 CEL 規則。這裡有三種不同的表示式,以適應 Pod spec 可能位於物件根部(裸 Pod)、template 下(工作負載控制器或 Job)或 jobTemplate 下(CronJob)的情況。

如果任何 specreadOnlyRootFilesystem 沒有設定為 true,該物件將不會被准入。

在您的叢集中使用 CEL 庫

策略以 Kubernetes 物件的形式提供,然後透過選擇器繫結到某些資源。

Minikube 是安裝和配置 Kubernetes 叢集以進行測試的一種快速簡便的方法。要安裝啟用了 ValidatingAdmissionPolicy 功能門控的 Kubernetes v1.26:

minikube start --kubernetes-version=1.26.1 --extra-config=apiserver.runtime-config=admissionregistration.k8s.io/v1alpha1  --feature-gates='ValidatingAdmissionPolicy=true'

要在您的叢集中安裝這些策略:

# Install configuration CRD
kubectl apply -f https://github.com/kubescape/cel-admission-library/releases/latest/download/policy-configuration-definition.yaml
# Install basic configuration
kubectl apply -f https://github.com/kubescape/cel-admission-library/releases/latest/download/basic-control-configuration.yaml
# Install policies
kubectl apply -f https://github.com/kubescape/cel-admission-library/releases/latest/download/kubescape-validating-admission-policies.yaml

要將策略應用於物件,請建立一個 ValidatingAdmissionPolicyBinding 資源。讓我們將上述 Kubescape C-0017 控制項應用於任何帶有標籤 policy=enforced 的名稱空間:

# Create a binding
kubectl apply -f - <<EOT
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: c0017-binding
spec:
  policyName: kubescape-c-0017-deny-mutable-container-filesystem
  matchResources:
    namespaceSelector:
      matchLabels:
        policy: enforced
EOT

# Create a namespace for running the example
kubectl create namespace policy-example
kubectl label namespace policy-example 'policy=enforced'

現在,如果您嘗試建立一個沒有指定 readOnlyRootFilesystem 的物件,它將不會被建立。

# The next line should fail
kubectl -n policy-example run nginx --image=nginx --restart=Never

輸出顯示了我們的錯誤:

The pods "nginx" is invalid: : ValidatingAdmissionPolicy 'kubescape-c-0017-deny-mutable-container-filesystem' with binding 'c0017-binding' denied request: Pods having containers with mutable filesystem not allowed! (see more at https://hub.armosec.io/docs/c-0017)

配置

策略物件可以包含配置,這些配置在另一個物件中提供。許多 Kubescape 控制項都需要配置:需要哪些標籤、允許或拒絕哪些能力、允許從哪些註冊中心部署容器等。這些控制項的預設值在 ControlConfiguration 物件中定義。

要使用此配置物件,或您自己格式相同的物件,請將一個 paramRef.name 值新增到您的繫結物件中:

apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: c0001-binding
spec:
  policyName: kubescape-c-0001-deny-forbidden-container-registries
  paramRef:
    name: basic-control-configuration
  matchResources:
    namespaceSelector:
      matchLabels:
        policy: enforced

總結

在大多數情況下,將我們的控制項轉換為 CEL 是很簡單的。我們無法移植整個 Kubescape 庫,因為一些控制項檢查的是 Kubernetes 叢集之外的東西,還有一些需要准入請求物件中不可用的資料。總的來說,我們很高興能將這個庫貢獻給 Kubernetes 社群,並將繼續為 Kubescape 和 Kubernetes 使用者開發它。我們希望它能變得有用,無論是您自己使用,還是作為您編寫自己策略的示例。

至於驗證性准入策略功能本身,我們非常高興看到這個原生功能被引入到 Kubernetes 中。我們期待著它進入 Beta 階段,然後是 GA,希望能在年底前實現。需要注意的是,該功能目前處於 Alpha 階段,這意味著現在是在 Minikube 等環境中試用並進行測試的絕佳機會。然而,它尚未被認為是生產就緒且穩定的,並且在大多數託管的 Kubernetes 環境中不會啟用。在底層功能變得穩定之前,我們不會建議 Kubescape 使用者在生產環境中使用這些策略。請關注KEP,當然還有本部落格,以獲取最終的釋出公告。