租戶隔離 - Amazon EKS

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

租戶隔離

當我們考慮多租戶時,我們通常想要隔離使用者或應用程式與在共用基礎設施上執行的其他使用者或應用程式。

Kubernetes 是單一租用戶協調程式,即控制平面的單一執行個體在叢集中的所有租用戶之間共用。不過,您可以使用各種 Kubernetes 物件來建立多租用戶的相似性。例如,可以實作命名空間和角色型存取控制 (RBAC),以邏輯方式將租用戶彼此隔離。同樣地,配額和限制範圍可用來控制每個租用戶可以使用的叢集資源數量。不過,叢集是唯一提供強大安全界限的建構。這是因為管理 以取得叢集內主機存取權的攻擊者可以擷取掛載在該主機上的所有秘密、ConfigMaps 和磁碟區。他們也可以模擬 Kubelet,允許他們操作節點的屬性和/或在叢集內橫向移動。

以下各節將說明如何實作租用戶隔離,同時降低使用 Kubernetes 等單一租用戶協調器的風險。

軟式多租用戶

透過軟式多租用戶,您可以使用原生 Kubernetes 建構模組,例如命名空間、角色和角色繫結,以及網路政策,在租用戶之間建立邏輯分隔。例如,RBAC 可以防止租戶存取或操作彼此的資源。配額和限制範圍控制每個租用戶可以使用的叢集資源數量,而網路政策可協助防止部署到不同命名空間的應用程式彼此通訊。

不過,這些控制項都無法防止來自不同租用戶的 Pod 共用節點。如果需要更強的隔離,您可以使用節點選擇器、反親和性規則和/或污點和容錯,強制來自不同租用戶的 Pod 排程到不同的節點;通常稱為唯一租用戶節點。這可能會在具有許多租用戶的環境中變得相當複雜且成本高昂。

重要

使用命名空間實作的軟式多租用不允許您為租戶提供篩選後的命名空間清單,因為命名空間是全域範圍類型。如果租用戶能夠檢視特定命名空間,則可以檢視叢集中的所有命名空間。

警告

使用soft-multi-tenancy時,租用戶保留查詢 CoreDNS 的功能,以查詢預設在叢集內執行的所有服務。攻擊者可以透過 ..svc.cluster.local從叢集中的任何 Pod 執行 dig SRV 來利用這一點。如果您需要限制存取叢集內所執行服務的 DNS 記錄,請考慮使用 CoreDNS 的防火牆或政策外掛程式。如需詳細資訊,請參閱 https://https://github.com/coredns/policy#kubernetes-metadata-multi-tenancy-policy

Kiosk 是一種開放原始碼專案,可協助實作軟式多租用戶。它實作為一系列 CRDs和控制器,提供下列功能:

  • 帳戶和帳戶 使用者在共用的 Kubernetes 叢集中分隔租用戶

  • 帳戶使用者的自助式命名空間佈建

  • 帳戶限制,以確保共享叢集時的服務品質和公平性

  • 用於安全租戶隔離和自助式命名空間初始化的命名空間範本

Loft 是來自 Kiosk 和 DevSpace 維護者的商業產品,新增了下列功能:

  • 授予不同叢集中空間存取權的多叢集存取權

  • 休眠模式會在閒置期間縮減空間中的部署

  • 使用 GitHub 等 OIDC 身分驗證供應商的單一登入

軟式多租用戶可以解決三個主要使用案例。

企業設定

第一個是企業設定,其中「租用戶」是半信任的,他們是員工、承包商或組織以其他方式授權。每個租戶通常會符合行政部門,例如部門或團隊。

在此類型的設定中,叢集管理員通常會負責建立命名空間和管理政策。他們也可以實作委派的管理模型,讓某些個人能夠監督命名空間,讓他們能夠針對部署、服務、Pod、任務等非政策相關物件執行 CRUD 操作。

在此設定中,容器執行時間提供的隔離可能是可接受的,或者可能需要增強額外的 Pod 安全控制。如果需要更嚴格的隔離,也可能需要限制不同命名空間中服務之間的通訊。

Kubernetes as a Service

