Kubernetes 集群安全機制詳解

本文主要介紹 Kubernetes 的安全機制,如何使用一系列概念、技術點、機制確保集群的訪問是安全的,涉及到的關鍵詞有:api-server,認證,授權,准入控制,RBAC,Service Account,客戶端證書認證,Kubernetes 用戶,Token 認證等等。雖然涉及到的技術點比較瑣碎,比較多,但是瞭解整個機制後就很容易將其串起來,從而能很好地理解 Kubernetes 集群安全機制。

Kubernetes api-server 安全訪問機制

kube-apiserver 是 Kubernetes 整個集群的入口,是一個 REST API 服務,提供的 API 實現了 Kubernetes 各類資源對象(如 Pod,RC,Service 等)的增、刪、改、查,API Server 也是集群內各個功能模塊之間交互和通信的樞紐,是整個集群的總線和數據中心。

Kubernetes 集群安全機制詳解

由此可見 API Server 的重要性了,我們用 kubectl、各種語言提供的客戶端庫或者發送 REST 請求和集群交互,其實底層都是以 HTTP REST 請求的方式同 API Server 交互,那麼訪問的安全機制是如何保證的呢,總不能隨便來一個請求都能接受並響應吧。API Server 為此提供了一套特有的、靈活的安全機制,每個請求到達 API Server 後都會經過:認證(Authentication)–>授權(Authorization)–>准入控制(Admission Control)三道安全關卡,通過這三道安全關卡的請求才給予響應:

Kubernetes 集群安全機制詳解

認證(Authentication)

認證階段的工作是識別用戶身份,支持的認證方式有很多,比如:HTTP Base,HTTP token,TLS,Service Account,OpenID Connect 等,API Server 啟動時可以同時指定多種認證方式,會逐個使用這些方法對客戶請求認證,只要通過任意一種認證方式,API Server 就會認為 Authentication 成功。高版本的 Kubernetes 默認認證方式是 TLS。在 TLS 認證方案中,每個用戶都擁有自己的 X.509 客戶端證書,API 服務器通過配置的證書頒發機構(CA)驗證客戶端證書。

授權階段判斷請求是否有相應的權限,授權方式有多種:AlwaysDeny,AlwaysAllow,ABAC,RBAC,Node 等。API Server 啟動時如果多種授權模式同時被啟用,Kubernetes 將檢查所有模塊,如果其中一種通過授權,則請求授權通過。 如果所有的模塊全部拒絕,則請求被拒絕(HTTP狀態碼403)。高版本 Kubernetes 默認開啟的授權方式是 RBAC 和 Node。

准入控制(Admission Control)

准入控制判斷操作是否符合集群要求,准入控制配備有一個“准入控制器”的列表,發送給 API Server 的每個請求都需要通過每個准入控制器的檢查,檢查不通過,則 API Server 拒絕調用請求,有點像 Web 編程的攔截器的意思。具體細節在這裡不進行展開了,如想進一步瞭解見這裡: Using Admission Controllers 。

Kubernetes 認證方式之客戶端證書(TLS)

通過上一節介紹我們知道 Kubernetes 認證方式有多種,這裡我們簡單介紹下客戶端證書(TLS)認證方式,也叫 HTTPS 雙向認證。一般我們訪問一個 https 網站,認證是單向的,只有客戶端會驗證服務端的身份,服務端不會管客戶端身份如何。我們來大概看下 HTTPS 握手過程(單向認證):

  1. 客戶端發送 Client Hello 消息給服務端;
  2. 服務端回覆 Server Hello 消息和自身證書給客戶端;
  3. 客戶端檢查服務端證書的合法性,證書檢查通過後根據雙方發送的消息生成 Premaster Key,然後用服務端的證書裡面的公鑰加密 Premaster Key 併發送給服務端 ;
  4. 服務端通過自己的私鑰解密得到 Premaster Key,然後通過雙方協商的算法和交換的消息生成 Session Key(後續雙方數據加密用的對稱密鑰,客戶端也能通過同樣的方法生成同樣的 Key),然後回覆客戶端一個消息表明握手結束,後續發送的消息會以協商的對稱密鑰加密。

HTTPS 雙向認證的過程就是在上述第 3 步的時候同時回覆自己的證書給服務端,然後第 4 步服務端驗證收到客戶端證書的合法性,從而達到了驗證客戶端的目的。在 Kubernetes 中就是用了這樣的機制,只不過相關的 CA 證書是自簽名的:

Kubernetes 集群安全機制詳解

Kubernetes 授權方式之 RBAC 介紹

