從零開始入門 K8s | K8s 安全之訪問控制

0.png

作者 | 匡大虎   阿里巴巴技術專家

本文整理自《CNCF x Alibaba 雲原生技術公開課》第 27 講,點擊直達課程頁面

關注“阿里巴巴雲原生”公衆號,回覆關鍵詞**“入門”**,即可下載從零入門 K8s 系列文章 PPT。

**導讀:**訪問控制是雲原生安全的一個重要組成部分,也是 K8s 集羣在多租環境下必要且基本的安全加固手段。在 K8s 體系中,訪問控制又分爲三個重要的組成部分,請求認證,鑑權和運行時刻的 admission 准入控制。在本文中,作者將帶領大家瞭解這 3 部分的基本定義和使用方法,並給出多租環境下安全加固的相關最佳實踐。

一、Kubernetes API 請求訪問控制

訪問控制

大家都知道訪問控制是雲原生安全中的一個重要組成部分。也是一個 Kubernetes 集羣在多租戶環境下必須要採取的一個基本的安全防護手段。

1.png

那麼在概念上可以抽象的定義爲誰在何種條件下可以對什麼資源做什麼操作。這裏的資源就是在 Kubernetes 中我們熟知的:Pod、 ConfigMaps、Deployment、Secrets 等等這樣的資源模型。

Kubernetes API 請求

2.png

由上圖來介紹一下 Kubernetes API 的請求從發起到其持久化入庫的一個流程。

首先看一下請求的發起,請求的發起分爲兩個部分:

  • 第一個部分是人機交互的過程。 是大家非常熟悉的用 kubectl 對 apiserver 的一個請求過程;
  • 第二個部分是 Pod 中的業務邏輯與 apiserver 之間的交互。

當我們的 apiserver 收到請求後,就會開啓訪問控制流程。這裏面分爲三個步驟:

  • Authentication 認證階段:判斷請求用戶是否爲能夠訪問集羣的合法用戶。如果用戶是個非法用戶,那 apiserver 會返回一個 401 的狀態碼,並終止該請求;

  • 如果用戶合法的話,我們的 apiserver 會進入到訪問控制的第二階段 Authorization:鑑權階段。在該階段中 apiserver 會判斷用戶是否有權限進行請求中的操作。如果無權進行操作,apiserver 會返回 403 的狀態碼,並同樣終止該請求;

  • 如果用戶有權進行該操作的話,訪問控制會進入到第三個階段:AdmissionControl。在該階段中 apiserver 的 admission controller 會判斷請求是否是一個安全合規的請求。如果最終驗證通過的話,訪問控制流程纔會結束。

此時我們的請求將會轉換爲一個 Kubernetes objects 相應的變更請求,最終持久化到 ETCD 中。

二、Kubernetes 認證

Kubernetes 中的用戶模型

對於認證來說,首先我們要確定請求的發起方是誰。並最終通過認證過程將其轉換爲一個系統可識別的用戶模型用於後期的鑑權,那麼先來看一下 Kubernetes 中的用戶模型。

1. Kubernetes 沒有自身的用戶管理能力

什麼是用戶管理能力呢?我們無法像操作 Pod 一樣,通過 API 的方式創建刪除一個用戶實例。同時我們也無法在 ETCD 中找到用戶對應的存儲對象。

2. Kubernetes 中的用戶通常是通過請求憑證設置

在 Kubernetes 的訪問控制流程中用戶模型是如何產生的呢?答案就在請求方的訪問控制憑證中,也就是我們平時使用的 kube-config 中的證書,或者是 Pod 中引入的 ServerAccount。經過 Kubernetes 認證流程之後,apiserver 會將請求中憑證中的用戶身份轉化爲對應的 User 和 Groups 這樣的用戶模型。在隨後的鑑權操作和審計操作流程中,apiserver 都會使用到改用戶模型實例。

3、Kubernetes支持的請求認證方式主要包括:

  • Basic 認證

