歡迎光臨
每天分享高質量文章

Kubernetes叢集安全最佳實踐

 

這是題為《保護Kubernetes for Cloud Native Applications》系列文章的倒數第二篇,延續我們關於如何保護叢集重要元件的討論,如API server和 Kubelet。 在本文中,我們將使用叢集的一些固有安全機制來解決如何應用安全控制的最佳實踐問題。如果將Kubernetes比作核心,那麼我們將討論保護使用者空間,位於核心之上的層,也就是我們的工作負載執行的地方。讓我們從身份驗證開始。

 

身份驗證(Authentication)

 

我們在上一篇文章中討論了對Kubernetes API伺服器的身份驗證,主要是在配置它以禁用匿名身份驗證方面。Kubernetes中有許多不同的認證方案,所以讓我們深入研究一下。
X.509 Certificates
X.509證書是使用TLS加密與API伺服器的任何客戶端通訊的必需元件。X.509證書也可以用作使用API伺服器進行身份驗證的方法之一,其中客戶端的身份在證書的屬性中提供:公共名稱(Common Name)提供使用者名稱,而可變數量的組織屬性提供身份屬於哪個組。
X.509證書是經過驗證的身份驗證方法,但在Kubernetes的背景關係中有一些限制:
  • 如果身份不再有效(可能是個人已離開您的組織),則可能需要撤銷與該身份相關聯的證書。目前,Kubernetes無法透過證書吊銷串列(CRL)或使用線上證書狀態協議(OSCP)的響應來查詢證書的有效性。有幾種方法可以解決這個問題(例如,重新建立CA並重新發出每個客戶端證書),或者可能會認為依賴於授權步驟就足以拒絕已經使用已撤銷證書進行身份驗證的常規使用者的訪問許可權。這意味著我們應該謹慎選擇證書的Organization屬性中的組。 如果我們無法撤銷的證書包含一個具有無法刪除的關聯預設系結的組(例如,system:masters),那麼我們就不能依賴授權步驟來阻止訪問。

  • 如果要管理大量身份,則頒發和輪換證書的任務變得繁重。在這種情況下,除非涉及一定程度的自動化,否則開銷可能變得過高。

OpenID Connect
另一種日益流行的客戶端身份驗證方法是利用內建的Kubernetes對OpenID Connect(OIDC)的支援,以及由外部身份提供商提供的身份驗證。OpenID Connect是一個位於OAuth 2.0之上的身份驗證層,它使用JSON Web令牌(JWT)對使用者的身份及其宣告進行編碼。身份提供者提供的ID令牌(儲存為使用者的kubeconfig的一部分)在每次使用者嘗試API請求時作為承載令牌提供。由於ID令牌無法撤銷,因此它們的生命週期往往較短,這意味著它們只能在有效期內用於身份驗證。通常,還會向用戶發放掃清令牌——可以與ID令牌一起儲存 – 並用於在到期時獲取新的ID令牌。
正如我們可以將使用者名稱及其關聯組體現為X.509證書的屬性一樣,我們也可以使用JWT ID令牌完全相同。這些屬性與令牌中體現的身份宣告相關聯,並使用kube-apiserver的配置選項進行對映。
Kubernetes可以配置為使用幾種流行的OIDC身份提供商中的任何一種,例如Google Identity Platform和Azure Active Directory。但是,如果您的組織使用目錄服務(例如LDAP)來儲存使用者身份,會發生什麼?一種基於OIDC的解決方案,支援LDAP身份驗證,是一種開源的Dex身份服務,透過“聯結器”充當許多型別的身份提供者的身份驗證中介。除了LDAP之外,Dex還為使用OAuth的GitHub,GitLab和Microsoft帳戶提供聯結器。(如果你想深入快速學習Kubernetes,可以報名參加我們組織的為期3天的Kubernetes實戰培訓,一線資深講師帶你從0開始上手Kubernetes。)

 

授權

 