相反地,軟式多租用戶可用於您想要提供 Kubernetes 即服務 (KaaS) 的設定。使用 KaaS,您的應用程式會託管在共用叢集中,以及一組提供一組 PaaS 服務的控制器和 CRDs。租用戶會直接與 Kubernetes API 伺服器互動,並允許 對非政策物件執行 CRUD 操作。中也有自助式元素,讓租戶可以建立和管理自己的命名空間。在此類型的環境中,租用戶會假設執行不受信任的程式碼。

若要隔離此類環境中的租戶,您可能需要實作嚴格的網路政策以及 Pod 沙盒。沙盒是您在 Firecracker 等微型 VM 或使用者空間核心中執行 Pod 容器的地方。今天,您可以使用 EKS Fargate 建立沙盒化 Pod。

軟體即服務 (SaaS)

軟式多租用戶的最終使用案例為Software-as-a-Service(SaaS) 設定。在此環境中,每個租用戶都會與叢集內執行的應用程式的特定執行個體相關聯。每個執行個體通常都有自己的資料,並使用通常與 Kubernetes RBAC 無關的個別存取控制。

與其他使用案例不同,SaaS 設定中的租用戶不會直接與 Kubernetes API 連接。相反地,SaaS 應用程式負責與 Kubernetes API 連接,以建立支援每個租用戶的必要物件。

Kubernetes 建構

在這些執行個體中,下列建構會用來將租用戶彼此隔離:

命名空間

命名空間是實作軟式多租用戶的基礎。它們可讓您將叢集分割為邏輯分割區。實作多租戶所需的配額、網路政策、服務帳戶和其他物件,範圍限定為命名空間。

網路政策

根據預設,Kubernetes 叢集中的所有 Pod 都可以彼此通訊。您可以使用網路政策來變更此行為。

網路政策會使用標籤或 IP 地址範圍來限制 Pod 之間的通訊。在需要租用戶之間嚴格網路隔離的多租用戶環境中,我們建議從拒絕 Pod 之間通訊的預設規則開始,以及允許所有 Pod 查詢 DNS 伺服器以進行名稱解析的另一個規則。有了該功能,您就可以開始新增更多允許在命名空間內通訊的寬鬆規則。這可以視需要進一步改進。

注意

Amazon VPC CNI 現在支援 Kubernetes 網路政策,以建立可隔離敏感工作負載的政策,並在 AWS 上執行 Kubernetes 時保護這些工作負載免於未經授權的存取。這表示您可以在 Amazon EKS 叢集中使用網路政策 API 的所有功能。此層級的精細控制可讓您實作最低權限原則,以確保僅允許授權的 Pod 彼此通訊。

重要

網路政策是必要的,但不夠。網路政策的強制執行需要政策引擎,例如 Calico 或 Cilium。

角色型存取控制 (RBAC)

角色和角色繫結是用於在 Kubernetes 中強制執行角色型存取控制 (RBAC) 的 Kubernetes 物件。角色包含可針對叢集中的物件執行的動作清單。角色繫結指定角色適用的個人或群組。在企業和 KaaS 設定中,RBAC 可用來允許由選取的群組或個人管理物件。

配額

配額用於定義叢集中託管工作負載的限制。透過配額,您可以指定 Pod 可以使用的 CPU 和記憶體數量上限,也可以限制叢集或命名空間中可配置的資源數量。限制範圍可讓您宣告每個限制的最小值、最大值和預設值。

過度承諾共用叢集中的資源通常很有幫助,因為它可讓您將資源最大化。不過,對叢集的無限制存取可能會導致資源匱乏,這可能會導致效能降低和應用程式可用性的損失。如果 Pod 的請求設定過低,且實際資源使用率超過節點的容量,則節點會開始遇到 CPU 或記憶體壓力。發生這種情況時,可能會重新啟動和/或從節點移出 Pod。

為了防止這種情況發生,您應該計劃在多租戶環境中的命名空間上強加配額,以強制租戶在叢集上排程其 Pod 時指定請求和限制。它還將限制 Pod 可以使用的資源量,以緩解潛在的拒絕服務。

您也可以使用配額來分配叢集的資源,以符合租戶的支出。這在 KaaS 案例中特別有用。

Pod 優先順序和先佔