基於角色的訪問控制(Role-Based Access Control,即 RBAC),是 Kubernetes 提供的一種授權策略,也是新版集群默認啟用的方式。RBAC 將角色和角色綁定分開,角色指的是一組定義好的操作集群資源的權限,而角色綁定是將角色和用戶、組或者服務賬號實體綁定,從而賦予這些實體權限。可以看出 RBAC 這種授權方式很靈活,要賦予某個實體權限只需要綁定相應的角色即可。針對 RBAC 機制,Kubernetes 提供了四種 API 資源:Role、ClusterRole、RoleBinding、ClusterRoleBinding。

Kubernetes 集群安全機制詳解

Role:只能用於授予對某一單一命名空間中資源的訪問權限,因此在定義時必須指定 namespace,以下示例描述了 default 命名空間中的一個 Role 對象的定義,用於授予對 Pod 的讀訪問權限:

<code>kind: Role

apiVersion: rbac.authorization.k8s.io/v1beta1

metadata:

namespace: default

name: pod-reader

rules:


- apiGroups: [""] # 空字符串""表明使用core API group

resources: ["pods"]

verbs: ["get", "watch", "list"]
/<code>

ClusterRole:針對集群範圍的角色,能訪問整個集群的資源,下面示例中的 ClusterRole 定義可用於授予用戶對某一特定命名空間,或者所有命名空間中的 secret(取決於其綁定方式)的讀訪問權限:

<code>kind: ClusterRole

apiVersion: rbac.authorization.k8s.io/v1beta1

metadata:

# 鑑於ClusterRole是集群範圍對象,所以這裡不需要定義"namespace"字段

name: secret-reader

rules:

- apiGroups: [""]

resources: ["secrets"]

verbs: ["get", "watch", "list"]
/<code>

RoleBinding:將 Role 和用戶實體綁定,從而賦予用戶實體命名空間內的權限,同時也支持 ClusterRole 和用戶實體的綁定,下面示例中定義的 RoleBinding 對象在 default 命名空間中將 pod-reader 角色授予用戶 jane。 這一授權將允許用戶 jane 從 default 命名空間中讀取 Pod:

<code># 以下角色綁定定義將允許用戶"jane"從"default"命名空間中讀取 Pod。 


kind: RoleBinding

apiVersion: rbac.authorization.k8s.io/v1beta1

metadata:

name: read-pods

namespace: default

subjects:

- kind: User

name: jane

apiGroup: rbac.authorization.k8s.io

roleRef:

kind: Role

name: pod-reader

apiGroup: rbac.authorization.k8s.io
/<code>

ClusterRoleBinding:將 ClusterRole 和用戶實體綁定,從而賦予用戶實體集群範圍的權限,下面示例中所定義的 ClusterRoleBinding 允許在用戶組 manager 中的任何用戶都可以讀取集群中任何命名空間中的 secret:

<code># 以下`ClusterRoleBinding`對象允許在用戶組"manager"中的任何用戶都可以讀取集群中任何命名空間中的secret。

kind: ClusterRoleBinding

apiVersion: rbac.authorization.k8s.io/v1beta1

metadata:

name: read-secrets-global

subjects:


- kind: Group

name: manager

apiGroup: rbac.authorization.k8s.io

roleRef:

kind: ClusterRole

name: secret-reader

apiGroup: rbac.authorization.k8s.io
/<code>

關於 RBAC 更詳細的講解見這裡: https://jimmysong.io/kubernete ... .html

Kubernetes 中兩種賬號類型介紹

Kubernetes 中有兩種用戶(User):服務賬號(ServiceAccount)和普通的用戶(User)。 ServiceAccount 是由 Kubernetes 管理的,而 User 賬號是在外部管理,Kubernetes 不存儲用戶列表,也就是說針對用戶的增、刪、該、查都是在集群外部進行,Kubernetes 本身不提供普通用戶的管理。

兩種賬號的區別:

  • ServiceAccount 是 Kubernetes 內部資源,而普通用戶是存在於 Kubernetes 之外的;
  • ServiceAccount 是屬於某個命名空間的,不是全局的,而普通用戶是全局的,不歸某個 namespace 特有;
  • ServiceAccount 一般用於集群內部 Pod 進程使用,和 api-server 交互,而普通用戶一般用於 kubectl 或者 REST 請求使用;

ServiceAccount 的實際應用

ServiceAccount 可以用於 Pod 訪問 api-server,其對應的 Token 可以用於 kubectl 訪問集群,或者登陸 kubernetes dashboard。

普通用戶的實際應用

  • X509 客戶端證書,客戶端證書驗證通過為 API Server 指定 –client-ca-file=xxx 選項啟用,API Server 通過此 ca 文件來驗證 API 請求攜帶的客戶端證書的有效性,一旦驗證成功,API Server 就會將客戶端證書 Subject 裡的 CN 屬性作為此次請求的用戶名。關於客戶端證書方式的用戶後面會有專門的實踐介紹。
  • 靜態token文件,通過指定 –token-auth-file=SOMEFILE 選項來啟用 bearer token 驗證方式,引用的文件是一個包含了 token,用戶名,用戶 ID 的 csv 文件,請求時,帶上 Authorization: Bearer xxx 頭信息即可通過 bearer token 驗證;
  • 靜態密碼文件,通過指定 --basic-auth-file=SOMEFILE 選項啟用密碼驗證,引用的文件是一個包含密碼,用戶名,用戶 ID 的 csv 文件,請求時需要將 Authorization 頭設置為 Basic BASE64ENCODED(USER:PASSWORD);