該認證方式下,管理員會將 Username 和 Password 組成的白名單放置在 apiserver 讀取的靜態配置文件上面進行認證,該方式一般用於測試場景,在安全方面是不推薦且不可拓展的一種方式。

  • X509 證書認證

該方式是 apiserver 中相對應用較多的使用方式,首先訪問者會使用由集羣 CA 簽發的,或是添加在 apiserver Client CA 中授信 CA 簽發的客戶端證書去訪問 apiserver。apiserver 服務端在接收到請求後,會進行 TLS 的握手流程。除了驗證證書的合法性,apiserver 還會校驗客戶端證書的請求源地址等信息。開啓雙向認證,X509 認證是一個比較安全的方式,也是 Kubernetes 組件之間默認使用的認證方式,同時也是 kubectl 客戶端對應的 kube-config 中經常使用到的訪問憑證。

  • Bearer Tokens(JSON Web Tokens)
    • Service Account
    • OpenID Connect
    • Webhooks

該方式的 Tokens 是通用的 JWT 的形式,其中包含了簽發者、用戶的身份、過期時間等多種元信息。它的認證方式也是常見的私鑰加簽,公鑰驗籤的一個基本流程。基於 Token 的認證使用場景也很廣泛,比如 Kubernetes Pod 應用中經常使用到的 Service Account,其中就會自動綁定一個簽名後的 JWT Token 用於請求 apiserver。

另外 apiserver 還支持基於 OpenID 協議的 Token 認證,可以通過對 apiserver 的配置連接一個指定的外部 IDP,同時可以通過 Keycloak,Dex 這樣的開源服務來管理 IDP,請求者可以按照自己熟悉的方式在原身份認證服務上進行登錄認證,並最終返回一個相應的 JWT token,爲了後面的 apiserver 的鑑權流程。

除此之外,還可以使用 Webhooks 的方式,將請求的 Token 發送到指定外部服務進行 Token 的驗籤。

X509 證書認證

3.png

對於一個集羣證書體系來說,認證機構 (CA) 是一個非常重要的證書對。它會被默認放置在集羣 Master 節點上的 /etc/Kubernetes/pki/ 目錄下。集羣中所有組件之間的通訊用到的證書,其實都是由集羣根 CA 來簽發的。在證書中有兩個身份憑證相關的重要字段:一個是 CN,一個是 O。

另外可以通過 openssl 命令來進行證書的解析。上圖右側可以看到,通過 Subject 中的 O 和 CN 字段可以查看對應的信息。

4.png

上面每一個組件證書都有自己指定的 Common Name 和 Organization 用於特定角色的綁定。這樣的設置可以使各系統組件只綁定自身功能範圍內的角色權限。從而保證了每個系統組件自身權限的最小化。

證書籤發 API

5.png

Kubernetes 集羣本身就提供了證書籤發的 API,而在集羣的創建過程中,像 kubeadm 這樣的集羣安裝工具,會基於不同的 CSR 簽發請求調用 apiserver 對應接口。此時 apiserver 會根據請求,以這種 csr 資源模型的形式創建對應的簽發請求實例。剛開始創建的簽發實例都會處於 pending 的狀態,直到有權限的管理員進行審批後,這個 csr 纔會處於 approved 的狀態,請求對應的證書就會被簽發。

通過上圖右側中的命令可以來查看相應的證書內容信息。

簽發用戶證書

6.png

首先開發人員需用通過 openssl 等證書工具生成私鑰,然後創建對應的 x509 csr 請求文件,需要在 subj 字段中指定用戶 user 和組 group,最後通過 API 創建 K8s csr 實例並等待管理員審批。

對於集羣管理員,他可以直接讀取集羣根 CA,並通過 x509 的 csr 請求文件簽發證書,所以它無需定義或審批 csr 實例。上圖中最後一行是一個 openssl 簽發示例,命令中需要指明 csr 和 ca.crt 的文件路徑,以及簽發證書的過期時間信息。

