在 Kubernetes 環境中,確保工作負載的安全性至關重要。除了網路層級的防護外,容器層級的安全性設定也不容忽視。透過安全性上下文,可以精細地控制容器內部程式的許可權,例如限制檔案系統的讀寫許可權、設定程式的使用者和群組、以及限制系統呼叫等。然而,單純設定安全性上下文並不足以應付複雜的應用場景,Pod Security Policies 提供更進階的控制機制,可以限制 Pod 的建立與執行,例如限制容器是否可以使用特權模式、限制容器可以使用的資源型別等。隨著 Pod Security Policies 的棄用,Open Policy Agent (OPA) 和 Kyverno 等工具成為更靈活且功能更強大的替代方案,它們可以根據自定義的策略來控制 Kubernetes 叢集的行為,提供更全面的安全性防護。
加強工作負載的安全性
在 Kubernetes 環境中,設定安全性上下文(Security Context)是強化工作負載安全性的重要步驟,特別是在開發將佈署在任意叢集中的應用程式時(例如,開發開源應用程式)。清楚瞭解應用程式所需的許可權,並確保安全性上下文與這些需求盡可能比對,將有助於使用者提高其叢集的安全性。
一般方法
安全性上下文可以在容器層級設定,也可以應用於 Pod 中的所有容器。如果兩者都定義了,容器層級的設定將覆寫 Pod 的設定。在大多數情況下,建議只在一個層級設定這些專案,以避免潛在的意外結果。
容器安全性上下文
在容器內,安全性上下文的定義與容器名稱和映像檔處於同一層級,如清單 20.1 所示。
containers:
- name: db
image: mongo
ports:
- name: mongo
containerPort: 27017
securityContext:
capabilities:
drop:
- all
add:
- CHOWN
- SETGID
- SETUID
readOnlyRootFilesystem: true
防止許可權提升
allowPrivilegeEscalation 是一個重要的強化選項,應該幾乎總是被設定。當設為 false 時,這個標誌指示容器執行時(以及 Linux 核心)防止容器內的程式請求額外的許可權。
示範
要示範這個效果,我們可以使用 Docker 命令在一個標準映像檔和 Docker Hub 上具有 setUID shell 的映像檔上進行操作。Docker Hub 映像檔 raesene/setuidexample 在 /bin/setuidbash 處有一個 setUID shell。
首先,啟動根據此映像檔的容器:
docker run -it raesene/setuidexample /bin/bash
執行 whoami 命令,應該會顯示使用者為 newuser:
newuser@83ddb9714a5e:/$ whoami
newuser
然後,執行 setUID shell 後,我們可以確認使用者已變更:
newuser@83ddb9714a5e:/$ /bin/setuidbash -p
setuidbash-4.4# whoami
root
為了示範 no-new-privileges 的效果,我們可以將該選項傳遞給 docker run,這與在 Kubernetes 工作負載中使用安全性上下文具有相同的效果。
docker run -it --security-opt=no-new-privileges raesene/setuidexample /bin/bash
現在嘗試使用 setUID shell,我們可以看到它沒有效果:
/bin/setuidbash -p
newuser@15e5a64014a4:/$ whoami
newuser
功能(Capabilities)
預設情況下,當 Linux 容器執行時,它將被分配一組功能(Linux 功能在第 1 章「什麼是容器?」中討論過)。預設功能集將取決於所使用的容器執行時(例如,Docker 可能提供與 CRI-O 不同的功能集)。因此,對於應用程式來說,指定所需的功能有助於應用程式在未知的叢集中平滑執行,因為它們不依賴於 CRI 分配的預設功能集是否正確。
示範功能
我們可以使用 Docker Hub 映像檔 raesene/alpine-containertools 來示範這一點,方法是執行以下命令:
kubectl run -it amicontained --image=raesene/alpine-containertools /bin/bash
然後執行 amicontained。如果您的叢集正在使用 Docker 作為執行時,您應該會看到類別似清單 20.2 的輸出。
securityContext:
capabilities:
drop:
- NET_RAW
內容解密:
此段落說明瞭如何使用 securityContext 設定容器的安全性上下文,以控制容器的許可權。其中包括瞭如何設定 allowPrivilegeEscalation 以防止容器內的程式提升許可權,以及如何使用 capabilities 設定來控制容器的功能。這些設定可以幫助提高容器的安全性,防止潛在的安全威脅。
加強容器安全性的兩種方法
- 丟棄不必要的功能:從預設功能集中丟棄不必要的功能。例如,大多數容器工作負載都不需要
net_raw功能,該功能可用於嘗試 ARP 欺騙攻擊。 - 明確指定所需功能:明確指定容器所需的功能,以確保容器在不同的叢集中都能正常執行。
加強工作負載安全性:Kubernetes 中的安全上下文與強制性安全控制
在 Kubernetes 環境中,加強工作負載安全性是至關重要的。本章將探討如何透過組態安全上下文和實施強制性安全控制來提升容器和工作負載的安全性。
安全上下文組態
安全上下文(Security Context)是 Kubernetes 中用於定義容器或 Pod 安全組態的關鍵機制。透過設定安全上下文,可以控制容器內程式的許可權、能力(Capabilities)、檔案系統存取許可權等,從而減少潛在的安全風險。
能力(Capabilities)
在 Linux 系統中,能力是一種細粒度的許可權控制機制,允許對程式的許可權進行精確控制。在容器環境中,可以透過組態安全上下文來新增或刪除容器的能力。
例如,在某些情況下,應用程式可能需要特定的能力,如 CHOWN、SETGID 和 SETUID,以便修改檔案的所有權和許可權。正確組態這些能力,可以在不授予過多許可權的情況下滿足應用需求。
securityContext:
capabilities:
drop:
- ALL
add:
- CHOWN
- SETGID
- SETUID
內容解密:
capabilities欄位用於組態容器的能力。drop: - ALL表示刪除所有預設的能力。add列表中增加了CHOWN、SETGID和SETUID能力,以滿足特定應用的需求。
特權模式(Privileged)
特權模式會停用容器的沙箱隔離機制,使其擁有主機的完全存取許可權。應盡量避免將 privileged 設定為 true,因為這會顯著增加安全風險。
securityContext:
privileged: false
內容解密:
- 將
privileged設定為false可以確保容器執行在隔離環境中,避免對主機造成不必要的風險。
只讀根檔案系統(readOnlyRootFilesystem)
將容器的根檔案系統設定為只讀,可以防止攻擊者在容器內寫入惡意檔案或修改系統檔案。這對於提升容器的安全性至關重要。
securityContext:
readOnlyRootFilesystem: true
內容解密:
readOnlyRootFilesystem: true確保容器的根檔案系統不可寫入,從而增強安全性。- 對於需要寫入資料的應用,可以掛載
emptyDir或持久化儲存卷來滿足需求。
Seccomp 組態
Seccomp(Secure Computing Mode)是一種 Linux 核心機制,用於限制程式可以呼叫的系統呼叫。透過組態 Seccomp Profile,可以進一步加強容器的隔離性。
在 Kubernetes 中,可以透過安全上下文組態 Seccomp Profile,從而限制容器內程式的系統呼叫。
securityContext:
seccompProfile:
type: RuntimeDefault
內容解密:
seccompProfile.type: RuntimeDefault表示使用容器執行時的預設 Seccomp 組態。- 這種組態可以限制容器內程式呼叫危險的系統呼叫,從而增強安全性。
強制性工作負載安全控制
除了自願性的安全上下文組態外,叢集管理員還需要實施強制性安全控制,以確保所有佈署的工作負載符合特定的安全標準。
Pod Security Standards
Kubernetes 定義了一套 Pod Security Standards,用於指導叢集管理工作負載的安全組態。這些標準包括三個級別:Privileged、Baseline 和 Restricted。
- Privileged:無任何限制,適用於可信的叢集元件。
- Baseline:提供最低限度的安全限制,適用於大多數常見容器。
- Restricted:實施最嚴格的安全限制,適用於對安全性要求極高的場景。
實施這些標準可以幫助叢集管理員確保工作負載的安全性,並減少潛在的安全風險。
工作負載強化:PodSecurityPolicy 的使用與設定
在 Kubernetes 中,強化工作負載的安全性是一項重要的任務。PodSecurityPolicy(PSP)是一種用於控制 Pod 安全設定的機制,儘管它已被標記為棄用,但許多現有的叢集仍在使用它。因此,瞭解其運作方式和挑戰是非常重要的。
PodSecurityPolicy 的運作原理
在啟用 PSP 之前,瞭解其運作方式是非常重要的。當工作負載在叢集中啟動時,PSP 控制器會檢查啟動工作負載的使用者或服務帳戶是否有許可權使用符合工作負載安全上下文要求的 PSP。如果找不到比對的 PSP,工作負載將被拒絕。
設定 PSP
為了避免在啟用 PSP 後無法建立新的工作負載,建議在啟用之前建立一些基本的 PSP。可以選擇建立一個預設的“允許所有”策略,或者建立一個高許可權和一個低許可權的策略。
高許可權 PSP
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: highpriv
spec:
privileged: true
allowPrivilegeEscalation: true
allowedCapabilities:
- '*'
volumes:
- '*'
hostNetwork: true
hostPorts:
- min: 0
max: 65535
hostIPC: true
hostPID: true
runAsUser:
rule: 'RunAsAny'
seLinux:
rule: 'RunAsAny'
supplementalGroups:
rule: 'RunAsAny'
fsGroup:
rule: 'RunAsAny'
內容解密:
- 此 PSP 允許特權容器,可能會允許使用者存取底層節點,因此需要謹慎使用。
privileged: true表示允許容器以特權模式執行。allowPrivilegeEscalation: true表示允許容器提升其許可權。allowedCapabilities和volumes的設定允許容器使用各種功能和掛載卷。
低許可權 PSP
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: lowpriv
spec:
privileged: false
allowPrivilegeEscalation: false
requiredDropCapabilities:
- ALL
volumes:
- 'configMap'
- 'emptyDir'
- 'secret'
hostNetwork: false
hostPID: false
runAsUser:
rule: 'MustRunAsNonRoot'
seLinux:
rule: 'RunAsAny'
supplementalGroups:
rule: 'MustRunAs'
ranges:
- min: 1
max: 65535
fsGroup:
rule: 'MustRunAs'
ranges:
- min: 1
max: 65535
readOnlyRootFilesystem: false
內容解密:
- 此 PSP 禁止特權容器和許可權提升,並限制了可以使用的卷型別。
privileged: false和allowPrivilegeEscalation: false表示禁止特權容器和許可權提升。requiredDropCapabilities表示需要丟棄所有功能。runAsUser的MustRunAsNonRoot表示容器必須以非 root 使用者執行。
建立和啟用 PSP
建立 PSP 後,需要將其套用到叢集中。可以使用 kubectl create 命令建立 PSP,然後使用 kubectl get psp 檢視已建立的 PSP。
在 kubeadm 叢集中啟用 PSP
需要在 API 伺服器的靜態 Pod 清單中新增 --enable-admission-plugins=NodeRestriction,PodSecurityPolicy。
PSP 與 RBAC
為了使 PSP 生效,需要正確組態 RBAC 設定。使用者和服務帳戶需要具有對 PSP 的“USE”許可權,才能使用它。可以建立一個 ClusterRole 和 ClusterRoleBinding,將低許可權 PSP 繫結到 system:authenticated 群組。
LowPriv ClusterRole
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: psp-lowpriv
rules:
- apiGroups:
- extensions
resources:
- podsecuritypolicies
resourceNames:
- lowpriv
verbs:
- use
內容解密:
- 此 ClusterRole 定義了對
lowprivPSP 的“USE”許可權。 apiGroups和resources指定了 PSP 的 API 群組和資源型別。resourceNames指定了允許使用的 PSP 名稱。verbs指定了允許的操作。
Kubernetes 工作負載強化:Pod Security Policies 與替代方案
Kubernetes 的 Pod Security Policies(PSP)提供了一種機制來控制 Pod 的建立和執行,以確保叢集的安全性。然而,隨著 PSP 即將被棄用,瞭解其替代方案至關重要。
Pod Security Policies 的組態與使用
PSP 的組態涉及到建立 ClusterRole 和 ClusterRoleBinding,以控制不同使用者和服務帳戶對 PSP 的存取許可權。
低許可權 PSP 組態範例
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: psp-default
subjects:
- kind: Group
name: system:authenticated
roleRef:
kind: ClusterRole
name: psp-lowpriv
apiGroup: rbac.authorization.k8s.io
高許可權 PSP 組態範例
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: psp-highpriv
rules:
- apiGroups:
- extensions
resources:
- podsecuritypolicies
resourceNames:
- highpriv
verbs:
- use
高許可權 PSP Role Binding 組態範例
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: psp-permissive
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: psp-highpriv
subjects:
- kind: ServiceAccount
name: daemon-set-controller
namespace: kube-system
- kind: ServiceAccount
name: replicaset-controller
namespace: kube-system
- kind: ServiceAccount
name: deployment-controller
namespace: kube-system
組態解說:
- 低許可權 PSP:允許所有已驗證使用者建立基本 Pod。
- 高許可權 PSP:提供對高許可權 Pod 的建立許可權,需謹慎使用。
- Role Binding:將高許可權 PSP 繫結到特定的服務帳戶(如
daemon-set-controller),並限制在kube-system名稱空間內。
PSP 的替代方案
由於 PSP 即將被棄用,以下是兩種流行的替代方案:
Open Policy Agent (OPA):一個通用的策略控制系統,適用於 Cloud Native 環境。OPA 提供了一個名為 Gatekeeper 的元件,可以安裝到 Kubernetes 叢集中以強制執行策略。
- 安裝 Gatekeeper 後,它會在叢集中執行,並透過驗證准入 Webhook 鉤入 API 伺服器。
- Gatekeeper 可以根據定義的策略決定是否允許或拒絕事件。
Kyverno:另一個流行的策略管理工具,提供更靈活的策略管理功能。
OPA Gatekeeper 安裝範例:
Gatekeeper 可以透過直接應用 manifest 或使用 Helm 包管理器進行安裝。
kubectl get ns
NAME STATUS AGE
default Active 6m58s
gatekeeper-system Active 6m45s
安裝解說:
- Gatekeeper 安裝後會在自己的名稱空間(
gatekeeper-system)中執行。 - 它可以檢查叢集中發生的事件,並根據定義的策略進行處理。