實踐:基於客戶端證書認證方式新建 Kubeconfig 訪問集群

Kubeconfig 文件詳解

我們知道在安裝完 Kubernetes 集群后會生成 $HOME/.kube/config 文件,這個文件就是 kubectl 命令行工具訪問集群時使用的認證文件,也叫 Kubeconfig 文件。這個 Kubeconfig 文件中有很多重要的信息,文件大概結構是這樣,這裡說明下每個字段的含義:

<code>apiVersion: v1

clusters:

- cluster:

certificate-authority-data: ...

server: https://192.168.26.10:6443

name: kubernetes

contexts:

- context:

cluster: kubernetes

user: kubernetes-admin

name: kubernetes-admin@kubernetes

current-context: kubernetes-admin@kubernetes

kind: Config

preferences: {}

users:

- name: kubernetes-admin

user:

client-certificate-data: ...

client-key-data: ...
/<code>

可以看出文件分為三大部分:clusters、contexts、users。

clusters 部分

定義集群信息,包括 api-server 地址、certificate-authority-data: 用於服務端證書認證的自簽名 CA 根證書(master 節點 /etc/kubernetes/pki/ca.crt 文件內容 )。

contexts 部分

集群信息和用戶的綁定,kubectl 通過上下文提供的信息連接集群。

users 部分

多種用戶類型,默認是客戶端證書(x.509 標準的證書)和證書私鑰,也可以是 ServiceAccount Token。這裡重點說下前者:

  • client-certificate-data:base64 加密後的客戶端證書;
  • client-key-data:base64 加密後的證書私鑰;

一個請求在通過 api-server 的認證關卡後,api-server 會從收到客戶端證書中取用戶信息,然後用於後面的授權關卡,這裡所說的用戶並不是服務賬號,而是客戶端證書裡面的 Subject 信息:O 代表用戶組,CN 代表用戶名。為了證明,可以使用 openssl 手動獲取證書中的這個信息:

首先,將 Kubeconfig 證書的 user 部分 client-certificate-data 字段內容進行 base64 解密,保存文件為 client.crt,然後使用 openssl 解析證書信息即可看到 Subject 信息:

<code>openssl x509 -in client.crt -text
/<code>

解析集群默認的 Kubeconfig 客戶端證書得到的 Subject 信息是:

<code>Subject: O=system:masters, CN=kubernetes-admin 

/<code>

可以看出該證書綁定的用戶組是 system:masters,用戶名是 kubernetes-admin,而集群中默認有個 ClusterRoleBinding 叫 cluster-admin,它將名為 cluster-admin 的 ClusterRole 和用戶組 system:masters 進行了綁定,而名為 cluster-admin 的 ClusterRole 有集群範圍的 Superadmin 權限,這也就理解了為什麼默認的 Kubeconfig 能擁有極高的權限來操作 Kubernetes 集群了。

新建具有隻讀權限的 Kubeconfig 文件

上面我們已經解釋了為什麼默認的 Kubeconfig 文件具有 Superadmin 權限,這個權限比較高,有點類型 Linux 系統的 Root 權限。有時我們會將集群訪問權限開放給其他人員,比如供研發人員查看 Pod 狀態、日誌等信息,這個時候直接用系統默認的 Kubeconfig 就不太合理了,權限太大,集群的安全性沒有了保障。更合理的做法是給研發人員一個只讀權限的賬號,避免對集群進行一些誤操作導致故障。

我們以客戶端證書認證方式創建 Kubeconfig 文件,所以需要向集群自簽名 CA 機構(master 節點)申請證書,然後通過 RBAC 授權方式給證書用戶授予集群只讀權限,具體方法如下:

假設我們設置證書的用戶名為:developer – 證書申請時 -subj 選項 CN 參數。

生成客戶端 TLS 證書

1、創建證書私鑰:

<code>openssl genrsa -out developer.key 2048
/<code>

2、用上面私鑰創建一個 csr(證書籤名請求)文件,其中我們需要在 subject 裡帶上用戶信息(CN為用戶名,O為用戶組):

<code>openssl req -new -key developer.key -out developer.csr -subj "/CN=developer"
/<code>

其中/O參數可以出現多次,即可以有多個用戶組