當您想要提供比其他 Pod 更重要的 Pod 時,Pod 優先順序和先佔可能很有用。例如,使用 Pod 優先順序,您可以設定客戶 A 的 Pod 以高於客戶 B 的優先順序執行。當可用容量不足時,排程器會從客戶 B 移出較低優先順序的 Pod,以容納客戶 A 的較高優先順序 Pod。這在 SaaS 環境中特別方便,而願意支付溢價的客戶會獲得較高的優先順序。

重要

Pod 優先順序可能會對優先順序較低的其他 Pod 產生不必要的效果。例如,雖然受害者的 Pod 已正常終止,但不保證 PodDisruptionBudget,這可能會破壞依賴一定數量 Pod 的優先順序較低的應用程式,請參閱先佔限制

緩解控制項

您身為多租用戶環境管理員的主要考量是阻止攻擊者存取基礎主機。應考慮以下控制項以降低此風險:

容器的沙盒化執行環境

沙盒是一種技術,每個容器都會在自己的隔離虛擬機器中執行。執行 Pod 沙盒的技術包括 Firecracker 和 Weave 的 Firekube

如需讓 Firecracker 成為 EKS 支援執行時間的詳細資訊,請參閱 https://https://threadreaderapp.com/thread/1238496944684597248.html

開啟政策代理程式 (OPA) 和 Gatekeeper

Gatekeeper 是 Kubernetes 許可控制器,可強制執行使用 OPA 建立的政策。使用 OPA,您可以建立從不同執行個體上的租用戶執行 Pod 的政策,或以比其他租用戶更高的優先順序執行。您可以在此專案的 GitHub 儲存庫中找到常見 OPA 政策的集合。

還有 CoreDNS 的實驗性 OPA 外掛程式,可讓您使用 OPA 來篩選/控制 CoreDNS 傳回的記錄。

基佛諾

Kyverno 是 Kubernetes 原生政策引擎,可使用政策做為 Kubernetes 資源來驗證、變更和產生組態。Kyverno 使用 Kustomize 樣式的浮水印進行驗證,支援 JSON 修補程式和變動的策略合併修補程式,並且可以根據彈性觸發在命名空間之間複製資源。

您可以使用 Kyverno 隔離命名空間、強制執行 Pod 安全性和其他最佳實務,以及產生預設組態,例如網路政策。此專案的 GitHub 儲存庫中包含數個範例。Kyverno 網站上的政策程式庫中包含許多其他項目。

將租戶工作負載隔離到特定節點

限制在特定節點上執行的租戶工作負載可用於提高軟式多租戶模型中的隔離。透過此方法,租戶特定的工作負載只會在為個別租戶佈建的節點上執行。為了實現此隔離,原生 Kubernetes 屬性 (節點親和性、污點和容錯) 用於鎖定特定節點以進行 Pod 排程,並防止其他租用戶的 Pod 排程在租用戶特定的節點上。

第 1 部分 - 節點親和性

Kubernetes 節點親和性用於根據節點標籤將節點設為目標以進行排程。使用節點親和性規則,Pod 會被吸引到符合選取器詞彙的特定節點。在下列 Pod 規格中,requiredDuringSchedulingIgnoredDuringExecution節點親和性會套用至個別的 Pod。結果是 Pod 將以以下列索引鍵/值標記的節點為目標:node-restriction.kubernetes.io/tenant: tenants-x

... spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: node-restriction.kubernetes.io/tenant operator: In values: - tenants-x ...

使用此節點親和性時,在排程期間需要標籤,但在執行期間則不需要;如果基礎節點的標籤變更,則不會僅因為該標籤變更而移出 Pod。不過,未來的排程可能會受到影響。

警告