我們不應該單獨依靠身份驗證來控制對API伺服器的訪問,這種“一刀切”的方式,在控制對叢集的資源的訪問時過於粗略。因此,Kubernetes根據API伺服器上配置的授權樣式,提供了對經過身份驗證的API請求進行授權審查的方法。我們在前一篇文章中討論過配置API伺服器授權樣式。
雖然可以將授權推遲到外部授權機制,但Kubernetes的事實上的標準授權樣式是內建的基於角色的訪問控制(RBAC)模組。由於大多數預打包的應用程式清單都預先定義了RBAC角色和系結,所以除非有充分的理由使用替代方法,否則RBAC應該是授權API請求的首選方法。
RBAC透過定義角色來實現,然後角色使用“角色系結(role bindings)”系結到主題。讓我們對這些術語進行一些解釋。
Roles(角色)——定義可以對哪些物件執行哪些操作。 該角色可以限制在特定的名稱空間中,在這種情況下,它可以在Role物件中定義,也可以是在ClusterRole物件中定義的叢集範圍的角色。在以下示例叢集範圍角色中,系結到角色的主體可以對“pods”和“pods/log”資源物件執行get和list操作——不多也不少:
  1. kind: ClusterRole
  2. apiVersion: rbac.authorization.k8s.io/v1
  3. metadata:
  4. name: pod-and-pod-logs-reader
  5. rules:
  6. - apiGroups: [""]
  7. resources: ["pods", "pods/log"]
  8. verbs: ["get", "list"]
如果這是一個名稱空間角色,那麼物件型別將是Role而不是ClusterRole,並且元資料部分中將存在具有關聯值的名稱空間鍵。
Role Bindings(角色系結)——將角色系結到一組主題。 RoleBinding物件將Role或ClusterRole系結到特定名稱空間範圍內的主題,而ClusterRoleBinding將ClusterRole系結到叢集範圍內的主題。
Subjects(主題)——使用者和組(由合適的身份驗證方案提供),以及服務帳戶(Service Account),它們是用於提供需要訪問Kubernetes API的Pod的API物件,具有標識。
在考慮應該在角色中定義的訪問級別時,始終遵循最小特權原則。換句話說,只提供具有實現其目的絕對必要的訪問權的角色。從實際角度來看,在建立新角色的定義時,更容易從現有角色(例如,編輯角色)開始,並刪除所有不需要的角色。如果您發現配置過於嚴格,並且需要確定哪些角色需要為特定操作或一組操作建立,則可以使用audit2rbac[1],它將根據從API伺服器觀察到的審核日誌自動生成必要的角色和角色系結。
在透過服務帳戶為Pod執行的應用程式提供API訪問時,可能很容易將新角色系結到為每個名稱空間建立的預設服務帳戶,該帳戶可供名稱空間中的每個Pod使用。我們應該為需要API訪問的Pod建立特定服務帳戶和角色,然後將該角色系結到新的服務帳戶。
顯然,仔細考慮誰需要訪問API伺服器,API的哪些部分以及它們可以透過API執行哪些操作,對於維護安全的Kubernetes叢集至關重要。給它時間和應有的關註,如果你需要一些額外的幫助,Giant Swarm有一些你可能會覺得有用的深入檔案[2]。
Pod安全策略

 

作為Pod的組成部分,容器通常配置有非常實用的安全預設值,這些預設值適用於大多數典型用例。但是,通常,Pod可能需要其他許可權才能執行其預期任務——例如,網路外掛或用於監視或記錄的代理。在這種情況下,我們需要增強Pod的預設許可權,但將不需要增強許可權的Pod限製為更嚴格的許可權集。 我們可以並且絕對應該這樣做,方法是啟用PodSecurityPolicy許可控制器,並使用Pod安全策略API定義策略。
Pod安全策略定義了Pod傳遞許可所需的安全配置,允許在叢集中建立或更新它們。 控制器將Pod的已定義安全背景關係與Pod的建立者(部署或使用者)允許“使用”的任何策略進行比較,並且在安全背景關係超出策略的情況下,它將拒絕建立或更新Pod。該策略還可用於透過定義最小限制策略來提供預設值,該策略可系結到非常通用的授權組,例如system:authenticated(適用於所有經過身份驗證的使用者),以限制這些使用者具有的訪問許可權到API伺服器。
Pod安全域
可以在PodSecurityPolicy(PSP)物件中定義相當多的可配置安全選項,您選擇定義的策略將非常依賴於工作負載的性質和組織的安全狀態。以下是API物件的一些示例欄位:
  • privileged:指定Pod是否可以在特權樣式下執行,允許它訪問主機的裝置,這在正常情況下無法執行。

  • allowedHostPaths:在主機上提供檔案系統路徑的白名單,Pod可以將其用作hostPath捲。

  • runAsUser:允許控制執行pod容器的UID。

  • allowedCapabilities:將提供的功能列入白名單,這些功能可以新增到提供給Pod容器的預設串列之上。

 
