前言
隨著 Kubernetes 在企業環境中的廣泛應用,Pod 安全性成為叢集管理的重要議題。Kubernetes 1.25 版本正式移除了 Pod Security Policies (PSP),取而代之的是更為簡潔且易於管理的 Pod Security Standards (PSS) 與 Pod Security Admission (PSA) 控制器。本文將深入探討這套新的安全機制,協助您建立更安全的 Kubernetes 環境。
Pod Security Standards 概述
Pod Security Standards (PSS) 定義了三個不同的安全等級,用於規範 Pod 的安全配置。這些標準涵蓋了 Pod 規格中的安全敏感欄位,提供了一套清晰且可預測的安全政策框架。
為什麼需要 Pod Security Standards?
- 簡化安全管理:相較於 PSP 的複雜配置,PSS 提供了預定義的安全等級
- 降低學習曲線:管理員只需選擇適當的安全等級即可
- 內建於 Kubernetes:作為核心功能,無需額外安裝元件
- 漸進式導入:支援 warn、audit、enforce 三種模式
三個安全等級
1. Privileged(特權模式)
這是最寬鬆的安全等級,幾乎不限制任何安全配置。適用於需要系統層級存取權限的工作負載。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| # Privileged 等級允許的配置範例
apiVersion: v1
kind: Pod
metadata:
name: privileged-pod
spec:
hostNetwork: true
hostPID: true
hostIPC: true
containers:
- name: privileged-container
image: nginx:latest
securityContext:
privileged: true
runAsUser: 0
capabilities:
add: ["ALL"]
|
適用場景:
- 系統 DaemonSet(如 CNI plugins、日誌收集器)
- 節點監控代理
- 需要存取主機資源的特殊工作負載
2. Baseline(基準模式)
這是中等安全等級,阻止已知的權限提升,同時保持足夠的彈性以運行大多數應用程式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # Baseline 等級的合規 Pod 範例
apiVersion: v1
kind: Pod
metadata:
name: baseline-pod
spec:
containers:
- name: app
image: nginx:latest
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
add: ["NET_BIND_SERVICE"]
ports:
- containerPort: 80
|
Baseline 等級限制:
- 禁止
hostNetwork、hostPID、hostIPC - 禁止
privileged 容器 - 限制
hostPath volumes 類型 - 限制可新增的 Linux capabilities
- 禁止
procMount 設定為 Unmasked
3. Restricted(受限模式)
這是最嚴格的安全等級,遵循當前 Pod 安全強化的最佳實務。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| # Restricted 等級的合規 Pod 範例
apiVersion: v1
kind: Pod
metadata:
name: restricted-pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: nginx:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
|
Restricted 等級額外要求:
- 必須以非 root 身份運行 (
runAsNonRoot: true) - 必須明確丟棄所有 capabilities
- 禁止權限提升 (
allowPrivilegeEscalation: false) - 必須設定 Seccomp profile
- 限制可使用的 volume 類型
Pod Security Admission 控制器
Pod Security Admission (PSA) 是 Kubernetes 內建的 admission controller,負責在 Pod 建立時驗證其是否符合指定的安全標準。
三種執行模式
| 模式 | 說明 | 行為 |
|---|
enforce | 強制執行 | 拒絕違規的 Pod |
audit | 稽核模式 | 記錄違規但允許建立 |
warn | 警告模式 | 顯示警告但允許建立 |
啟用 PSA 控制器
在 Kubernetes 1.23+ 版本中,PSA 預設啟用。若需手動配置,可在 API server 中設定:
1
2
3
4
5
| # 確認 PSA 已啟用
kubectl api-versions | grep admission
# 查看 admission controller 配置
cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep -A5 enable-admission-plugins
|
PSA 配置檔案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| # /etc/kubernetes/psa/admission-configuration.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: PodSecurity
configuration:
apiVersion: pod-security.admission.config.k8s.io/v1
kind: PodSecurityConfiguration
defaults:
enforce: "baseline"
enforce-version: "latest"
audit: "restricted"
audit-version: "latest"
warn: "restricted"
warn-version: "latest"
exemptions:
usernames: []
runtimeClasses: []
namespaces: ["kube-system"]
|
Namespace 層級設定
PSS 透過 Namespace labels 進行配置,提供細緻的安全控制。
設定 Namespace 安全等級
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| # 建立具有安全設定的 Namespace
kubectl create namespace secure-app
# 設定 enforce 模式為 restricted
kubectl label namespace secure-app \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=v1.28
# 設定 warn 模式
kubectl label namespace secure-app \
pod-security.kubernetes.io/warn=restricted \
pod-security.kubernetes.io/warn-version=latest
# 設定 audit 模式
kubectl label namespace secure-app \
pod-security.kubernetes.io/audit=restricted \
pod-security.kubernetes.io/audit-version=latest
|
Namespace 配置範例
1
2
3
4
5
6
7
8
9
10
11
| apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: v1.28
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: latest
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: latest
|
驗證 Namespace 設定
1
2
3
4
5
6
7
8
| # 檢視 Namespace 的安全標籤
kubectl get namespace secure-app -o yaml | grep pod-security
# 列出所有 Namespace 及其安全等級
kubectl get namespaces -L pod-security.kubernetes.io/enforce
# 測試 Pod 是否符合標準(dry-run)
kubectl apply --dry-run=server -f pod.yaml -n secure-app
|
從 PSP 遷移指南
遷移策略概述
- 評估現有 PSP:分析目前使用的 Pod Security Policies
- 對應安全等級:將 PSP 規則對應到 PSS 等級
- 漸進式導入:先使用 warn/audit 模式測試
- 逐步強制執行:確認無問題後切換至 enforce 模式
- 移除 PSP:完成遷移後停用 PSP
評估現有 PSP
1
2
3
4
5
6
7
8
| # 列出所有 PSP
kubectl get psp
# 查看 PSP 詳細配置
kubectl get psp <psp-name> -o yaml
# 分析哪些 Pod 使用了哪些 PSP
kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.metadata.annotations.kubernetes\.io/psp}{"\n"}{end}'
|
PSP 到 PSS 對應表
| PSP 設定 | Privileged | Baseline | Restricted |
|---|
privileged: true | 允許 | 禁止 | 禁止 |
hostNetwork: true | 允許 | 禁止 | 禁止 |
hostPID: true | 允許 | 禁止 | 禁止 |
runAsUser: MustRunAsNonRoot | 不要求 | 不要求 | 要求 |
allowPrivilegeEscalation: false | 不要求 | 不要求 | 要求 |
遷移腳本範例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| #!/bin/bash
# migrate-psp-to-pss.sh
# 為所有非系統 Namespace 設定 warn 模式
for ns in $(kubectl get namespaces -o jsonpath='{.items[*].metadata.name}'); do
if [[ ! "$ns" =~ ^kube- ]] && [[ "$ns" != "default" ]]; then
echo "Setting warn mode for namespace: $ns"
kubectl label namespace "$ns" \
pod-security.kubernetes.io/warn=baseline \
pod-security.kubernetes.io/audit=baseline \
--overwrite
fi
done
# 檢查是否有違規 Pod
echo "Checking for policy violations..."
kubectl get pods --all-namespaces -o wide
|
遷移驗證
1
2
3
4
5
6
7
8
| # 在 dry-run 模式下測試現有工作負載
kubectl label namespace test-ns \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=v1.28 \
--dry-run=server -o yaml
# 檢視 audit 日誌中的違規記錄
kubectl logs -n kube-system -l component=kube-apiserver | grep "pod-security"
|
政策豁免設定
某些工作負載(如系統元件)可能需要豁免安全限制。PSA 支援三種豁免類型。
豁免類型
- Usernames:特定使用者或服務帳號
- RuntimeClasses:特定 RuntimeClass
- Namespaces:特定 Namespace
叢集層級豁免配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| # admission-configuration.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: PodSecurity
configuration:
apiVersion: pod-security.admission.config.k8s.io/v1
kind: PodSecurityConfiguration
defaults:
enforce: "restricted"
enforce-version: "latest"
audit: "restricted"
audit-version: "latest"
warn: "restricted"
warn-version: "latest"
exemptions:
# 豁免特定使用者
usernames:
- system:serviceaccount:kube-system:calico-node
- system:serviceaccount:kube-system:fluentd
# 豁免特定 RuntimeClass
runtimeClasses:
- kata-runtime
- gvisor
# 豁免特定 Namespace
namespaces:
- kube-system
- kube-node-lease
- kube-public
- monitoring
|
服務帳號豁免範例
1
2
3
4
5
6
7
8
9
10
| # 為需要特權的服務帳號設定豁免
apiVersion: v1
kind: ServiceAccount
metadata:
name: privileged-sa
namespace: monitoring
---
# 在 PSA 配置中加入此服務帳號
# usernames:
# - system:serviceaccount:monitoring:privileged-sa
|
動態豁免策略
1
2
3
4
5
6
7
8
9
| # 使用 kubectl auth can-i 驗證權限
kubectl auth can-i create pods --as=system:serviceaccount:monitoring:privileged-sa
# 建立特權 Pod 測試豁免是否生效
kubectl run test-pod \
--image=nginx \
--overrides='{"spec":{"serviceAccountName":"privileged-sa"}}' \
-n monitoring \
--dry-run=server
|
監控與稽核
啟用 Audit Logging
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata
resources:
- group: ""
resources: ["pods"]
namespaces: ["*"]
verbs: ["create", "update", "patch"]
- level: RequestResponse
users: ["system:anonymous"]
resources:
- group: ""
resources: ["pods"]
|
設定 API Server 稽核
1
2
3
4
5
6
7
8
9
10
11
| # 在 kube-apiserver 中啟用稽核
# /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
containers:
- command:
- kube-apiserver
- --audit-policy-file=/etc/kubernetes/audit/audit-policy.yaml
- --audit-log-path=/var/log/kubernetes/audit/audit.log
- --audit-log-maxage=30
- --audit-log-maxbackup=10
- --audit-log-maxsize=100
|
使用 Prometheus 監控
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| # ServiceMonitor for PSA metrics
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: kube-apiserver
namespace: monitoring
spec:
endpoints:
- bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
interval: 30s
port: https
scheme: https
tlsConfig:
insecureSkipVerify: true
selector:
matchLabels:
component: apiserver
|
PSA 相關指標
1
2
3
4
5
6
| # 查詢 PSA 違規指標
kubectl get --raw /metrics | grep pod_security
# 常見指標:
# pod_security_evaluations_total - 評估總數
# pod_security_exemptions_total - 豁免總數
|
使用 Falco 進行執行時期監控
1
2
3
4
5
6
7
8
9
10
11
12
13
| # falco-rules.yaml
- rule: Pod Created in Privileged Mode
desc: Detect privileged pod creation
condition: >
kevt and
kcreate and
pod and
ka.req.pod.containers.privileged = true
output: >
Privileged pod created
(user=%ka.user.name pod=%ka.resp.name ns=%ka.target.namespace)
priority: WARNING
tags: [k8s, pod, privileged]
|
最佳實務與範例
1. 漸進式導入策略
1
2
3
4
5
6
7
8
9
10
11
| # 第一階段:開啟警告模式
kubectl label namespace production \
pod-security.kubernetes.io/warn=restricted
# 第二階段:開啟稽核模式
kubectl label namespace production \
pod-security.kubernetes.io/audit=restricted
# 第三階段:觀察一段時間後強制執行
kubectl label namespace production \
pod-security.kubernetes.io/enforce=restricted
|
2. 建立安全的 Deployment 範本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
| # secure-deployment-template.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-app
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: secure-app
template:
metadata:
labels:
app: secure-app
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10000
runAsGroup: 10000
fsGroup: 10000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
limits:
cpu: "500m"
memory: "256Mi"
requests:
cpu: "100m"
memory: "128Mi"
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /var/cache
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
serviceAccountName: secure-app-sa
automountServiceAccountToken: false
|
3. 使用 Kyverno 補充 PSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| # kyverno-policy.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-run-as-nonroot
spec:
validationFailureAction: Enforce
background: true
rules:
- name: check-runAsNonRoot
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Running as root is not allowed"
pattern:
spec:
securityContext:
runAsNonRoot: true
containers:
- securityContext:
runAsNonRoot: true
|
4. CI/CD 整合驗證
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # .gitlab-ci.yml
stages:
- validate
validate-pod-security:
stage: validate
image: bitnami/kubectl:latest
script:
- |
for file in $(find ./k8s -name "*.yaml"); do
echo "Validating: $file"
kubectl apply --dry-run=server \
-f "$file" \
--namespace=test-restricted \
2>&1 | tee -a validation.log
done
- |
if grep -q "violat" validation.log; then
echo "Pod Security Standard violations found!"
exit 1
fi
|
5. 多環境配置策略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| # namespace-configs.yaml
---
# 開發環境 - 寬鬆
apiVersion: v1
kind: Namespace
metadata:
name: development
labels:
environment: dev
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/warn: restricted
---
# 測試環境 - 中等
apiVersion: v1
kind: Namespace
metadata:
name: staging
labels:
environment: staging
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
---
# 正式環境 - 嚴格
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
environment: prod
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
|
6. 常見問題排解
1
2
3
4
5
6
7
8
9
10
11
| # 檢查 Pod 為何被拒絕
kubectl describe pod <pod-name> -n <namespace>
# 查看詳細的安全驗證結果
kubectl get events -n <namespace> --field-selector reason=FailedCreate
# 分析 Pod spec 的安全問題
kubectl auth can-i create pods --as=system:serviceaccount:<ns>:<sa> -n <namespace>
# 使用 kubectl debug 進行偵錯
kubectl debug -it <pod-name> --image=busybox --target=<container-name>
|
總結
Pod Security Standards 為 Kubernetes 提供了一套標準化且易於管理的安全機制。透過三個清晰的安全等級(Privileged、Baseline、Restricted)和三種執行模式(enforce、audit、warn),管理員可以靈活地控制叢集中的 Pod 安全性。
重點回顧:
- 選擇適當的安全等級:根據工作負載需求選擇 Privileged、Baseline 或 Restricted
- 漸進式導入:先使用 warn/audit 模式測試,再逐步切換至 enforce
- 善用豁免機制:為系統元件設定適當的豁免
- 持續監控:透過 audit logging 和 metrics 監控安全狀態
- 自動化驗證:將安全檢查整合至 CI/CD pipeline
透過正確實施 Pod Security Standards,您可以大幅提升 Kubernetes 叢集的安全性,同時降低維運複雜度。
參考資源