的標籤字首在 Kubernetes 中node-restriction.kubernetes.io/具有特殊意義。為 EKS 叢集啟用的 NodeRestriction kubelet 可防止adding/removing/updating具有此字首的標籤。攻擊者無法使用 ,kubelet’s credentials to update the node object or modify the system setup to pass these labels into `kubelet因為 kubelet 不允許修改這些標籤。如果此字首用於所有 Pod 到節點排程,則可防止攻擊者透過修改節點標籤,將不同的工作負載集吸引到節點的情況。

我們可以使用節點選擇器,而不是節點親和性。不過,節點親和性更具表達性,並允許在 Pod 排程期間考慮更多條件。如需有關差異和更進階排程選擇的其他資訊,請參閱此 CNCF 部落格文章中的進階 Kubernetes Pod 到節點排程

第 2 部分 - 污點和容錯

吸引 Pod 到節點只是這個三部分方法的第一部分。為了讓此方法運作,我們必須避免 Pod 排程到未獲授權 Pod 的節點。為了避免不必要的或未經授權的 Pod,Kubernetes 會使用節點污點。污點用於在節點上放置條件,以防止 Pod 排程。以下污點使用 的鍵/值對tenant: tenants-x

... taints: - key: tenant value: tenants-x effect: NoSchedule ...

鑑於上述節點 taint,僅允許在節點上排程可容忍污點的 Pod。若要允許將授權的 Pod 排程到節點上,個別的 Pod 規格必須包含污點toleration的 ,如下所示。

... tolerations: - effect: NoSchedule key: tenant operator: Equal value: tenants-x ...

具有上述內容的 Pod toleration不會停止在節點上排程,至少不會因為該特定污點而停止排程。Kubernetes 也會使用污點,在特定情況下暫時停止 Pod 排程,例如節點資源壓力。透過節點親和性、污點和容錯,我們可以有效地將所需的 Pod 吸引到特定節點,並排斥不需要的 Pod。

重要

某些 Kubernetes Pod 需要在所有節點上執行。這些 Pod 的範例是由容器網路界面 (CNI)kube-proxy 協助程式集啟動的範例。為此,這些 Pod 的規格包含非常寬鬆的容錯能力,以容忍不同的污點。請小心不要變更這些容錯。變更這些容錯可能會導致不正確的叢集操作。此外,OPA/GatekeeperKyverno 等政策管理工具可用於撰寫驗證政策,以防止未經授權的 Pod 使用這些允許容錯。

第 3 部分 - 節點選擇的政策型管理

有數種工具可用來協助管理 Pod 規格的節點親和性與公差,包括強制執行 CICD 管道中的規則。不過,也應在 Kubernetes 叢集層級執行隔離。因此,政策管理工具可用來根據請求承載來變更傳入 Kubernetes API 伺服器請求,以套用上述各自的節點親和性規則和容錯。

例如,以 tenants-x 命名空間為目標的 Pod 可以使用正確的節點親和性和容錯性來加上戳記,以允許在 tenants-x 節點上排程。利用使用 Kubernetes Mutating Admission Webhook 設定的政策管理工具,政策可用來變更傳入 Pod 規格。變動會新增所需的元素,以允許所需的排程。新增節點親和性的範例 OPA/Gatekeeper 政策如下所示。

apiVersion: mutations.gatekeeper.sh/v1alpha1 kind: Assign metadata: name: mutator-add-nodeaffinity-pod annotations: aws-eks-best-practices/description: >- Adds Node affinity - https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity spec: applyTo: - groups: [""] kinds: ["Pod"] versions: ["v1"] match: namespaces: ["tenants-x"] location: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms" parameters: assign: value: - matchExpressions: - key: "tenant" operator: In values: - "tenants-x"

上述政策會套用至 Kubernetes API 伺服器請求,以將 Pod 套用至 tenants-x 命名空間。政策會新增requiredDuringSchedulingIgnoredDuringExecution節點親和性規則,以便將 Pod 吸引到具有 tenant: tenants-x標籤的節點。

第二個政策如下所示,使用目標命名空間和群組、種類和版本的相同相符條件,將容錯新增至相同的 Pod 規格。

apiVersion: mutations.gatekeeper.sh/v1alpha1 kind: Assign metadata: name: mutator-add-toleration-pod annotations: aws-eks-best-practices/description: >- Adds toleration - https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ spec: applyTo: - groups: [""] kinds: ["Pod"] versions: ["v1"] match: namespaces: ["tenants-x"] location: "spec.tolerations" parameters: assign: value: - key: "tenant" operator: "Equal" value: "tenants-x" effect: "NoSchedule"

上述政策專屬於 Pod;這是因為政策元素中變動location元素的路徑所致。可以撰寫其他政策來處理建立 Pod 的資源,例如部署和任務資源。本指南的配套 GitHub 專案中可以看到列出的政策和其他範例。

這兩個變動的結果是 Pod 會吸引到所需的節點,同時不會被特定節點污點排斥。為了驗證這一點,我們可以看到來自兩個kubectl呼叫的輸出片段,以取得標記為 的節點tenant=tenants-x,並在tenants-x命名空間中取得 Pod。

kubectl get nodes -l tenant=tenants-x NAME ip-10-0-11-255... ip-10-0-28-81... ip-10-0-43-107... kubectl -n tenants-x get pods -owide NAME READY STATUS RESTARTS AGE IP NODE tenant-test-deploy-58b895ff87-2q7xw 1/1 Running 0 13s 10.0.42.143 ip-10-0-43-107... tenant-test-deploy-58b895ff87-9b6hg 1/1 Running 0 13s 10.0.18.145 ip-10-0-28-81... tenant-test-deploy-58b895ff87-nxvw5 1/1 Running 0 13s 10.0.30.117 ip-10-0-28-81... tenant-test-deploy-58b895ff87-vw796 1/1 Running 0 13s 10.0.3.113 ip-10-0-11-255... tenant-test-pod 1/1 Running 0 13s 10.0.35.83 ip-10-0-43-107...

如以上輸出所示,所有 Pod 都會排程在標有 的節點上tenant=tenants-x。簡言之,Pod 只會在所需的節點上執行,而其他 Pod (沒有必要的親和性與容錯能力) 則不會執行。租用戶工作負載已有效隔離。

範例變動 Pod 規格如下所示。

apiVersion: v1 kind: Pod metadata: name: tenant-test-pod namespace: tenants-x spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: tenant operator: In values: - tenants-x ... tolerations: - effect: NoSchedule key: tenant operator: Equal value: tenants-x ...
重要

與 Kubernetes API 伺服器請求流程整合的政策管理工具,使用變動和驗證許可 Webhook,旨在在特定時間範圍內回應 API 伺服器的請求。這通常為 3 秒或更短。如果 Webhook 呼叫無法在設定的時間內傳回回應,則傳入 API 伺服器請求的變動和/或驗證可能會發生,也可能不會發生。此行為是根據許可 Webhook 組態設定為 Fail Open 或 Fail Close

在上述範例中,我們使用為 OPA/Gatekeeper 撰寫的政策。不過,還有其他政策管理工具也會處理我們的節點選擇使用案例。例如,此 Kyverno 政策可用於處理節點親和性變動。

注意

如果操作正確,變動政策將影響對傳入 API 伺服器請求承載的所需變更。不過,在允許變更持續之前,也應包含驗證政策,以確認所需的變更是否發生。這在將這些政策用於tenant-to-node隔離時特別重要。也建議您包含稽核政策,以定期檢查叢集是否有不需要的組態。

參考

硬式多租戶

透過為每個租用戶佈建個別叢集,即可實作硬式多租用戶。雖然這在租用戶之間提供了非常強的隔離,但它有幾個缺點。

首先,當您有許多租戶時,這種方法可能會很快變得昂貴。您不僅必須支付每個叢集的控制平面成本,也無法在叢集之間共用運算資源。這最終會導致分段,其中您的叢集子集未充分利用,而其他叢集則過度利用。

其次,您可能需要購買或建置特殊工具來管理所有這些叢集。隨著時間的推移,管理數百個或數千個叢集可能變得過於難以理解。

最後,相對於建立命名空間,為每個租用戶建立叢集的速度會很慢。不過,在高度管制的產業或需要高度隔離的 SaaS 環境中,可能需要硬租用方法。

未來方向

Kubernetes 社群已識別軟式多租用戶目前的缺點,以及硬式多租用戶的挑戰。多租戶特殊興趣群組 (SIG) 正嘗試透過數個孵化專案解決這些缺點,包括階層式命名空間控制器 (HNC) 和虛擬叢集。

HNC 提案 (KEP) 描述了一種在具有 【政策】 物件繼承的命名空間之間建立父子關係的方法,以及租用戶管理員建立子命名空間的能力。

虛擬叢集提案說明為叢集內的每個租用戶 (也稱為「Kubernetes on Kubernetes」) 建立控制平面服務個別執行個體的機制,包括 API 伺服器、控制器管理員和排程器。

多租戶基準提案提供使用命名空間進行隔離和分割的共享叢集準則,以及驗證是否符合準則的命令列工具 kubectl-mtb

多叢集管理工具和資源