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

Kubernetes 1.23:Pod 安全性進階至 Beta

隨著 Kubernetes v1.23 的釋出,Pod 安全性准入現已進入 Beta 階段。Pod 安全性是一個內建准入控制器,它根據一組預定義的Pod 安全性標準評估 Pod 規範,並確定是准入還是拒絕 Pod 執行。

Pod 安全性是PodSecurityPolicy的繼任者,PodSecurityPolicy 在 v1.21 版本中已棄用,並將於 Kubernetes v1.25 中移除。在本文中,我們將介紹 Pod 安全性的關鍵概念以及如何使用它。我們希望叢集管理員和開發人員都能使用這種新機制為其工作負載強制執行安全的預設設定。

為何選擇 Pod 安全性

Pod 安全性的總體目標是讓您能夠隔離工作負載。您可以執行一個執行不同工作負載的叢集,並且無需新增額外的第三方工具,即可實施控制,要求工作負載的 Pod 將其自身許可權限制在一個定義的邊界集合內。

Pod 安全性克服了 Kubernetes 現有但已棄用的 PodSecurityPolicy (PSP) 機制的關鍵缺點

  • 策略授權模型 — 部署控制器時面臨挑戰。
  • 切換風險 — 缺乏幹執行/審計功能使得啟用 PodSecurityPolicy 變得困難。
  • 不一致且無邊界的 API — 龐大的配置表面和不斷演變的約束導致 API 複雜且令人困惑。

PSP 的缺點使得其使用非常困難,這促使社群重新評估是否能透過更好的實現來達到相同的目標。其中一個目標是提供開箱即用的解決方案來應用安全最佳實踐。Pod 安全性附帶預定義的 Pod 安全級別,叢集管理員可以配置這些級別以滿足所需的安全性態勢。

重要的是,Pod 安全性與已棄用的 PodSecurityPolicy 並非完全功能對等。具體來說,它不具備變異或更改 Kubernetes 資源以代表使用者自動修復策略違反的能力。此外,它不提供對 Pod 規範或您可能希望評估的任何其他 Kubernetes 資源中每個允許的欄位和值的細粒度控制。如果您需要更細粒度的策略控制,請檢視支援此類用例的其他專案。

Pod 安全性還遵循 Kubernetes 宣告式物件管理的最佳實踐,即拒絕違反策略的資源。這要求在部署到 Kubernetes 之前更新源儲存庫中的資源和工具。

Pod 安全性如何工作?

Pod 安全性是 Kubernetes v1.22 及更高版本中內建的准入控制器,但也可以作為獨立的Webhook執行。准入控制器透過在 Kubernetes API 伺服器將請求持久化到儲存之前攔截請求來發揮作用。它們可以准入拒絕請求。對於 Pod 安全性,Pod 規範將根據以 Pod 安全性標準形式配置的策略進行評估。這意味著 Pod 規範中的安全敏感欄位將只允許具有特定值。

配置 Pod 安全性

Pod 安全性標準

為了使用 Pod 安全性,我們首先需要了解Pod 安全性標準。這些標準定義了三種不同的策略級別,範圍從寬鬆到嚴格。這些級別如下:

  • privileged — 開放且不受限制
  • baseline — 涵蓋已知的特權升級,同時最大限度地減少限制
  • restricted — 高度受限,防範已知和未知的特權升級。可能會導致相容性問題

這些策略級別中的每一個都定義了 Pod 規範中受限制的欄位和允許的值。這些策略限制的一些欄位包括

  • spec.securityContext.sysctls
  • spec.hostNetwork
  • spec.volumes[*].hostPath
  • spec.containers[*].securityContext.privileged

策略級別透過對 Namespace 資源應用標籤來實施,從而實現細粒度的按名稱空間策略選擇。API 伺服器中的 AdmissionConfiguration 也可以配置為設定叢集範圍的預設級別和豁免。

策略模式

策略以特定模式應用。可以在同一個名稱空間上設定多個模式(具有不同的策略級別)。以下是模式列表:

  • enforce — 任何違反策略的 Pod 都將被拒絕
  • audit — 違規行為將作為註釋記錄在審計日誌中,但不會影響 Pod 是否被允許。
  • warn — 違規行為將向用戶傳送警告訊息,但不會影響 Pod 是否被允許。