利用Pod安全策略
啟用PodSecurityPolicy許可控制器時的警告: 除非已在PSP中定義了策略,否則將無法建立容器,因為許可控制器(admission controller)的預設行為是拒絕建立不存在與策略匹配的容器——無策略,不匹配。 Pod安全策略API是獨立於許可控制器(admission controller)啟用的,因此完全可以在啟用它之前定義策略。
值得指出的是,與RBAC不同,預先打包的應用程式很少在其清單中包含PSP,這意味著這些應用程式的使用者需要建立必要的策略。
一旦定義了PSP,它們就不能用於驗證Pod,除非建立Pod的使用者或與Pod關聯的服務帳戶有權使用該策略。許可權授權通常都是透過RBAC來實現的,透過定義允許使用特定PSP的角色以及將角色系結到使用者和/或服務帳戶的角色系結來實現授予許可權。
從實際角度來看——特別是在生產環境中,使用者不太可能直接建立Pod。 作為更高階別工作負載抽象的一部分(例如部署Deployment),通常會建立Pod,因此,它是與Pod關聯的服務帳戶,需要角色才能使用任何給定的PSP。
Giant Swarm的檔案[2]再次提供了一些關於使用PSP為應用程式提供特權訪問的深刻解釋。

 

隔離工作負載

 

在大多數情況下,Kubernetes叢集被建立為執行多個不同且通常不相關的應用程式工作負載的通用資源。 以這種方式共同租用工作負載帶來了巨大的好處,但同時可能會增加與這些工作負載及其相關資料意外或故意暴露於不可信來源相關的風險。 組織策略,甚至監管要求,可能需要將部署的服務與任何其他不相關的服務進行隔離。
當然,確保這一點的一種方法是將敏感應用程式隔離到其自己的叢集中。 在單獨的叢集中執行應用程式可確保最高程度地隔離應用程式。但是,有時候,這種程度的隔離可能不是絕對必要的,而且我們可以使用Kubernetes中提供的一些內建隔離功能。 我們來看看這些內建隔離功能。
名稱空間
名稱空間是Kubernetes中的一種機制,用於為您可能認為相關的所有物件提供不同的環境,並且需要與其他不相關的物件分開。 它們提供了分割槽工作負載,團隊,環境,客戶以及您認為值得隔離的任何事物的方法。
通常,建立Kubernetes叢集時預設初始化了三個預設名稱空間:
  • kube-system:用於由Kubernetes自己建立的物件。

  • kube-public:用於公開可用的可讀物件。

  • default:用於在沒有與特定名稱空間顯式關聯的情況下建立的所有物件。

 

為了有效地使用名稱空間——而不是讓每個物件最終都在預設名稱空間中——應該建立名稱空間並用於根據其預期目的隔離物件。名稱空間物件沒有正確或錯誤的方式,很大程度上取決於組織的特定要求。一些仔細的規劃可以讓你以後節省大量的重新設計工作,因此預先給予應有的考慮是值得的。一些需要考慮的想法可能包括:組織的不同團隊和/或領域,諸如開發,QA,staging和production之類的環境,不同的應用程式工作負載,以及可能在共同租賃的場景中的不同客戶。以分層方式規劃名稱空間可能很誘人,但名稱空間具有扁平結構,因此不可能這樣做。相反,您可以為推斷的層次結構提供合適的名稱空間名稱,例如teamA-appY和teamB-appZ。
採用名稱空間來隔離工作負載也有助於管理叢集資源的使用。如果我們將叢集視為隔離為不同名稱空間的共享計算資源,則可以在每個名稱空間的基礎上應用資源配額。Resource Hungry和明智地透過名稱空間來隔離關鍵工作負載可以最大化利用共享資源。

 