另外各個雲廠商也會基於登錄用戶和目標集羣一鍵化生成對應的集羣訪問憑證,方便用戶的使用。

Service Account

7.png

除了證書認證之外,Service Account 也是 apiserver 中應用比較廣泛的一種方式。對於 Service Account 來說,它是 K8s 中唯一能夠通過 API 方式管理的 APIService 訪問憑證,其他特性在上圖中可以看到。

圖中也給出了一些使用 kubectl 進行 Service Account API 相關增刪改查的示例,同時我們可以爲已經存在的 serviceaccount 手動創建其 token 對應的 secret,有興趣的同學可以在 Kubernetes 集羣中操作執行一下。

接着看一下 Service Account 的使用。

8.png

首先可以通過 get secret –oyaml 命令查看 serviceaccount 對應的指定 secret,其中 token 字段即爲經過了 base64 編碼的 JWT 格式的認證 token。

9.png

在部署一個應用時,我們可以通過 template -> spec -> containers 中的 serviceAccountName 字段聲明需要使用的 Service Account 名稱。注意如果是在 Pod 創建過程中,發現制定的 ServiceAccount 不存在,則該 Pod 創建過程會被終止。

在生成的 pod 模板中可以看到指定 serviceaccount 對應的 secret 中的 ca,namespace 和認證 token 會以文件的形式掛載到容器中的指定目錄下。另外對於已經創建的 Pod,我們不能更新其已經掛載的 ServiceAccount 內容。

生成 kubeconfig

kubeconfig 是用戶本地連接 Kubernetes 集羣使用的重要訪問憑證,接着來介紹一下 kubeconfig 的配置和使用。

10.png

使用 kubeconfig

11.png

三、Kubernetes 鑑權 - RBAC

當一個請求在完成 apiserver 認證後,可以認爲它是一個合法的用戶,那麼如何控制該用戶在集羣中的哪些 namespace 中訪問哪些資源,對這些資源又能進行哪些操作呢?

這就由訪問控制的第二步 Kubernetes 鑑權來完成。apiserver 本身支持多種鑑權方式,在本節內容中,我們主要介紹在安全上推薦的鑑權方式 RBAC。

RBAC 鑑權三要素

12.png

  • 第一要素是 Subjects,也就是主體。可以是開發人員、集羣管理員這樣的自然人,也可以是系統組件進程,或者是 Pod 中的邏輯進程;
  • 第二個要素是 API Resource,也就是請求對應的訪問目標。在 Kubernetes 集羣中也就是各類資源;
  • 第三要素是 Verbs,對應爲請求對象資源可以進行哪些操作,包括增刪改查、list、get、watch 等。

這裏舉個例子,假設有個通過合法認證的用戶 Bob,他請求 list 某個 namespace下的 Pods,改請求的鑑權語義記爲:Can Bob list pods ?其中 Bob 即爲請求中的 Subject,list 爲對應的請求動作 Action,而 pods 爲對應的請求資源 Resource。

RBAC 權限粒度

上面介紹了 RBAC 角色模型的三要素,在整個 RBAC 策略定義下,還需要將這個角色綁定到一個具體的控制域內。這就是 Kubernetes 大家熟悉的命名空間。通過 namespace 可以將 Kubernetes api 資源限定在不同的作用域內。從而幫助我們在一個多租戶集羣中,對用戶進行邏輯上的隔離。

13.png

上面的事例可以改爲 User A can create pods in namespace B。這裏需要注意的是,如果不進行任何的權限綁定,RBAC 會拒絕所有訪問。

通常 RBAC 會進行對 apiserver 的細粒度訪問控制,但是這個細粒度是個相對的概念,RBAC 是面向模型級別的綁定。它不能綁定到 namespace 中的一個具體的 object 實例,更不能綁定到指定資源的任意一個 field。

RBAC 對訪問權限的控制粒度上,它可以細化到 Kubernetes api 的 subresources 級別。比如針對一個訪問者,我們可以控制其在指定 namespace 下對 nodes/status 模型的訪問。

