做者 | 匡大虎 阿里巴巴技術專家node
本文整理自《CNCF x Alibaba 雲原生技術公開課》第 27 講,點擊直達課程頁面。docker
關注「阿里巴巴雲原生」公衆號,回覆關鍵詞**「入門」**,便可下載從零入門 K8s 系列文章 PPT。api
**導讀:**訪問控制是雲原生安全的一個重要組成部分,也是 K8s 集羣在多租環境下必要且基本的安全加固手段。在 K8s 體系中,訪問控制又分爲三個重要的組成部分,請求認證,鑑權和運行時刻的 admission 准入控制。在本文中,做者將帶領你們瞭解這 3 部分的基本定義和使用方法,並給出多租環境下安全加固的相關最佳實踐。安全
你們都知道訪問控制是雲原生安全中的一個重要組成部分。也是一個 Kubernetes 集羣在多租戶環境下必需要採起的一個基本的安全防禦手段。app
那麼在概念上能夠抽象的定義爲誰在何種條件下能夠對什麼資源作什麼操做。這裏的資源就是在 Kubernetes 中咱們熟知的:Pod、 ConfigMaps、Deployment、Secrets 等等這樣的資源模型。less
由上圖來介紹一下 Kubernetes API 的請求從發起到其持久化入庫的一個流程。微服務
首先看一下請求的發起,請求的發起分爲兩個部分:工具
當咱們的 apiserver 收到請求後,就會開啓訪問控制流程。這裏面分爲三個步驟:學習
Authentication 認證階段:判斷請求用戶是否爲可以訪問集羣的合法用戶。若是用戶是個非法用戶,那 apiserver 會返回一個 401 的狀態碼,並終止該請求;測試
若是用戶合法的話,咱們的 apiserver 會進入到訪問控制的第二階段 Authorization:鑑權階段。在該階段中 apiserver 會判斷用戶是否有權限進行請求中的操做。若是無權進行操做,apiserver 會返回 403 的狀態碼,並一樣終止該請求;
若是用戶有權進行該操做的話,訪問控制會進入到第三個階段:AdmissionControl。在該階段中 apiserver 的 admission controller 會判斷請求是不是一個安全合規的請求。若是最終驗證經過的話,訪問控制流程纔會結束。
此時咱們的請求將會轉換爲一個 Kubernetes objects 相應的變動請求,最終持久化到 ETCD 中。
對於認證來講,首先咱們要肯定請求的發起方是誰。並最終經過認證過程將其轉換爲一個系統可識別的用戶模型用於後期的鑑權,那麼先來看一下 Kubernetes 中的用戶模型。
什麼是用戶管理能力呢?咱們沒法像操做 Pod 同樣,經過 API 的方式建立刪除一個用戶實例。同時咱們也沒法在 ETCD 中找到用戶對應的存儲對象。
在 Kubernetes 的訪問控制流程中用戶模型是如何產生的呢?答案就在請求方的訪問控制憑證中,也就是咱們平時使用的 kube-config 中的證書,或者是 Pod 中引入的 ServerAccount。通過 Kubernetes 認證流程以後,apiserver 會將請求中憑證中的用戶身份轉化爲對應的 User 和 Groups 這樣的用戶模型。在隨後的鑑權操做和審計操做流程中,apiserver 都會使用到改用戶模型實例。
該認證方式下,管理員會將 Username 和 Password 組成的白名單放置在 apiserver 讀取的靜態配置文件上面進行認證,該方式通常用於測試場景,在安全方面是不推薦且不可拓展的一種方式。
該方式是 apiserver 中相對應用較多的使用方式,首先訪問者會使用由集羣 CA 簽發的,或是添加在 apiserver Client CA 中授信 CA 簽發的客戶端證書去訪問 apiserver。apiserver 服務端在接收到請求後,會進行 TLS 的握手流程。除了驗證證書的合法性,apiserver 還會校驗客戶端證書的請求源地址等信息。開啓雙向認證,X509 認證是一個比較安全的方式,也是 Kubernetes 組件之間默認使用的認證方式,同時也是 kubectl 客戶端對應的 kube-config 中常用到的訪問憑證。
該方式的 Tokens 是通用的 JWT 的形式,其中包含了簽發者、用戶的身份、過時時間等多種元信息。它的認證方式也是常見的私鑰加簽,公鑰驗籤的一個基本流程。基於 Token 的認證使用場景也很普遍,好比 Kubernetes Pod 應用中常用到的 Service Account,其中就會自動綁定一個簽名後的 JWT Token 用於請求 apiserver。
另外 apiserver 還支持基於 OpenID 協議的 Token 認證,能夠經過對 apiserver 的配置鏈接一個指定的外部 IDP,同時能夠經過 Keycloak,Dex 這樣的開源服務來管理 IDP,請求者能夠按照本身熟悉的方式在原身份認證服務上進行登陸認證,並最終返回一個相應的 JWT token,爲了後面的 apiserver 的鑑權流程。
除此以外,還可使用 Webhooks 的方式,將請求的 Token 發送到指定外部服務進行 Token 的驗籤。
對於一個集羣證書體系來講,認證機構 (CA) 是一個很是重要的證書對。它會被默認放置在集羣 Master 節點上的 /etc/Kubernetes/pki/ 目錄下。集羣中全部組件之間的通信用到的證書,其實都是由集羣根 CA 來簽發的。在證書中有兩個身份憑證相關的重要字段:一個是 CN,一個是 O。
另外能夠經過 openssl 命令來進行證書的解析。上圖右側能夠看到,經過 Subject 中的 O 和 CN 字段能夠查看對應的信息。
上面每個組件證書都有本身指定的 Common Name 和 Organization 用於特定角色的綁定。這樣的設置可使各系統組件只綁定自身功能範圍內的角色權限。從而保證了每一個系統組件自身權限的最小化。
Kubernetes 集羣自己就提供了證書籤發的 API,而在集羣的建立過程當中,像 kubeadm 這樣的集羣安裝工具,會基於不一樣的 CSR 簽發請求調用 apiserver 對應接口。此時 apiserver 會根據請求,以這種 csr 資源模型的形式建立對應的簽發請求實例。剛開始建立的簽發實例都會處於 pending 的狀態,直到有權限的管理員進行審批後,這個 csr 纔會處於 approved 的狀態,請求對應的證書就會被簽發。
經過上圖右側中的命令能夠來查看相應的證書內容信息。
首先開發人員需用經過 openssl 等證書工具生成私鑰,而後建立對應的 x509 csr 請求文件,須要在 subj 字段中指定用戶 user 和組 group,最後經過 API 建立 K8s csr 實例並等待管理員審批。
對於集羣管理員,他能夠直接讀取集羣根 CA,並經過 x509 的 csr 請求文件簽發證書,因此它無需定義或審批 csr 實例。上圖中最後一行是一個 openssl 簽發示例,命令中須要指明 csr 和 ca.crt 的文件路徑,以及簽發證書的過時時間信息。
另外各個雲廠商也會基於登陸用戶和目標集羣一鍵化生成對應的集羣訪問憑證,方便用戶的使用。
除了證書認證以外,Service Account 也是 apiserver 中應用比較普遍的一種方式。對於 Service Account 來講,它是 K8s 中惟一可以經過 API 方式管理的 APIService 訪問憑證,其餘特性在上圖中能夠看到。
圖中也給出了一些使用 kubectl 進行 Service Account API 相關增刪改查的示例,同時咱們能夠爲已經存在的 serviceaccount 手動建立其 token 對應的 secret,有興趣的同窗能夠在 Kubernetes 集羣中操做執行一下。
接着看一下 Service Account 的使用。
首先能夠經過 get secret –oyaml 命令查看 serviceaccount 對應的指定 secret,其中 token 字段即爲通過了 base64 編碼的 JWT 格式的認證 token。
在部署一個應用時,咱們能夠經過 template -> spec -> containers 中的 serviceAccountName 字段聲明須要使用的 Service Account 名稱。注意若是是在 Pod 建立過程當中,發現制定的 ServiceAccount 不存在,則該 Pod 建立過程會被終止。
在生成的 pod 模板中能夠看到指定 serviceaccount 對應的 secret 中的 ca,namespace 和認證 token 會以文件的形式掛載到容器中的指定目錄下。另外對於已經建立的 Pod,咱們不能更新其已經掛載的 ServiceAccount 內容。
kubeconfig 是用戶本地鏈接 Kubernetes 集羣使用的重要訪問憑證,接着來介紹一下 kubeconfig 的配置和使用。
當一個請求在完成 apiserver 認證後,能夠認爲它是一個合法的用戶,那麼如何控制該用戶在集羣中的哪些 namespace 中訪問哪些資源,對這些資源又能進行哪些操做呢?
這就由訪問控制的第二步 Kubernetes 鑑權來完成。apiserver 自己支持多種鑑權方式,在本節內容中,咱們主要介紹在安全上推薦的鑑權方式 RBAC。
這裏舉個例子,假設有個經過合法認證的用戶 Bob,他請求 list 某個 namespace下的 Pods,改請求的鑑權語義記爲:Can Bob list pods ?其中 Bob 即爲請求中的 Subject,list 爲對應的請求動做 Action,而 pods 爲對應的請求資源 Resource。
上面介紹了 RBAC 角色模型的三要素,在整個 RBAC 策略定義下,還須要將這個角色綁定到一個具體的控制域內。這就是 Kubernetes 你們熟悉的命名空間。經過 namespace 能夠將 Kubernetes api 資源限定在不一樣的做用域內。從而幫助咱們在一個多租戶集羣中,對用戶進行邏輯上的隔離。
上面的事例能夠改成 User A can create pods in namespace B。這裏須要注意的是,若是不進行任何的權限綁定,RBAC 會拒絕全部訪問。
一般 RBAC 會進行對 apiserver 的細粒度訪問控制,可是這個細粒度是個相對的概念,RBAC 是面向模型級別的綁定。它不能綁定到 namespace 中的一個具體的 object 實例,更不能綁定到指定資源的任意一個 field。
RBAC 對訪問權限的控制粒度上,它能夠細化到 Kubernetes api 的 subresources 級別。好比針對一個訪問者,咱們能夠控制其在指定 namespace 下對 nodes/status 模型的訪問。
接着介紹 RBAC 具體的綁定權限和對象。
首先是角色 Role,它定義了用戶在指定的 Kubernetes 命名空間資源上能夠進行哪些操做。好比能夠定一個 namespace 中 pod 的只讀權限,同時還能夠定義一個 namespace 管理員權限,它具備對這個命名空間下全部對象資源的全部操做權限。
如上圖所示,是一個 Role 的定義模板編排文件,其中 resource 字段定義了這個角色能夠訪問哪些資源,verbs 字段定義了這個角色有哪些操做的權限。在 apiGroups 中,須要指定目標資源的 apiGroups 名稱,這裏能夠經過官方 API 文檔查詢,若是指定的 Group 是 core,那麼在角色模板中的 apiGroups 可置爲空。
當咱們完成了一個 namespace 下的角色定義以後,還須要創建其與使用這個角色的主體之間在 namespace 下的綁定關係,這裏須要一個 RoleBinding 模型。使用 RoleBinding 能夠將 Role 對應的權限模型綁定到對應的 Subject 上。
好比這裏能夠將名爲 test 的 namespace 中的 pod 只讀權限同時綁定給用戶 test1 和 test2 以及 proc1。也能夠將 namespace test 只讀權限綁定 tech-lead group 中的 test1 用戶,這樣用戶 test2 和 proc1 是沒有 get namespace 權限的。
接着看一下對應的 RoleBinding 編排文件模板。
其中 roleRef 字段中聲明瞭咱們須要綁定的角色,一個綁定只能指定惟一的 Role。在 subject 字段中定義了咱們要綁定的對象,這裏能夠是 User,Group 或者是 Service Account。它同時支持綁定多個對象。
除了定義指定 namespace 中的權限模型,也能夠經過 ClusterRole 定義一個集羣維度的權限模型。在一個 Cluster 實例中,能夠定義集羣維度的權限使用權限,好比像 PV、Nodes 在 namespace 中不可見的資源權限,能夠在 ClusterRole 中定義,而操做這些資源的動做一樣是以前 Role 中支持的增刪改查和 list、watch 等操做。
下圖爲 ClusterRole 編排文件模板:
ClusterRole 編排文件幾乎和 Role 是如出一轍的,惟一不一樣的地方是 ClusterRole 中是全部集羣維度的權限定義,不支持 namespace 的定義。
一樣在 ClusterRole 的基礎上,能夠將其綁定在對應的 Subject 主體上。而 ClusterRoleBinding 模型實例能夠幫助咱們在集羣全部命名空間上將 ClusterRole 綁定到具體的 Subject 對象上。
好比這裏能夠將全部 namespace 的 list 權限綁定給 group 爲 sre 或者 devops 的管理員 admin1 和 admin2。
相比較於 RoleBinding,ClusterRoleBinding 模板定義也只是在 namespace 和 roleRef 中的權限對象模型定義上有不一樣,其餘的定義格式是同樣的。
經過上文的學習,咱們知道在不進行任何權限的綁定下,RABC 會拒絕全部的訪問。那麼咱們的系統組件之間是如何互相請求呢?
其實在集羣建立的時候,處理系統各組件的客戶端證書,它們各自的角色和環境對象也會被建立出來,以知足組件業務之間交互必須的權限要求。
下面看幾個預置的集羣角色:
經過以上對 RBAC 的學習,你們應該對 Kubernetes 中 RBAC 中的模型定義有了必定的瞭解,可是在某些複雜的多租戶業務場景下,如何在權限模板中針對各個 API 模型定義相應的動做策略,仍是須要必定的理論和實踐基礎的。而對一個應用開發人員來講,kubectl 可能更爲直觀和熟悉些,這裏也給出了一些 kubectl 操做和 RBAC 中的對應關係。
好比當咱們但願 edit 一個 deploy 的時候,須要在相應的角色模板中增長對 Deployment 資源的 get、patch 這樣的權限。若是但願 exec 到一個 pod 中,須要在相應的角色模板中增長對 pod 的 get 權限,以及針對 pod/exec 模型的 create 權限。
經過 docker hub 上的統計結果能夠看到,主流的業務鏡像有 82.4% 是以 root 用戶來啓動的。經過這個調查能夠看到對 Security Context 的相關使用是不容樂觀的。
通過對上面的分析結果能夠看出來,若是咱們可以對業務容器配置足夠安全的運行時刻參數,其實攻擊者很難有可乘之機。那麼咱們究竟應該在部署 Kubernetes 集羣中的業務容器作哪些 runtime 運行時刻的安全加固呢?
因爲 PSP 策略相對複雜一些,這裏介紹一下使用注意事項。
首先能夠經過 API 直接操做 PSP 的安全策略實例,如上圖左側是 PSP 策略支持的配置參數,包括特權容器,系統capabilities,運行時刻用戶 id 和文件系統權限等多種配置。你們也能夠在官方文檔找到各個參數的詳細說明。
而 PSP 的做用正是在業務容器運行前,基於這個策略校驗安全參數配置,若是不知足該安全策略,則禁止該 Pod 運行。
最後在 PSP 的使用上,咱們須要注意幾點,如上圖右側所示。
最後在對多租環境下,如何利用 Kubernetes 下原生的安全能力作安全加固作一個最佳實踐的小結。
本文主要內容就到此爲止了,這裏爲你們簡單總結一下要點:
「阿里巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的公衆號。」