網路策略

 

開箱即用:Kubernetes允許來自叢集中任何容器的所有網路流量傳送到叢集中的任何其他容器並由其接收。當我們嘗試隔離工作負載時,這種開放式方法對我們沒有幫助,因此我們需要應用網路策略來幫助我們實現所需的隔離。
Kubernetes NetworkPolicy API使我們能夠將入口和出口規則應用於選定的Pod,用於第3層和第4層流量,並依賴於實現容器網路介面(CNI)的相容網路外掛的部署。並非所有Kubernetes網路外掛都支援網路策略,但流行的選擇(如Calico,Weave Net和Romana)都可以。
網路策略是名稱空間作用域,並根據匹配標簽(例如,tier:backend)的選擇應用於Pod。當NetworkPolicy物件的Pod選擇器與Pod匹配時,根據策略中定義的入口和出口規則來管理進出Pod的流量。 所有來自或發往該Pod的流量都會被拒絕,除非有允許它的規則。
要在Kubernetes叢集中正確隔離網路和傳輸層的應用程式,網路策略應以“拒絕所有”的預設前提開始。然後,應將每個應用程式元件及其所需源和標的的規則逐個列入白名單,併進行測試以確保流量樣式按預期工作。

 

Service-to-Service的安全

 

網路策略正是我們對第3/4層流量隔離所需要的,但是如果我們還能確保我們的應用服務可以相互驗證,它們的通訊是加密的。我們得有用於服務內互動的細粒度訪問控制。
幫助我們實現這一標的的解決方案依賴於應用於網路堆疊5-7層的策略,並且是雲原生應用程式的開發功能。Istio就是這樣一種工具,其目的是將應用程式工作負載管理為服務網格,包括: 高階流量管理和服務可觀察性,以及基於策略的身份驗證和授權。Istio將一個sidecar容器部署到每個Pod艙中,該Pod基於Envoy反向代理。Sidecar容器形成網格,並且考慮到定義的流量規則和安全策略,以及來自不同服務的Pod之間的代理流量。
Istio的服務到服務通訊的認證機制基於雙向TLS,服務物體的身份體現在X.509證書中。這些身份符合每個人的安全生產身份框架(SPIFFE)規範,該規範旨在提供向工作負載釋出身份的標準。 SPIFFE是由Cloud Native Computing Foundation(CNCF)託管的專案。
Istio具有極其強大的功能,但是它的功能套件並非都是必需的,部署帶來的運營開銷和維護可能會超過它所帶來的好處。基於SPIFFE的經過身份驗證的服務標識的替代解決方案是SPIRE,一組用於建立和釋出標識的開源工具。
另一個用於保護Kubernetes叢集中服務之間通訊的解決方案是開源Cilium專案,該專案使用Linux核心中的伯克利資料包過濾器(BPF)來為第7層流量實施定義的安全策略。 除了HTTP之外,Cilium還支援其他第7層協議,如Kafka和gRPC。

 

總結

 

與Kubernetes堆疊中的每個層一樣,從安全形度來看,在使用者空間層中也需要考慮大量問題。Kubernetes是將安全作為一類公民建立的,各種固有的安全控制以及與第三方安全工具介面的機制提供了全面的安全功能。
然而,這不僅僅是關於定義策略和規則。同樣重要的是確保以及滿足組織更廣泛的安全標的,您的安全配置支援著您的團隊的組織方式以及他們的工作方式。這需要仔細考慮和規劃。
在本系列的下一篇也就是最後一篇文章《管理Kubernetes容器工作負載的安全性》中,我們將討論與容器工作負載內容相關的安全性,以及如何將安全性作為端到端工作流的一部分。
相關連結:
  1. https://github.com/liggitt/audit2rbac

  2. https://docs.giantswarm.io/guides/securing-with-rbac-and-psp

原文連結:https://blog.giantswarm.io/applying-best-practice-security-controls-to-a-kubernetes-cluster/
贊(0)

分享創造快樂