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

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

關注“阿里巴巴雲原生”公眾號,回覆關鍵詞

“入門”

,即可下載從零入門 K8s 系列文章 PPT。

導讀:

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

一、Kubernetes API 請求訪問控制

訪問控制

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

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

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

Kubernetes API 請求

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

由上圖來介紹一下 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 證書認證

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

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

另外可以透過 openssl 命令來進行證書的解析。上圖右側可以看到,透過 Subject 中的 O 和 CN 欄位可以檢視對應的資訊。

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

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

證書籤發 API

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

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

透過上圖右側中的命令可以來檢視相應的證書內容資訊。

簽發使用者證書

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

首先開發人員需用透過 openssl 等證書工具生成私鑰,然後建立對應的 x509 csr 請求檔案,需要在 subj 欄位中指定使用者 user 和組 group,最後透過 API 建立 K8s csr 例項並等待管理員審批。

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

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

Service Account

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

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

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

接著看一下 Service Account 的使用。

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

首先可以透過 get secret –oyaml 命令檢視 serviceaccount 對應的指定 secret,其中 token 欄位即為經過了 base64 編碼的 JWT 格式的認證 token。

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

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

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

生成 kubeconfig

kubeconfig 是使用者本地連線 Kubernetes 叢集使用的重要訪問憑證,接著來介紹一下 kubeconfig 的配置和使用。

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

使用 kubeconfig

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

三、Kubernetes 鑑權 - RBAC

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

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

RBAC 鑑權三要素

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

第一要素是 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 資源限定在不同的作用域內。從而幫助我們在一個多租戶叢集中,對使用者進行邏輯上的隔離。

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

上面的事例可以改為 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 具體的繫結許可權和物件。

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

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

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

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

RBAC - RoleBinding

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

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

比如這裡可以將名為 test 的 namespace 中的 pod 只讀許可權同時繫結給使用者 test1 和 test2 以及 proc1。也可以將 namespace test 只讀許可權繫結 tech-lead group 中的 test1 使用者,這樣使用者 test2 和 proc1 是沒有 get namespace 許可權的。

接著看一下對應的 RoleBinding 編排檔案模板。

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

其中 roleRef 欄位中聲明瞭我們需要繫結的角色,一個繫結只能指定唯一的 Role。在 subject 欄位中定義了我們要繫結的物件,這裡可以是 User,Group 或者是 Service Account。它同時支援繫結多個物件。

RBAC - ClusterRole

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

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

下圖為 ClusterRole 編排檔案模板:

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

ClusterRole 編排檔案幾乎和 Role 是一模一樣的,唯一不同的地方是 ClusterRole 中是所有叢集維度的許可權定義,不支援 namespace 的定義。

RBAC - ClusterRoleBinding

同樣在 ClusterRole 的基礎上,可以將其繫結在對應的 Subject 主體上。而 ClusterRoleBinding 模型例項可以幫助我們在叢集所有名稱空間上將 ClusterRole 繫結到具體的 Subject 物件上。

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

比如這裡可以將所有 namespace 的 list 許可權繫結給 group 為 sre 或者 devops 的管理員 admin1 和 admin2。

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

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

RABC - Default ClusterRoleBinding

透過上文的學習,我們知道在不進行任何許可權的繫結下,RABC 會拒絕所有的訪問。那麼我們的系統元件之間是如何互相請求呢?

其實在叢集建立的時候,處理系統各元件的客戶端證書,它們各自的角色和環境物件也會被創建出來,以滿足元件業務之間互動必須的許可權要求。

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

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

角色中的 verbs 如何設定?

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

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

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

四、Security Context 的使用

CVE-2019-5736

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

透過 docker hub 上的統計結果可以看到,主流的業務映象有 82。4% 是以 root 使用者來啟動的。透過這個調查可以看到對 Security Context 的相關使用是不容樂觀的。

Kubernetes Runtime 安全策略

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

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

首先還是要遵循許可權最小化原則,除了業務執行所必需的系統許可權,其他許可權都是可以去除的;

此外還可以透過在 pod 或者 container 維度設定 Security Context 引數,進行業務容器執行時刻的安全配置;

另外就是可以透過開啟 Pod Security Policy,在 apiserver 請求的 Admission 階段強制校驗容器的安全配置;

除了 PSP 的開啟之外,如上圖還列舉了常見的,使用比較多的配置引數。

Pod Security Policy

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

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

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

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

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

五、總結 - 多租安全加固

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

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

六、本節總結

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

Kubernetes API 請求訪問控制的基本定義;

Kubernetes 認證的幾種通用方式和基本原理;

Kubernetes RBAC 的基本定義和使用方式;

Kubernetes 執行時刻 Security Context 的概念和使用;

Kubernetes 多租安全加固小節。

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

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