一文讀懂 TKE 及 Kubernetes 訪問許可權控制
阿新 • • 發佈:2021-01-21
> 你有了解過Kubernetes的認證授權鏈路嗎?是否對TKE的許可權控制CAM策略、服務角色傻傻分不清楚?本文將會向你介紹`騰訊雲TKE平臺側的訪問控制`、`Kubernetes訪問控制鏈路`,以及演示如何將平臺側賬號對接到Kubernetes內。
當你在使用騰訊雲容器服務TKE(Tencent Kubernetes Engine)的時候,如果多人共用一個賬號的情況下,是否有遇到以下問題呢?
- 金鑰由多人共享,洩密風險高。
- 無法限制其他人的訪問許可權,其他人誤操作易造成安全風險。
為了解決以上問題,騰訊雲CAM(Cloud Access Management)提供了主賬號和子賬號的認證體系以及基於角色的許可權控制。
而不同的子賬號對於TKE平臺側資源的控制粒度比較粗(cluster例項級別),又會遇到以下問題:
- 同一個叢集由多子賬號可訪問,無法保證叢集資源級別、名稱空間級別的讀寫控制。
- 叢集的高許可權子賬戶無法對低許可權子賬戶進行授權管理。
為了解決以上兩個問題,TKE針對`平臺側資源`、`Kubernetes資源`分別進行相應的訪問控制管理。
## 平臺側訪問控制
首先介紹下什麼是平臺側資源,平臺側資源即`Cluster資源`、`CVM資源`、`CLB資源`、`VPC資源`等騰訊雲資源,而訪問的使用者主要分為`使用者`和`服務角色載體`。
1. `使用者`就是我們平時登入控制檯的主賬號、子賬號或者協作者賬號
2. `服務角色`是一種定義好帶有某些許可權的角色,可以將這個角色賦予某個`載體`,可以是某個其他賬戶,也可以是騰訊雲下一個產品的服務提供者,CAM會預設為產品提供一個預設的載體和預設的角色,例如TKE的預設角色就是TKE_QCSRole,而載體就是`ccs.qcloud.com`。
而這個角色有什麼用處呢?舉個TKE的例子,比如TKE的service-controller會Watch叢集內的Service資源,如果需要建立LoadBalance型別的Service,會通過雲API購買並建立`CLB資源`,而service-controller是TKE平臺為使用者部署的,去訪問雲API需要有身份,這個身份就是`ccs.qcloud.com`載體,而許可權則需要使用者給載體授予一個角色,即TKE_QCSRole。只有使用者在授權TKE載體之後,TKE才可以通過服務扮演的方式代替使用者購買CLB。
下面我會簡單為你介紹如何給`使用者`授權,以及如何給TKE平臺授予`角色`。
### 定製策略
TKE通過接入CAM,對叢集的API介面級別進行許可權細分,需要您在CAM控制檯對子賬戶進行不同的許可權授予。同時TKE也在CAM側提供了預設的許可權,提供您預設選擇,例如:
![](https://img2020.cnblogs.com/other/2041406/202101/2041406-20210121180120401-682437689.png)
也可以自定義策略,具體策略定製請參考CAM產品介紹文件
![](https://img2020.cnblogs.com/other/2041406/202101/2041406-20210121180120730-1767080091.png)
例如擁有隻讀許可權的子賬戶嘗試修改叢集名稱,將會在API介面時校驗CAM許可權失敗
![](https://img2020.cnblogs.com/other/2041406/202101/2041406-20210121180121079-45821483.png)
### 劃分使用者組
可以依據團隊的職責劃分好使用者組,將之前規劃好的自定義策略繫結到一個使用者組上,來方便的進行許可權管理。
例如:有新同學入職時可方便的加入指定使用者組(如運維組),就可以獲取到該使用者組的許可權,避免了繁瑣的許可權配置操作。
### 授予TKE角色許可權
使用TKE容器服務需要授予TKE平臺為您操作CVM\CLB\VPC\CBS等許可權,所以首次訪問TKE控制檯需要確保同意授權,即建立預設角色TKE_QCSRole,此角色預設授予TKE載體,該載體會通過CAM獲取操作您叢集的臨時金鑰,來進行相應的雲API操作。
![](https://img2020.cnblogs.com/other/2041406/202101/2041406-20210121180121475-1793381284.png)
![](https://img2020.cnblogs.com/other/2041406/202101/2041406-20210121180121834-802579425.png)
### 更多
更多豐富的平臺側訪問控制用法請訪問[CAM產品說明文件](https://cloud.tencent.com/document/product/598/17848)
## Kubernetes訪問控制
介紹完平臺側資源的訪問控制,我們再來看看TKE叢集內的資源如何進行許可權管理。當不同的子賬戶都擁有訪問同一個TKE Kubernetes叢集許可權之後,如何保證不同的子賬戶,對於叢集內資源擁有不同的角色和許可權呢?讓我們首先從社群的Kubernetes訪問鏈路來分析整個過程,從而向您介紹TKE是如何實現容器服務子賬戶對接Kubernetes認證授權體系的。
### Overview
首先從巨集觀的角度看下Kubernetes的請求鏈路是如何進行的。![](https://img2020.cnblogs.com/other/2041406/202101/2041406-20210121180122285-1508761281.png)圖片來源於k8s社群官網。
可以大概瞭解到一個請求的鏈路是依次通過Authentication(認證,簡稱Authn)、Authorization(授權,簡稱Authz)、AdmissionControl(准入控制),從而獲取到後端持久化的資料。
從圖中可以看到Authn、Authz、AdmissionControl是由多個模組組成的,每個步驟都有多種方式構成的。
在進入認證模組之前會將HTTP的Request進行構建context,而context中就包含了使用者的RequestInfo,userInfo、Verb、APIGroup、Version、Namespace、Resource、Path等。
帶著這些資訊,下面我們來一次看下准入過程中的每個步驟吧。
### Kubernetes認證
認證的過程的證明user身份的過程。
Kubernetes中有兩類使用者,一類是ServiceAccount,一類是叢集真實的使用者。
ServiceAccount賬戶是由Kubernetes提供API(資源)進行建立和管理的,ServiceAccount可以認為是特殊的Secret資源,可使用者叢集內資源訪問APIServer的認證所用。通過可以通過mount的方式掛載到Pod內進行使用。
真實的使用者通常是從外部發起請求訪問APIServer,由管理員進行管理認證憑證,而Kubernetes本身不管理任何的使用者和憑證資訊的,即所有的使用者都是邏輯上的使用者,無法通過API呼叫Kubernetes API進行建立真實使用者。
Kubernetes認證的方式眾多,常見的有TLS客戶端證書雙向認證、BearerToken認證、BasicAuthorization或認證代理(WebHook)
所有的認證方式都是以外掛的形式串聯在認證鏈路中,只要有一種認證方式通過,即可通過認證模組,且後續的認證方式不會被執行。
在此處參考一點點Kubernetes APIServer Authentication模組的程式碼,可以發現,任何的認證方式都是一下Interface的實現方式都是接收http Request請求,然後會返回一個user.Info的結構體,一個bool,以及一個error
```
// Request attempts to extract authentication information from a request and returns
// information about the current user and true if successful, false if not successful,
// or an error if the request could not be checked.
type Request interface {
AuthenticateRequest(req *http.Request) (user.Info, bool, error)
}
```
user.Info中包含了使用者的資訊,包括UserName、UUID、Group、Extra。
bool返回了使用者是否通過認證,false的話即返回無法通過認證,即返回401錯誤。
error則返回了當Request無法被檢查的錯誤,如果遇到錯誤則會繼續進行下一種註冊的方式進行認證。
如果認證通過,則會把user.Info寫入到到請求的context中,後續請求過程可以隨時獲取使用者資訊,比如授權時進行鑑權。
下面我會以Kubernetes程式碼中的認證方式順序,挑選幾項認證方式,並結合TKE開啟的認證方式來向你介紹TKE建立的Kubernetes叢集預設的認證策略。
#### Basic Authentication
APIServer啟動引數`--basic-auth-file=SOMEFILE`指定basic認證的csv檔案,在APIServer啟動之後修改此檔案都不會生效,需要重啟APIServer來更新basic authentication的token。csv檔案格式為:`token,user,uid,"group1,group2,group3"`。
請求時,需要指定HTTP Header中Authentication為Basic,並跟上Base64Encode(user:passward)值。
#### x509客戶端證書
APIServer啟動引數`--client-ca-file=SOMEFILE`指定CA證書,而在TKE的K8s叢集建立過程中,會對叢集進行自簽名CA金鑰和證書用於管理,如果使用者下發的客戶端證書是由此CA證書的金鑰簽發的,那麼就可以通過客戶端證書認證,並使用客戶端證書中的CommonName、Group欄位分別作為Kubernetes的UserInfo中Username和Group資訊。
目前TKE對接子賬戶都是通過自簽名的CA憑證進行簽發子賬戶Uin對應CN的客戶端證書。
#### Bearer Token
Bearer Token的認證方式包含很多,比如啟動引數指定的、ServiceAccount(也是一種特殊的BeaerToken)、BootstrapToken、OIDCIssure、WebhookToken
##### 1. **預設指定Token csv檔案**
APIServer啟動引數`--token-auth-file=SOMEFILE`指定Bearer Token認證的csv檔案。和Basic Authentication方式相似,只不過請求APIServer時,指定的HTTP認證方式為Bearer方式。此Bearer後直接跟passward即可。csv檔案格式為:`password,user,uid,"group1,group2,group3"`。
請求時,需要指定HTTP Header中Authentication為Bearer,並跟上Base64Encode(user:passward)值。
##### 2. **ServiceAccount**
ServiceAccount也是一種特殊beaer token,ServiceAccount在Kubernetes中是一種資源,建立一個ServiceAccount資源之後預設會建立一個Secret資源,而Secret資源中就包含了一個JWT格式的Token欄位,以Bearer Token的方式請求到Kube-APIServer,Kube-APIServer解析token中的部分user資訊,以及validate以下ServiceAccount是否存在即可進行認證檢查。這種方式即之前提到的“兩種使用者”中常見的叢集內認證方式,ServiceAccount,主要用於叢集內資源訪問APIServer,但不限於叢集內。
##### 3. **BootstrapToken**
此項開關在Kubernetes v1.18版本中才為stable版本,此類Token是專門用來引導叢集安裝使用的,需要配合controller-manager的TokenCleaner。
目前TKE預設開啟此配置。
##### 4. **OpenID Connect Tokens**
OIDCToken的認證方式是結合OAuth2向身份提供方獲取ID Token來訪問APIServer。
如需要開啟此項功能,需要在APIServer的啟動引數中指定oidc的配置引數,例如`--oidc-issuer-url`指定oidc身份提供方的地址,`--oidc-client-id`指定身份提供方側的賬戶ID,`--oidc-username-claim`身份提供方的使用者名稱。
具體可參考[Kubernetes官方文件](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens),目前公有云TKE沒有使用此引數對接騰訊雲賬戶,因為涉及使用者需要主動登入授權後才可返回Id Token,和當前官網互動衝突,可以在後續CLI工具中實現。
##### 5. **Webhook Token Server**
Webhook Token是一種hook的方式來校驗是否認證通過。
APIServer啟動引數`--authentication-token-webhook-config-file`及`--authentication-token-webhook-cache-ttl`來分別指定Webhook地址以及token的cache ttl。
若APiServer開啟此方式進行認證校驗,則在接受到使用者的Request之後,會包裝Bearer Token成一個`TokenReview`傳送給WebHookServer,Server端接收到之後會進行校驗,並返回`TokenReview`介面,在status欄位中進行反饋是否通過校驗通過和user.Info資訊。
#### 總結
以上即為Kubernetes APIServer認證的幾種方式,TKE在每種認證方式都有支援。供使用者靈活使用。
目前TKE正在推使用x509客戶端證書方式來進行認證管理,以方便進行對接子賬戶的建立、授權管理、更新。
### Kubernetes授權
Kubernetes的授權模式支援一下幾種,和認證一樣,參考開始說的RequestInfo context,可知使用者Reqeust的context除了認證需要的userInfo,還有一些其他的欄位例如Verb、APIGroup、APIVersion、Resource、Namespaces、Path……
授權就是判斷user是否擁有操作資源的相應許可權。
Kubernetes支援AlwaysAllow、AlwaysDeny、Node、ABAC、RBAC、Webhook授權Mode,和認證一樣,只要有一種鑑權模組通過,即可返回資源。
在這裡重點介紹下面兩種方式
#### RBAC
RBAC(*Role-Based Access Control*),Kubernetes提供ClusterRole、Role資源,分別對應叢集維度、Namespace維度角色許可權管控,使用者可以自定義相應的ClusterRole、Role資源,繫結到已經認證的User之上。
如下tke:pod-reader ClusterRole,定義了該角色可以訪問core apigroup下面對pods資源的get/watch/list操作
```
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: tke:pod-reader
rules:
- apiGroups: [""] # "" 指定核心 API 組
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
# 此角色繫結使得使用者 "alex" 能夠讀取 "default" 名稱空間中的 Pods
kind: ClusterRoleBinding
metadata:
name: alex-ClusterRole
subjects:
- kind: User
name: alex
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: tke:pod-reader # 這裡的名稱必須與你想要繫結的 Role 或 ClusterRole 名稱一致
apiGroup: rbac.authorization.k8s.io
```
通過以上的yaml配置,通過認證模組到達授權模組的requestInfo中userInfo資訊是alex的請求,在授權模組中走到RBAC授權模組時,則會進行查詢叢集的ClusterRole/ClusterRoleBinding資訊。進行判斷是否擁有context相應操作的許可權。
TKE的對接子賬戶的許可權授權策略就是使用的Kubernetes原生的RBAC進行對子賬戶資源訪問控制,這樣符合原生,符合有K8s使用習慣的使用者。
#### WebHook
Webhook模式是一種基於HTTP回撥的方式,通過配置好授權webhook server地址。當APIServer接收到request的時候,會進行包裝`SubjectAccessReview`請求Webhook Server,Webhook Server會進行判斷是否可以訪問,然後返回allow資訊。
以下是kubernetes社群一個例子,以供參考。
```
{
"apiVersion": "authorization.k8s.io/v1beta1",
"kind": "SubjectAccessReview",
"spec": {
"resourceAttributes": {
"namespace": "kittensandponies",
"verb": "get",
"group": "unicorn.example.org",
"resource": "pods"
},
"user": "alex",
"group": [
"group1",
"group2"
]
}
}
{
"apiVersion": "authorization.k8s.io/v1beta1",
"kind": "SubjectAccessReview",
"status": {
"allowed": true
}
}
```
目前TKE沒有考慮使用Webhook的模式,但是Webhook模式提供了強大的靈活性,比如對接CAM,實現K8s許可權對接到平臺側,但是也有一定的風險和挑戰,比如依賴CAM的穩定性;請求延遲、快取/TTL的配置;CAM action配置與K8s許可權對應關係。此項授權模式仍然在考慮中,有需求的使用者可以反饋。
### 准入控制
什麼是admission controller?
> In a nutshell, Kubernetes admission controllers are plugins that govern and enforce how the cluster is used.
Admission controllers是K8s的外掛,用來管理和強制使用者如何來操作叢集。
Admission controllers主要分為兩個phase,一個是mutating,一個是validating。這兩個階段都是在authn&authz之後的,mutating做的變更准入,就是會對request的resource,進行轉換,比如填充預設的requestLimit?而validating admission的意思就是驗證准入,比如校驗Pod副本數必須大於2。
API Server請求鏈路:
![](https://img2020.cnblogs.com/other/2041406/202101/2041406-20210121180122549-1228198409.png)
> `ValidatingAdmissionWebhooks` and `MutatingAdmissionWebhooks`, both of which are in beta status as of Kubernetes 1.13.
k8s支援30多種admission control 外掛 ,而其中有兩個具有強大的靈活性,即`ValidatingAdmissionWebhooks`和`MutatingAdmissionWebhooks`,這兩種控制變換和准入以Webhook的方式提供給使用者使用,大大提高了靈活性,使用者可以在叢集建立自定義的AdmissionWebhookServer進行調整准入策略。
TKE中1.10及以上版本也預設開啟了`ValidatingAdmissionWebhooks`、`MutatingAdmissionWebhooks`
瞭解更多Admission Controller參考[這裡](https://kubernetes.io/zh/docs/reference/access-authn-authz/extensible-admission-controllers/)
## kubernetes許可權對接子賬戶
TKE許可權實現對接子賬戶主要的方案是:`x509客戶端認證`+`Kubernetes RBAC授權`。
### 認證
每個子賬戶都擁有單獨的屬於自己的客戶端證書,用於訪問KubernetesAPIServer。
- 使用者在使用TKE的新授權模式時,不同子賬戶在獲取叢集訪問憑證時,即前臺訪問叢集詳情頁或呼叫DescribeClusterKubeconfig時,會展示子賬戶自己的x509客戶端證書,此證書是每個叢集的自簽名CA簽發的。
- 該使用者在控制檯訪問Kubernetes資源時,後臺預設使用此子賬戶的客戶端證書去訪問使用者Kubernetes APIServer。
- 支援子賬戶`更新`自己的證書。
- 支援主賬戶或叢集tke:admin許可權的賬戶進行`檢視`、`更新`其他子賬戶證書。
![](https://img2020.cnblogs.com/other/2041406/202101/2041406-20210121180122997-2045514177.png)
### 授權
TKE控制檯通過Kubernetes原生的RBAC授權策略,對子賬戶提供細粒度的Kubernetes資源粒度許可權控制。
- 提供授權管理頁,讓`主賬號`和`叢集建立者`預設擁有管理員許可權,可以對其他擁有此叢集DescribeCluster Action許可權的子賬戶進行許可權管理。
![](https://img2020.cnblogs.com/other/2041406/202101/2041406-20210121180123637-1113009910.png)
- 並提供預設的ClusterRole。
- 所有名稱空間維度:
- 管理員(tke:admin):對所有名稱空間下資源的讀寫許可權, 對叢集節點,儲存卷,名稱空間,配額的讀寫許可權, 可子賬號和許可權的讀寫許可權
- 運維人員(tke:ops):對所有名稱空間下控制檯可見資源的讀寫許可權, 對叢集節點,儲存卷,名稱空間,配額的讀寫許可權
- 開發人員(tke:dev):對所有名稱空間下控制檯可見資源的讀寫許可權
- 受限人員(tke:ro):對所有名稱空間下控制檯可見資源的只讀許可權
- 使用者自定義ClusterRole
- 指定名稱空間維度:
- 開發人員(tke:ns:dev): 對所選名稱空間下控制檯可見資源的讀寫許可權, 需要選擇指定名稱空間。
- 只讀使用者(tke:ns:ro):對所選名稱空間下控制檯可見資源的只讀許可權, 需要選擇指定名稱空間。
![](https://img2020.cnblogs.com/other/2041406/202101/2041406-20210121180124142-743361154.png)
![](https://img2020.cnblogs.com/other/2041406/202101/2041406-20210121180124488-1224213303.png)
- 所有預設的ClusterRole都將帶有固定label:`cloud.tencent.com/tke-rbac-generated: "true"`
- 所有預設的ClusterRoleBinding都帶有固定的annotations:`cloud.tencent.com/tke-account-nickname: yournickname`,及label:`cloud.tencent.com/tke-account: "yourUIN"`
![](https://img2020.cnblogs.com/other/2041406/202101/2041406-20210121180125007-2069078837.png)
### 更多
當然,除了TKE控制檯提供的預設授權策略,管理員也可以通過`kubectl`操作ClusterRole/Role來實現自定義角色的靈活配置細粒度許可權,以及操作ClusterRoleBinding/RoleBinding進行許可權繫結,繫結到任意的角色許可權之上。
例如你想設定CAM側使用者組為productA產品的pod-dev的使用者許可權只能夠get/list/watch product-a名稱空間下的pods資源,則你可以這樣操作:
- 建立自定義ClusterRole/Role:dev-pod-reader,yaml例項如下,檔名為developer.yaml
```
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole # 這裡使用ClusterRole可以複用給產品其他名稱空間
metadata:
name: pod-dev # pod-dev此角色為只能讀取pod的開發
rules:
- apiGroups: [""] # "" 指定核心 API 組
resources: ["pods"]
verbs: ["get", "watch", "list"]
```
- 使用`kubectl`或者通過TKE控制檯`YAML建立資源`建立上述Role
![](https://img2020.cnblogs.com/other/2041406/202101/2041406-20210121180125321-1916310655.png)
- 繫結dev使用者組下的dev1、dev2、dev3使用者,繫結自定義許可權pod-dev到product-a名稱空間下
![](https://img2020.cnblogs.com/other/2041406/202101/2041406-20210121180125680-442757993.png)
- 從此dev1,dev2,dev3使用者則只能使用get/list/watch訪問product-a下的pods資源
```
$ kubectl --kubeconfig=./dev.kubeconfig get pods
Error from server (Forbidden): pods is forbidden: User "10000001xxxx-1592395536" cannot list resource "pods" in API group "" in the namespace "default"
$ kubectl --kubeconfig=./dev.kubeconfig get pods -n product-a
No resources found.
```
### 參考
1. [kubernetes認證介紹](https://kubernetes.io/docs/reference/access-authn-authz/authentication/)
2. [kubernetes授權介紹](https://kubernetes.io/docs/reference/access-authn-authz/authorization/)
3. [kubernetesRBAC介紹](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)
>【騰訊雲原生】雲說新品、雲研新術、雲遊新活、雲賞資訊,掃碼關注同名公眾號,及時獲取更多幹貨!!
![](https://img2020.cnblogs.com/other/2041406/202101/2041406-20210121180126053-1103636