除了模式之外,您還可以將策略固定到特定版本(例如 v1.22)。固定到特定版本允許行為保持一致,即使策略定義在未來的 Kubernetes 版本中發生變化。

動手演示

先決條件

部署 kind 叢集

kind create cluster --image kindest/node:v1.23.0

啟動可能需要一段時間,啟動後節點準備就緒可能還需要一分鐘左右。

kubectl cluster-info --context kind-kind

等待節點狀態變為就緒。

kubectl get nodes

輸出類似於此

NAME                 STATUS   ROLES                  AGE   VERSION
kind-control-plane   Ready    control-plane,master   54m   v1.23.0

確認 Pod 安全性已啟用

確認 API 預設啟用外掛的最佳方法是檢查 Kubernetes API 容器的幫助引數。

kubectl -n kube-system exec kube-apiserver-kind-control-plane -it -- kube-apiserver -h | grep "default enabled ones"

輸出類似於此

...
      --enable-admission-plugins strings
admission plugins that should be enabled in addition
to default enabled ones (NamespaceLifecycle, LimitRanger,
ServiceAccount, TaintNodesByCondition, PodSecurity, Priority,
DefaultTolerationSeconds, DefaultStorageClass,
StorageObjectInUseProtection, PersistentVolumeClaimResize,
RuntimeClass, CertificateApproval, CertificateSigning,
CertificateSubjectRestriction, DefaultIngressClass,
MutatingAdmissionWebhook, ValidatingAdmissionWebhook,
ResourceQuota).
...

PodSecurity 列在預設啟用的准入外掛組中。

如果使用雲提供商,或者如果無法訪問 API 伺服器,最好的檢查方法是執行一個快速端到端測試

kubectl create namespace verify-pod-security
kubectl label namespace verify-pod-security pod-security.kubernetes.io/enforce=restricted
# The following command does NOT create a workload (--dry-run=server)
kubectl -n verify-pod-security run test --dry-run=server --image=busybox --privileged
kubectl delete namespace verify-pod-security

輸出類似於此

