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

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)

分享創造快樂