本頁面說明如何指示 Google Kubernetes Engine (GKE) 將工作負載排程在專屬的獨立節點集區,與具備權限的 GKE 管理工作負載分開,降低叢集發生權限提升攻擊的風險。只有在無法使用 GKE Sandbox 時,才應採用這個方法。建議您使用 GKE Sandbox 隔離節點。GKE Sandbox 也為工作負載提供其他強化功能。
本頁面適用於需要工作負載隔離層,但無法使用 GKE Sandbox 的安全防護專家。如要進一步瞭解 Google Cloud 內容中提及的常見角色和範例工作,請參閱常見的 GKE Enterprise 使用者角色和工作。
本頁內容適用於沒有節點自動佈建功能的標準叢集。如要在 Autopilot 叢集和啟用節點自動佈建功能的 Standard 叢集中區隔工作負載,請參閱「在 GKE 中設定工作負載區隔」。
總覽
GKE 叢集會使用具備特殊權限的 GKE 代管工作負載,啟用特定叢集功能和特性,例如指標收集。這些工作負載會獲得特殊權限,可在叢集中正確執行。
部署至節點的工作負載可能會遭到惡意實體入侵。如果這些工作負載與具備高權限的 GKE 管理工作負載一起執行,表示攻擊者只要從遭入侵的容器脫逃,就能使用節點上具備高權限工作負載的憑證,在叢集中提升權限。
防止容器突破
應用程式應是主要防禦措施。GKE 提供多項功能,可用於強化叢集和 Pod。在大多數情況下,我們強烈建議使用 GKE Sandbox 隔離工作負載。GKE Sandbox 以 gVisor 開放原始碼專案為基礎,並在使用者空間中實作 Linux 核心 API。每個 Pod 都會在專屬核心上執行,將應用程式放入沙箱,防止存取主機核心中的系統呼叫權限。在 GKE Sandbox 中執行的工作負載會自動排程至獨立節點,與其他工作負載隔離。
您也應遵循「強化叢集的安全防護機制」一文中的建議。
避免權限提升攻擊
如果無法使用 GKE Sandbox,且除了其他強化措施外,還想增加一層隔離機制,可以使用節點汙染和節點親和性,在專屬節點集區中排定工作負載。節點汙染會告知 GKE,避免在這些節點上排程沒有對應容許項的工作負載 (例如 GKE 管理的工作負載)。自有工作負載的節點親和性會告知 GKE,將 Pod 排定至專屬節點。
節點隔離的限制
- 攻擊者仍可從遭入侵的節點發動阻斷服務 (DoS) 攻擊。
- 遭入侵的節點仍可讀取許多資源,包括叢集中的所有 Pod 和命名空間。
- 遭入侵的節點可以存取在該節點上執行的每個 Pod 所使用的 Secret 和憑證。
- 使用個別節點集區隔離工作負載可能會影響成本效益、自動調度資源和資源用量。
- 遭入侵的節點仍可略過輸出網路政策。
- 部分 GKE 管理的工作負載必須在叢集的每個節點上執行,且設定為可容許所有汙點。
- 如果您部署的 DaemonSet 具有提升的權限,且可容許任何汙點,這些 Pod 可能會成為權限提升的路徑,讓遭入侵的節點得逞。
節點隔離的運作方式
如要為工作負載實作節點隔離,請完成下列步驟:
- 為工作負載汙染節點集區並加上標籤。
- 使用對應的容許度和節點親和性規則更新工作負載。
本指南假設您從叢集中的一個節點集區開始。除了節點汙染之外,使用節點親和性並非必要,但我們建議您這麼做,因為這樣可以更有效控管排程。
事前準備
開始之前,請確認你已完成下列工作:
- 啟用 Google Kubernetes Engine API。 啟用 Google Kubernetes Engine API
- 如要使用 Google Cloud CLI 執行這項工作,請安裝並初始化 gcloud CLI。如果您先前已安裝 gcloud CLI,請執行
gcloud components update
,取得最新版本。
- 為要用於專屬節點集區的節點汙點和節點標籤選擇特定名稱。
為工作負載汙染節點集區並加上標籤
為工作負載建立新的節點集區,並套用節點汙點和節點標籤。在節點集區層級套用汙點或標籤時,任何新節點 (例如自動調度資源建立的節點) 都會自動取得指定的汙點和標籤。
您也可以將節點汙點和節點標籤新增至現有節點集區。如果您使用 NoExecute
效果,GKE 會清空節點上未容許新汙染的 Pod。
如要隔離工作負載,請一律在節點標籤和 Pod 資訊清單中的對應選取器使用 node-restriction.kubernetes.io/
前置字元。這個前置字串可防止攻擊者使用節點的憑證,設定或修改使用這個前置字串的標籤。詳情請參閱 Kubernetes 說明文件中的「節點隔離/限制」。
如要將汙點和標籤新增至新的節點集區,請執行下列指令:
gcloud container node-pools create POOL_NAME \
--cluster=CLUSTER_NAME \
--node-taints=TAINT_KEY=TAINT_VALUE:TAINT_EFFECT \
--node-labels=node-restriction.kubernetes.io/LABEL_KEY=LABEL_VALUE
更改下列內容:
POOL_NAME
:工作負載的新節點集區名稱。CLUSTER_NAME
:GKE 叢集名稱。TAINT_KEY=TAINT_VALUE
:與排程TAINT_EFFECT
相關聯的鍵/值組合。例如:workloadType=untrusted
。TAINT_EFFECT
:下列其中一個效果值:NoSchedule
、PreferNoSchedule
或NoExecute
。NoExecute
比NoSchedule
提供更完善的驅逐保證。node-restriction.kubernetes.io/LABEL_KEY
=LABEL_VALUE
:節點標籤的鍵/值組合,對應至您在工作負載資訊清單中指定的選取器。node-restriction.kubernetes.io/
前置字元可防止節點憑證用於在節點上設定這些鍵/值配對。
為工作負載新增容許度和節點親和性規則
為專屬節點集區設定污點後,除非工作負載具有與您新增污點相應的容許條件,否則無法排程至該節點集區。在工作負載的規格中新增容許條件,讓這些 Pod 在受汙染的節點集區中排程。
如果您已為專屬節點集區加上標籤,也可以新增節點相依性規則,告知 GKE 只在該節點集區中排程工作負載。
以下範例會為 workloadType=untrusted:NoExecute
taint 新增容許度,並為 workloadType=untrusted
節點標籤新增節點親和性規則。
kind: Deployment
apiVersion: apps/v1
metadata:
name: my-app
namespace: default
labels:
app: my-app
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
tolerations:
- key: TAINT_KEY
operator: Equal
value: TAINT_VALUE
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-restriction.kubernetes.io/LABEL_KEY
operator: In
values:
- "LABEL_VALUE"
containers:
- name: sleep
image: ubuntu
command: ["/bin/sleep", "inf"]
更改下列內容:
TAINT_KEY
:您套用至專屬節點集區的汙點鍵。TAINT_VALUE
:您套用至專屬節點集區的汙點值。LABEL_KEY
:您套用至專屬節點集區的節點標籤鍵。LABEL_VALUE
:您套用至專屬節點集區的節點標籤值。
使用 kubectl apply
更新 Deployment 時,GKE 會重新建立受影響的 Pod。節點親和性規則會強制 Pod 進入您建立的專屬節點集區。容許條件只允許將這些 Pod 放置在節點上。
確認分離功能是否正常運作
如要確認排程是否正常運作,請執行下列指令,並檢查工作負載是否位於專屬節點集區:
kubectl get pods -o=wide
建議做法與最佳做法
設定節點隔離後,建議您採取下列做法:
- 新增
components.gke.io/gke-managed-components
汙點,將特定節點集區限制為僅適用於 GKE 代管的工作負載。新增這項汙點可防止您自己的 Pod 排定在這些節點上,進而提升隔離效果。 - 建立新的節點集區時,請在這些節點集區中新增自己的汙點,防止大多數 GKE 管理的工作負載在這些節點上執行。
- 每當您將新工作負載部署到叢集時 (例如安裝第三方工具),請稽核 Pod 要求的權限。盡可能避免將使用提升權限的工作負載部署至共用節點。