Error from server (Forbidden): pods "test" is forbidden: violates PodSecurity "restricted:latest": privileged (container "test" must not set securityContext.privileged=true), allowPrivilegeEscalation != false (container "test" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "test" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "test" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "test" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")

配置 Pod 安全性

策略透過標籤應用於名稱空間。這些標籤如下:

  • pod-security.kubernetes.io/<MODE>: <LEVEL> (啟用 pod 安全性所必需)
  • pod-security.kubernetes.io/<MODE>-version: <VERSION> (可選,預設為最新)

可以為每個強制模式提供特定版本。該版本將策略固定到隨 Kubernetes 版本釋出的版本。固定到特定 Kubernetes 版本可以實現確定性的策略行為,同時允許未來 Pod 安全性標準的靈活更新。可能的 enforceauditwarn

何時使用 warn

warn 的典型用途是為未來您想要強制執行不同策略的更改做準備。最常見的兩種情況是

  • 以相同級別但不同版本warn(例如,將enforce固定到 restricted+v1.23,將warn設定為 restricted+latest
  • 以更嚴格的級別warn(例如,enforce baseline,warn restricted)

不建議將 warn 用於與 enforce 完全相同的策略級別+版本。在准入序列中,如果 enforce 失敗,則整個序列在評估 warn 之前失敗。

首先,如果之前未建立,請建立一個名為 verify-pod-security 的名稱空間。對於演示,在標記時使用 --overwrite 以允許將單個名稱空間用於多個示例。

kubectl create namespace verify-pod-security

部署演示工作負載

每個工作負載都代表更高安全級別,這些級別無法透過其後的配置檔案。

對於以下示例,busybox 容器執行 sleep 命令 100 萬秒(約 11 天)或直到被刪除。Pod 安全性不關心您選擇哪個容器映象,而更關心 Pod 級別的設定及其對安全性的影響。

特權級別和工作負載

對於特權 Pod,使用特權策略。這允許容器內的程序獲取新程序(也稱為“特權升級”),如果不受信任,可能會很危險。

首先,我們為測試應用受限的 Pod 安全級別。

# enforces a "restricted" security policy and audits on restricted
kubectl label --overwrite ns verify-pod-security \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/audit=restricted

接下來,嘗試在該名稱空間中部署一個特權工作負載。

cat <<EOF | kubectl -n verify-pod-security apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox-privileged
spec:
  containers:
  - name: busybox
    image: busybox
    args:
    - sleep
    - "1000000"
    securityContext:
      allowPrivilegeEscalation: true
EOF

輸出類似於此

Error from server (Forbidden): error when creating "STDIN": pods "busybox-privileged" is forbidden: violates PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "busybox" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "busybox" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "busybox" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "busybox" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")

現在讓我們應用特權 Pod 安全級別並再試一次。

# enforces a "privileged" security policy and warns / audits on baseline
kubectl label --overwrite ns verify-pod-security \
  pod-security.kubernetes.io/enforce=privileged \
  pod-security.kubernetes.io/warn=baseline \
  pod-security.kubernetes.io/audit=baseline
cat <<EOF | kubectl -n verify-pod-security apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox-privileged
spec:
  containers:
  - name: busybox
    image: busybox
    args:
    - sleep
    - "1000000"
    securityContext:
      allowPrivilegeEscalation: true
EOF

輸出類似於此

pod/busybox-privileged created

我們可以執行 kubectl -n verify-pod-security get pods 來驗證它是否正在執行。使用以下命令清理:

kubectl -n verify-pod-security delete pod busybox-privileged

基線級別和工作負載

基線策略演示了合理的預設值,同時防止了常見的容器漏洞利用。

讓我們回到受限的 Pod 安全級別進行快速測試。

# enforces a "restricted" security policy and audits on restricted
kubectl label --overwrite ns verify-pod-security \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/audit=restricted

應用工作負載。

cat <<EOF | kubectl -n verify-pod-security apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox-baseline
spec:
  containers:
  - name: busybox
    image: busybox
    args:
    - sleep
    - "1000000"
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        add:
          - NET_BIND_SERVICE
          - CHOWN
EOF

輸出類似於此

Error from server (Forbidden): error when creating "STDIN": pods "busybox-baseline" is forbidden: violates PodSecurity "restricted:latest": unrestricted capabilities (container "busybox" must set securityContext.capabilities.drop=["ALL"]; container "busybox" must not include "CHOWN" in securityContext.capabilities.add), runAsNonRoot != true (pod or container "busybox" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "busybox" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")

讓我們再次應用基線 Pod 安全級別並重試。

# enforces a "baseline" security policy and warns / audits on restricted
kubectl label --overwrite ns verify-pod-security \
  pod-security.kubernetes.io/enforce=baseline \
  pod-security.kubernetes.io/warn=restricted \
  pod-security.kubernetes.io/audit=restricted
cat <<EOF | kubectl -n verify-pod-security apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox-baseline
spec:
  containers:
  - name: busybox
    image: busybox
    args:
    - sleep
    - "1000000"
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        add:
          - NET_BIND_SERVICE
          - CHOWN
EOF

輸出類似於以下內容。請注意,警告與上述測試中的錯誤訊息匹配,但 Pod 仍然成功建立。

Warning: would violate PodSecurity "restricted:latest": unrestricted capabilities (container "busybox" must set securityContext.capabilities.drop=["ALL"]; container "busybox" must not include "CHOWN" in securityContext.capabilities.add), runAsNonRoot != true (pod or container "busybox" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "busybox" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")
pod/busybox-baseline created

請記住,我們根據受限配置檔案將 verify-pod-security 名稱空間設定為 warn。我們可以執行 kubectl -n verify-pod-security get pods 來驗證它是否正在執行。使用以下命令進行清理:

kubectl -n verify-pod-security delete pod busybox-baseline

受限級別和工作負載

受限策略要求拒絕所有特權引數。它是最安全的,但權衡是複雜性。受限策略僅允許容器新增 NET_BIND_SERVICE 功能。

雖然我們已經測試了將受限作為阻止功能,但讓我們嘗試執行一個符合所有條件的功能。

首先,我們需要重新應用受限配置檔案,這是最後一次。

# enforces a "restricted" security policy and audits on restricted
kubectl label --overwrite ns verify-pod-security \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/audit=restricted
cat <<EOF | kubectl -n verify-pod-security apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox-restricted
spec:
  containers:
  - name: busybox
    image: busybox
    args:
    - sleep
    - "1000000"
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        add:
          - NET_BIND_SERVICE
EOF

輸出類似於此

Error from server (Forbidden): error when creating "STDIN": pods "busybox-restricted" is forbidden: violates PodSecurity "restricted:latest": unrestricted capabilities (container "busybox" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "busybox" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "busybox" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")

這是因為受限配置檔案明確要求將某些值設定為最安全的引數。

透過要求明確的值,清單變得更具宣告性,並且您的整個安全模型可以向左移動。透過 restricted 強制級別,公司可以根據允許的清單審計其叢集的合規性。

讓我們修復每個警告,生成以下檔案

cat <<EOF | kubectl -n verify-pod-security apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox-restricted
spec:
  containers:
  - name: busybox
    image: busybox
    args:
    - sleep
    - "1000000"
    securityContext:
      seccompProfile:
        type: RuntimeDefault
      runAsNonRoot: true
      allowPrivilegeEscalation: false
      capabilities:
        drop:
          - ALL
        add:
          - NET_BIND_SERVICE
EOF

輸出類似於此

pod/busybox-restricted created

執行 kubectl -n verify-pod-security get pods 來驗證它是否正在執行。輸出類似於此

NAME               READY   STATUS                       RESTARTS   AGE
busybox-restricted   0/1     CreateContainerConfigError   0          2m26s

讓我們透過 kubectl -n verify-pod-security describe pod busybox-restricted 找出容器未啟動的原因。輸出類似於此:

Events:
  Type     Reason     Age                    From               Message
  ----     ------     ----                   ----               -------
  Warning  Failed     2m29s (x8 over 3m55s)  kubelet            Error: container has runAsNonRoot and image will run as root (pod: "busybox-restricted_verify-pod-security(a4c6a62d-2166-41a9-b288-20df17cf5c90)", container: busybox)

要解決此問題,請將有效 UID (runAsUser) 設定為非零(root)值,或使用 nobody UID (65534)。

# delete the original pod
kubectl -n verify-pod-security delete pod busybox-restricted

# create the pod again with new runAsUser
cat <<EOF | kubectl -n verify-pod-security apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox-restricted
spec:
  securityContext:
    runAsUser: 65534
  containers:
  - name: busybox
    image: busybox
    args:
    - sleep
    - "1000000"
    securityContext:
      seccompProfile:
        type: RuntimeDefault
      runAsNonRoot: true
      allowPrivilegeEscalation: false
      capabilities:
        drop:
          - ALL
        add:
          - NET_BIND_SERVICE
EOF

執行 kubectl -n verify-pod-security get pods 來驗證它是否正在執行。輸出類似於此

NAME                 READY   STATUS    RESTARTS   AGE
busybox-restricted   1/1     Running   0          25s

使用以下命令清除演示(受限 Pod 和名稱空間):

kubectl delete namespace verify-pod-security

此時,如果您想深入瞭解 Linux 許可權或某個容器允許哪些許可權,可以執行到控制平面並使用 containerdcrictl inspect 進行操作。

# if using docker, shell into the control plane
docker exec -it kind-control-plane bash

# list running containers
crictl ps

# inspect each one by container ID
crictl inspect <CONTAINER ID>

應用叢集範圍策略

除了透過標籤將策略應用於名稱空間之外,您還可以使用 AdmissionConfiguration 資源配置叢集範圍的策略和豁免。

使用此資源,策略定義預設在叢集範圍內應用,並且透過名稱空間標籤應用的任何策略都將優先。

對於 AdmissionConfiguration 配置檔案,沒有執行時可配置的 API,因此叢集管理員需要在 API 伺服器上透過 --admission-control-config-file 標誌指定檔案的路徑。

在以下資源中,我們正在強制執行基線策略,並對基線策略進行警告和審計。我們還將 kube-system 名稱空間從該策略中豁免。

不建議在安裝後更改控制平面/叢集,因此讓我們構建一個新叢集,其中所有名稱空間都具有預設策略。

首先,刪除當前叢集。

kind delete cluster

建立一個 Pod 安全性配置,它強制審計基線策略,同時使用受限配置檔案警告終端使用者。

cat <<EOF > pod-security.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: PodSecurity
  configuration:
    apiVersion: pod-security.admission.config.k8s.io/v1beta1
    kind: PodSecurityConfiguration
    defaults:
      enforce: "baseline"
      enforce-version: "latest"
      audit: "baseline"
      audit-version: "latest"
      warn: "restricted"
      warn-version: "latest"
    exemptions:
      # Array of authenticated usernames to exempt.
      usernames: []
      # Array of runtime class names to exempt.
      runtimeClasses: []
      # Array of namespaces to exempt.
      namespaces: [kube-system]
EOF

有關其他選項,請查閱官方的標準准入控制器文件。

我們現在有了一個預設的基線策略。接下來,將其傳遞給 kind 配置,以啟用 --admission-control-config-file API 伺服器引數並傳遞策略檔案。要將檔案傳遞給 kind 叢集,請使用配置檔案傳遞額外的設定指令。Kind 使用 kubeadm 來配置叢集,並且配置檔案能夠傳遞 kubeadmConfigPatches 以進行進一步自定義。在我們的示例中,本地檔案作為 /etc/kubernetes/policies/pod-security.yaml 掛載到控制平面節點中,然後掛載到 apiServer 容器中。我們還傳遞了指向策略位置的 --admission-control-config-file 引數。

cat <<EOF > kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  kubeadmConfigPatches:
  - |
    kind: ClusterConfiguration
    apiServer:
        # enable admission-control-config flag on the API server
        extraArgs:
          admission-control-config-file: /etc/kubernetes/policies/pod-security.yaml
        # mount new file / directories on the control plane
        extraVolumes:
          - name: policies
            hostPath: /etc/kubernetes/policies
            mountPath: /etc/kubernetes/policies
            readOnly: true
            pathType: "DirectoryOrCreate"
  # mount the local file on the control plane
  extraMounts:
  - hostPath: ./pod-security.yaml
    containerPath: /etc/kubernetes/policies/pod-security.yaml
    readOnly: true
EOF

使用上面定義的 kind 配置檔案建立新叢集。

kind create cluster --image kindest/node:v1.23.0 --config kind-config.yaml

讓我們看看預設名稱空間。

kubectl describe namespace default

輸出類似於此

Name:         default
Labels:       kubernetes.io/metadata.name=default
Annotations:  <none>
Status:       Active

No resource quota.

No LimitRange resource.

讓我們建立一個新的名稱空間,看看標籤是否也適用於那裡。

kubectl create namespace test-defaults
kubectl describe namespace test-defaults

相同。

Name:         test-defaults
Labels:       kubernetes.io/metadata.name=test-defaults
Annotations:  <none>
Status:       Active

No resource quota.

No LimitRange resource.

是否可以部署特權工作負載?

cat <<EOF | kubectl -n test-defaults apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox-privileged
spec:
  containers:
  - name: busybox
    image: busybox
    args:
    - sleep
    - "1000000"
    securityContext:
      allowPrivilegeEscalation: true
EOF

嗯……是的。至少預設的warn級別正在工作。

Warning: would violate PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "busybox" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "busybox" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "busybox" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "busybox" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")
pod/busybox-privileged created

讓我們使用 kubectl -n test-defaults delete pod/busybox-privileged 刪除 Pod。

我的配置是否正常工作?

# if using docker, shell into the control plane
docker exec -it kind-control-plane bash

# cat out the file we mounted
cat /etc/kubernetes/policies/pod-security.yaml

# check the api server logs
cat /var/log/containers/kube-apiserver*.log 

# check the api server config
cat /etc/kubernetes/manifests/kube-apiserver.yaml 

更新:基線策略允許 allowPrivilegeEscalation。雖然我無法看到 Pod 安全性的預設強制級別,但它們確實存在。讓我們嘗試提供一個透過請求 hostNetwork 訪問來違反基線的清單。

# delete the original pod
kubectl -n test-defaults delete pod busybox-privileged

cat <<EOF | kubectl -n test-defaults apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox-privileged
spec:
  containers:
  - name: busybox
    image: busybox
    args:
    - sleep
    - "1000000"
  hostNetwork: true
EOF

輸出類似於此

Error from server (Forbidden): error when creating "STDIN": pods "busybox-privileged" is forbidden: violates PodSecurity "baseline:latest": host namespaces (hostNetwork=true)

成功了!!!🎉🎉🎉

後來我發現,另一種檢查事物是否按預期執行的方法是檢查原始 API 伺服器指標端點。

執行以下命令

kubectl get --raw /metrics | grep pod_security_evaluations_total

輸出類似於此

# HELP pod_security_evaluations_total [ALPHA] Number of policy evaluations that occurred, not counting ignored or exempt requests.
# TYPE pod_security_evaluations_total counter
pod_security_evaluations_total{decision="allow",mode="enforce",policy_level="baseline",policy_version="latest",request_operation="create",resource="pod",subresource=""} 2
pod_security_evaluations_total{decision="allow",mode="enforce",policy_level="privileged",policy_version="latest",request_operation="create",resource="pod",subresource=""} 0
pod_security_evaluations_total{decision="allow",mode="enforce",policy_level="privileged",policy_version="latest",request_operation="update",resource="pod",subresource=""} 0
pod_security_evaluations_total{decision="deny",mode="audit",policy_level="baseline",policy_version="latest",request_operation="create",resource="pod",subresource=""} 1
pod_security_evaluations_total{decision="deny",mode="enforce",policy_level="baseline",policy_version="latest",request_operation="create",resource="pod",subresource=""} 1
pod_security_evaluations_total{decision="deny",mode="warn",policy_level="restricted",policy_version="latest",request_operation="create",resource="controller",subresource=""} 2
pod_security_evaluations_total{decision="deny",mode="warn",policy_level="restricted",policy_version="latest",request_operation="create",resource="pod",subresource=""} 2

監控工具也可以攝取這些指標,用於報告、評估或測量趨勢。

清理

完成後,刪除 kind 叢集。

kind delete cluster

審計

審計是另一種跟蹤叢集中正在強制執行的策略的方式。要使用 kind 設定審計,請查閱啟用審計的官方文件。從版本 1.11開始,Kubernetes 審計日誌包含兩個註釋,指示請求是否已授權 (authorization.k8s.io/decision) 以及決策的原因 (authorization.k8s.io/reason)。審計事件可以流式傳輸到 Webhook 以進行監控、跟蹤或警報。

審計事件看起來類似於以下內容

{"authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":"","pod-security.kubernetes.io/audit":"allowPrivilegeEscalation != false (container \"busybox\" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container \"busybox\" must set securityContext.capabilities.drop=[\"ALL\"]), runAsNonRoot != true (pod or container \"busybox\" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container \"busybox\" must set securityContext.seccompProfile.type to \"RuntimeDefault\" or \"Localhost\")"}}

審計也是評估叢集當前 Pod 安全合規性的良好第一步。Kubernetes 增強提案 (KEP) 暗示未來 baseline 可能成為未標記名稱空間的預設設定

針對 Pod 安全事件調整的 audit-policy.yaml 配置示例

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: RequestResponse
  resources:
    - group: "" # core API group
      resources: ["pods", "pods/ephemeralcontainers", "podtemplates", "replicationcontrollers"]
    - group: "apps"
      resources: ["daemonsets", "deployments", "replicasets", "statefulsets"]
    - group: "batch"
      resources: ["cronjobs", "jobs"]
  verbs: ["create", "update"]
  omitStages:
    - "RequestReceived"
    - "ResponseStarted"
    - "Panic"

啟用審計後,如果使用 --audit-log-path,請檢視配置的本地檔案,如果使用 --audit-webhook-config-file,則檢視 Webhook 的目的地。

如果使用檔案(--audit-log-path),執行 cat /PATH/TO/API/AUDIT.log | grep "is forbidden:" 檢視所有被審計的被拒絕工作負載。

PSP 遷移

如果您已經在使用 PSP,SIG Auth 已建立指南並釋出了從 PSP 遷移的步驟

總結過程如下:

  • 更新所有現有 PSP 為非變異
  • warnaudit 模式應用 Pod 安全策略
  • 將 Pod 安全策略升級到 enforce 模式
  • --enable-admission-plugins 中移除 PodSecurityPolicy

SIG Auth 已經討論過提供一個工具來協助遷移的想法,該工具被列為“可選的未來擴充套件”且目前不在範圍之內。KEP 中有更多詳細資訊

總結

Pod 安全性是一個很有前途的新功能,它提供了一種開箱即用的方式,讓使用者可以提高其工作負載的安全態勢。與任何已成熟到 Beta 階段的新增強功能一樣,我們懇請您試用它,提供反饋,或透過提出 Github 問題或參加 SIG Auth 社群會議來分享您的經驗。我們希望 Pod 安全效能夠部署在每個叢集上,作為我們社群持續追求將 Kubernetes 安全性作為優先事項的一部分。

有關如何透過 Pod 安全性准入功能啟用“基線”Pod 安全性標準的逐步指南,請參閱這些專門的教程,其中涵蓋了叢集級別和名稱空間級別所需的配置。

其他資源