RBAC - Role

接着介紹 RBAC 具體的綁定權限和對象。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iBvDrwVz-1584426168152)(https://ucc.alicdn.com/pic/developer-ecology/01beaacec5d840d38a96bd4d916ed5f3.png)]

首先是角色 Role,它定義了用戶在指定的 Kubernetes 命名空間資源上可以進行哪些操作。比如可以定一個 namespace 中 pod 的只讀權限,同時還可以定義一個 namespace 管理員權限,它具有對這個命名空間下所有對象資源的所有操作權限。

15.png

如上圖所示,是一個 Role 的定義模板編排文件,其中 resource 字段定義了這個角色可以訪問哪些資源,verbs 字段定義了這個角色有哪些操作的權限。在 apiGroups 中,需要指定目標資源的 apiGroups 名稱,這裏可以通過官方 API 文檔查詢,如果指定的 Group 是 core,那麼在角色模板中的 apiGroups 可置爲空。

RBAC - RoleBinding

當我們完成了一個 namespace 下的角色定義之後,還需要建立其與使用這個角色的主體之間在 namespace 下的綁定關係,這裏需要一個 RoleBinding 模型。使用 RoleBinding 可以將 Role 對應的權限模型綁定到對應的 Subject 上。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-NjD7AJtS-1584426168154)(https://ucc.alicdn.com/pic/developer-ecology/ac786cf7af6247ca9fbb3afdfc0766c8.png)]

比如這裏可以將名爲 test 的 namespace 中的 pod 只讀權限同時綁定給用戶 test1 和 test2 以及 proc1。也可以將 namespace test 只讀權限綁定 tech-lead group 中的 test1 用戶,這樣用戶 test2 和 proc1 是沒有 get namespace 權限的。

接着看一下對應的 RoleBinding 編排文件模板。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-M3VWRa2C-1584426168155)(https://ucc.alicdn.com/pic/developer-ecology/c61559198cc44eef8417630bb052655d.png)]

其中 roleRef 字段中聲明瞭我們需要綁定的角色,一個綁定只能指定唯一的 Role。在 subject 字段中定義了我們要綁定的對象,這裏可以是 User,Group 或者是 Service Account。它同時支持綁定多個對象。

RBAC - ClusterRole

18.png

除了定義指定 namespace 中的權限模型,也可以通過 ClusterRole 定義一個集羣維度的權限模型。在一個 Cluster 實例中,可以定義集羣維度的權限使用權限,比如像 PV、Nodes 在 namespace 中不可見的資源權限,可以在 ClusterRole 中定義,而操作這些資源的動作同樣是之前 Role 中支持的增刪改查和 list、watch 等操作。

下圖爲 ClusterRole 編排文件模板:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ewlF394Q-1584426168157)(https://ucc.alicdn.com/pic/developer-ecology/cb8bbadcc7f04c91bd8e0b8f3d1b335d.png)]

ClusterRole 編排文件幾乎和 Role 是一模一樣的,唯一不同的地方是 ClusterRole 中是所有集羣維度的權限定義,不支持 namespace 的定義。

RBAC - ClusterRoleBinding

同樣在 ClusterRole 的基礎上,可以將其綁定在對應的 Subject 主體上。而 ClusterRoleBinding 模型實例可以幫助我們在集羣所有命名空間上將 ClusterRole 綁定到具體的 Subject 對象上。

20.png

比如這裏可以將所有 namespace 的 list 權限綁定給 group 爲 sre 或者 devops 的管理員 admin1 和 admin2。

21.png

相比較於 RoleBinding,ClusterRoleBinding 模板定義也只是在 namespace 和 roleRef 中的權限對象模型定義上有不同,其他的定義格式是一樣的。

RABC - Default ClusterRoleBinding

通過上文的學習,我們知道在不進行任何權限的綁定下,RABC 會拒絕所有的訪問。那麼我們的系統組件之間是如何互相請求呢?

其實在集羣創建的時候,處理系統各組件的客戶端證書,它們各自的角色和環境對象也會被創建出來,以滿足組件業務之間交互必須的權限要求。

下面看幾個預置的集羣角色:

22.png

角色中的 verbs 如何設置?

通過以上對 RBAC 的學習,大家應該對 Kubernetes 中 RBAC 中的模型定義有了一定的瞭解,但是在某些複雜的多租戶業務場景下,如何在權限模板中針對各個 API 模型定義相應的動作策略,還是需要一定的理論和實踐基礎的。而對一個應用開發人員來說,kubectl 可能更爲直觀和熟悉些,這裏也給出了一些 kubectl 操作和 RBAC 中的對應關係。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-zGWU98Lr-1584426168160)(https://ucc.alicdn.com/pic/developer-ecology/692c540aa34d4fa1b540477891efd7ba.png)]

比如當我們希望 edit 一個 deploy 的時候,需要在相應的角色模板中增加對 Deployment 資源的 get、patch 這樣的權限。如果希望 exec 到一個 pod 中,需要在相應的角色模板中增加對 pod 的 get 權限,以及針對 pod/exec 模型的 create 權限。

四、Security Context 的使用

CVE-2019-5736

24.png

通過 docker hub 上的統計結果可以看到,主流的業務鏡像有 82.4% 是以 root 用戶來啓動的。通過這個調查可以看到對 Security Context 的相關使用是不容樂觀的。

Kubernetes Runtime 安全策略

經過對上面的分析結果可以看出來,如果我們能夠對業務容器配置足夠安全的運行時刻參數,其實攻擊者很難有可乘之機。那麼我們究竟應該在部署 Kubernetes 集羣中的業務容器做哪些 runtime 運行時刻的安全加固呢?

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-69gRIoN2-1584426168162)(https://ucc.alicdn.com/pic/developer-ecology/aa8e4294027c4c6fa02316abee8f3802.png)]

  • 首先還是要遵循權限最小化原則,除了業務運行所必需的系統權限,其他權限都是可以去除的;
  • 此外還可以通過在 pod 或者 container 維度設置 Security Context 參數,進行業務容器運行時刻的安全配置;
  • 另外就是可以通過開啓 Pod Security Policy,在 apiserver 請求的 Admission 階段強制校驗容器的安全配置;
  • 除了 PSP 的開啓之外,如上圖還列舉了常見的,使用比較多的配置參數。

Pod Security Policy

由於 PSP 策略相對複雜一些,這裏介紹一下使用注意事項。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-vOZOICze-1584426168163)(https://ucc.alicdn.com/pic/developer-ecology/5f7983ede5b143ca890f0184442ce80c.png)]

首先可以通過 API 直接操作 PSP 的安全策略實例,如上圖左側是 PSP 策略支持的配置參數,包括特權容器,系統capabilities,運行時刻用戶 id 和文件系統權限等多種配置。大家也可以在官方文檔找到各個參數的詳細說明。

而 PSP 的作用正是在業務容器運行前,基於這個策略校驗安全參數配置,如果不滿足該安全策略,則禁止該 Pod 運行。

最後在 PSP 的使用上,我們需要注意幾點,如上圖右側所示。

五、總結 - 多租安全加固

最後在對多租環境下,如何利用 Kubernetes 下原生的安全能力做安全加固做一個最佳實踐的小結。

27.png

六、本節總結

本文主要內容就到此爲止了,這裏爲大家簡單總結一下要點:

  • Kubernetes API 請求訪問控制的基本定義;
  • Kubernetes 認證的幾種通用方式和基本原理;
  • Kubernetes RBAC 的基本定義和使用方式;
  • Kubernetes 運行時刻 Security Context 的概念和使用;
  • Kubernetes 多租安全加固小節。

2羣直播海報.png

阿里巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的公衆號。”

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章