3、找到 Kubernetes 集群(API Server)的 CA 根證書文件,其位置取決於安裝集群的方式,通常會在 master 節點的 /etc/kubernetes/pki/ 路徑下,會有兩個文件,一個是 CA 根證書(ca.crt),一個是 CA 私鑰(ca.key)。

4、通過集群的 CA 根證書和第 2 步創建的 csr 文件,來為用戶頒發證書:

<code>openssl x509 -req -in developer.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out developer.crt -days 365
/<code>

至此,客戶端證書頒發完成,我們後面會用到文件是 developer.key 和 developer.crt

基於 RBAC 授權方式授予用戶只讀權限

在 Kubernetes 集群中已經有個默認的名為 view 只讀 ClusterRole 了,我們只需要將該 ClusterRole 綁定到 developer 用戶即可:

<code>kubectl create clusterrolebinding kubernetes-viewer --clusterrole=view --user=developer
/<code>

基於客戶端證書生成 Kubeconfig 文件

前面已經生成了客戶端證書,並給證書裡的用戶賦予了集群只讀權限,接下來基於客戶端證書生成 Kubeconfig 文件:

拷貝一份 $HOME/.kube.config,假設名為 developer-config,在其基礎上做修改:

1、contexts 部分 user 字段改為 developer,name 字段改為 developer@kubernetes。(這些改動隨意命名,只要前後統一即可);

2、users 部分 name 字段改為 developer,client-certificate-data 字段改為 developer.crt base64 加密後的內容,client-key-data 改為 developer.key base64 加密後的內容;

注意:證書 base64 加密時指定 –wrap=0 參數

  • cat developer.crt | base64 –wrap=0
  • cat developer.key | base64 –wrap=0

接下來測試使用新建的 Kubeconfig 文件:

<code>[root@master ~]# kubectl –kubeconfig developer-config –context=developer@kubernetes get pod

NAME READY STATUS RESTARTS AGE

nginx-deployment-5754944d6c-dqsdj 1/1 Running 0 5d9h

nginx-deployment-5754944d6c-q675s 1/1 Running 0 5d9h

[root@master ~]# kubectl –kubeconfig developer-config –context=developer@kubernetes delete pod nginx-deployment-5754944d6c-dqsdj

Error from server (Forbidden): pods “nginx-deployment-5754944d6c-dqsdj” is forbidden: User “developer” cannot delete resource “pods” in API group “” in the namespace “default”
/<code>

可以看出新建的 Kubeconfig 文件可以使用,寫權限是被 forbidden 的,說明前面配的 RBAC 權限機制是起作用的。

實踐:Kubeconfig 或 token 方式登陸 Kubernetes dashboard

我們打開 kubernetes dashboard 訪問地址首先看到的是登陸認證頁面,有兩種登陸認證方式可供選擇:Kubeconfig 和 Token 方式。

Kubernetes 集群安全機制詳解

其實兩種方式都需要服務賬號的 Token,對於 Kubeconfig 方式直接使用集群默認的 Kubeconfig: $HOME/.kube/config 文件不能登陸,因為文件中缺少 Token 字段,所以直接選擇本地的 Kubeconfig 文件登陸會報錯。正確的使用方法是獲取某個服務賬號的 Token,然後將 Token 加入到 $HOME/.kube/config 文件。下面具體實踐下兩種登陸 dashboard 方式:

準備工作

首先,兩種方式都需要服務賬號,所以我們先創建一個服務賬號,然後為了測試,給這個服務賬號一個查看權限(RBAC 授權),到時候登陸 dashboard 後只能查看,不能對集群中的資源做修改。

1、創建一個服務賬號(在 default 命名空間下):

<code>kubectl create serviceaccount kube-dashboard-reader
/<code>

2、將系統自帶的 ClusterRole:view 角色綁定到上一步創建的服務賬號,授予集群範圍的資源只讀權限:

<code>kubectl create clusterrolebinding kube-dashboard-reader --clusterrole=view --serviceaccount=default:kube-dashboard-reader
/<code>

3、獲取服務賬號的 token:

<code>kubectl get secret `kubectl get secret -n default | grep kube-dashboard-reader | awk '{print $1}'` -o jsonpath={.data.token} -n default | base64 -d
/<code>

Kubeconfig 方式登陸 dashboard

拷貝一份 $HOME/.kube/config,修改內容,將準備工作中獲取的 Token 添加入到文件中:在 Kubeconfig 的 Users 下 User 部分添加,類型下面這樣:

<code>...

users:

- name: kubernetes-admin

user:


client-certificate-data: ...

client-key-data: ...

token:
/<code>

然後登陸界面選擇 Kubeconfig 單選框,選擇該文件即可成功登陸 dashboard。

Token 方式登陸 dashboard

登陸界面選擇 Token 單選框,將準備工作中獲取的 Token 粘貼進去即可成功登陸。


分享到:


相關文章: