訪問控制概述
Kubernetes作為一個分布式集群的管理工具,保證集群的安全性是其一個重要的任務(wù)。所謂的安全性其實就是保證對Kubernetes的各種客戶端進行認(rèn)證和鑒權(quán)操作。
客戶端
在Kubernetes集群中,客戶端通常有兩類:
User Account:一般是獨立于kubernetes之外的其他服務(wù)管理的用戶賬號。
Service Account:kubernetes管理的賬號,用于為Pod中的服務(wù)進程在訪問Kubernetes時提供身份標(biāo)識。

認(rèn)證、授權(quán)與準(zhǔn)入控制
ApiServer是訪問及管理資源對象的唯一入口。任何一個請求訪問ApiServer,都要經(jīng)過下面三個流程:
- Authentication(認(rèn)證):身份鑒別,只有正確的賬號才能夠通過認(rèn)證
- Authorization(授權(quán)): 判斷用戶是否有權(quán)限對訪問的資源執(zhí)行特定的動作
- Admission Control(準(zhǔn)入控制):用于補充授權(quán)機制以實現(xiàn)更加精細(xì)的訪問控制功能。

認(rèn)證管理
Kubernetes集群安全的最關(guān)鍵點在于如何識別并認(rèn)證客戶端身份,它提供了3種客戶端身份認(rèn)證方式:
HTTP Base認(rèn)證:通過用戶名+密碼的方式認(rèn)證
這種認(rèn)證方式是把“用戶名:密碼”用BASE64算法進行編碼后的字符串放在HTTP請求中的Header Authorization域里發(fā)送給服務(wù)端。服務(wù)端收到后進行解碼,獲取用戶名及密碼,然后進行用戶身份認(rèn)證的過程。HTTP Token認(rèn)證:通過一個Token來識別合法用戶
這種認(rèn)證方式是用一個很長的難以被模仿的字符串--Token來表明客戶身份的一種方式。每個Token對應(yīng)一個用戶名,當(dāng)客戶端發(fā)起API調(diào)用請求時,需要在HTTP Header里放入Token,API Server接到Token后會跟服務(wù)器中保存的token進行比對,然后進行用戶身份認(rèn)證的過程。HTTPS證書認(rèn)證:基于CA根證書簽名的雙向數(shù)字證書認(rèn)證方式
這種認(rèn)證方式是安全性最高的一種方式,但是同時也是操作起來最麻煩的一種方式。

HTTPS認(rèn)證大體分為3個過程:
- 證書申請和下發(fā)
HTTPS通信雙方的服務(wù)器向CA機構(gòu)申請證書,CA機構(gòu)下發(fā)根證書、服務(wù)端證書及私鑰給申請者
- 證書申請和下發(fā)
-
- 客戶端和服務(wù)端的雙向認(rèn)證
- 客戶端向服務(wù)器端發(fā)起請求,服務(wù)端下發(fā)自己的證書給客戶端,客戶端接收到證書后,通過私鑰解密證書,在證書中獲得服務(wù)端的公鑰,客戶端利用服務(wù)器端的公鑰認(rèn)證證書中的信息,如果一致,則認(rèn)可這個服務(wù)器
- 客戶端發(fā)送自己的證書給服務(wù)器端,服務(wù)端接收到證書后,通過私鑰解密證書,在證書中獲得客戶端的公鑰,并用該公鑰認(rèn)證證書信息,確認(rèn)客戶端是否合法
- 服務(wù)器端和客戶端進行通信
- 服務(wù)器端和客戶端協(xié)商好加密方案后,客戶端會產(chǎn)生一個隨機的秘鑰并加密,然后發(fā)送到服務(wù)器端。
- 服務(wù)器端接收這個秘鑰后,雙方接下來通信的所有內(nèi)容都通過該隨機秘鑰加密
注意: Kubernetes允許同時配置多種認(rèn)證方式,只要其中任意一個方式認(rèn)證通過即可
授權(quán)管理
授權(quán)發(fā)生在認(rèn)證成功之后,通過認(rèn)證就可以知道請求用戶是誰, 然后Kubernetes會根據(jù)事先定義的授權(quán)策略來決定用戶是否有權(quán)限訪問,這個過程就稱為授權(quán)。
每個發(fā)送到ApiServer的請求都帶上了用戶和資源的信息:比如發(fā)送請求的用戶、請求的路徑、請求的動作等,授權(quán)就是根據(jù)這些信息和授權(quán)策略進行比較,如果符合策略,則認(rèn)為授權(quán)通過,否則會返回錯誤。
API Server目前支持以下幾種授權(quán)策略:
AlwaysDeny:表示拒絕所有請求,一般用于測試
AlwaysAllow:允許接收所有請求,相當(dāng)于集群不需要授權(quán)流程(Kubernetes默認(rèn)的策略)
ABAC:基于屬性的訪問控制,表示使用用戶配置的授權(quán)規(guī)則對用戶請求進行匹配和控制
Webhook:通過調(diào)用外部REST服務(wù)對用戶進行授權(quán)
Node:是一種專用模式,用于對kubelet發(fā)出的請求進行訪問控制
RBAC:基于角色的訪問控制(kubeadm安裝方式下的默認(rèn)選項)
RBAC(Role-Based Access Control) 基于角色的訪問控制,主要是在描述一件事情:給哪些對象授予了哪些權(quán)限
其中涉及到了下面幾個概念:
- 對象:User、Groups、ServiceAccount
- 角色:代表著一組定義在資源上的可操作動作(權(quán)限)的集合
- 綁定:將定義好的角色跟用戶綁定在一起

RBAC引入了4個頂級資源對象:
- Role、ClusterRole:角色,用于指定一組權(quán)限
- RoleBinding、ClusterRoleBinding:角色綁定,用于將角色(權(quán)限)賦予給對象
Role、ClusterRole
一個角色就是一組權(quán)限的集合,這里的權(quán)限都是許可形式的(白名單)。
# Role只能對命名空間內(nèi)的資源進行授權(quán),需要指定nameapce
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: dev
name: authorization-role
rules:
- apiGroups: [""] # 支持的API組列表,"" 空字符串,表示核心API群
resources: ["pods"] # 支持的資源對象列表
verbs: ["get", "watch", "list"] # 允許的對資源對象的操作方法列表
# ClusterRole可以對集群范圍內(nèi)資源、跨namespaces的范圍資源、非資源類型進行授權(quán)
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: authorization-clusterrole
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
需要詳細(xì)說明的是,rules中的參數(shù):
- apiGroups: 支持的API組列表
"","apps", "autoscaling", "batch"
- resources:支持的資源對象列表
"services", "endpoints", "pods","secrets","configmaps","crontabs","deployments","jobs",
"nodes","rolebindings","clusterroles","daemonsets","replicasets","statefulsets",
"horizontalpodautoscalers","replicationcontrollers","cronjobs"
- verbs:對資源對象的操作方法列表
"get", "list", "watch", "create", "update", "patch", "delete", "exec"
RoleBinding、ClusterRoleBinding
角色綁定用來把一個角色綁定到一個目標(biāo)對象上,綁定目標(biāo)可以是User、Group或者ServiceAccount。
# RoleBinding可以將同一namespace中的subject綁定到某個Role下,則此subject即具有該Role定義的權(quán)限
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: authorization-role-binding
namespace: dev
subjects:
- kind: User
name: heima
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: authorization-role
apiGroup: rbac.authorization.k8s.io
# ClusterRoleBinding在整個集群級別和所有namespaces將特定的subject與ClusterRole綁定,授予權(quán)限
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: authorization-clusterrole-binding
subjects:
- kind: User
name: heima
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: authorization-clusterrole
apiGroup: rbac.authorization.k8s.io
RoleBinding引用ClusterRole進行授權(quán)
RoleBinding可以引用ClusterRole,對屬于同一命名空間內(nèi)ClusterRole定義的資源主體進行授權(quán)。
一種很常用的做法就是,集群管理員為集群范圍預(yù)定義好一組角色(ClusterRole),然后在多個命名空間中重復(fù)使用這些ClusterRole。這樣可以大幅提高授權(quán)管理工作效率,也使得各個命名空間下的基礎(chǔ)性授權(quán)規(guī)則與使用體驗保持一致。
# 雖然authorization-clusterrole是一個集群角色,但是因為使用了RoleBinding
# 所以heima只能讀取dev命名空間中的資源
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: authorization-role-binding-ns
namespace: dev
subjects:
- kind: User
name: heima
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: authorization-clusterrole
apiGroup: rbac.authorization.k8s.io
實戰(zhàn):創(chuàng)建一個只能管理dev空間下Pods資源的賬號
- 1、創(chuàng)建賬號
# 1) 創(chuàng)建證書
[root@master pki]# cd /etc/kubernetes/pki/
[root@master pki]# (umask 077;openssl genrsa -out devman.key 2048)
# 2) 用apiserver的證書去簽署
# 2-1) 簽名申請,申請的用戶是devman,組是devgroup
[root@master pki]# openssl req -new -key devman.key -out devman.csr -subj "/CN=devman/O=devgroup"
# 2-2) 簽署證書
[root@master pki]# openssl x509 -req -in devman.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out devman.crt -days 3650
# 3) 設(shè)置集群、用戶、上下文信息
[root@master pki]# kubectl config set-cluster kubernetes --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.109.100:6443
[root@master pki]# kubectl config set-credentials devman --embed-certs=true --client-certificate=/etc/kubernetes/pki/devman.crt --client-key=/etc/kubernetes/pki/devman.key
[root@master pki]# kubectl config set-context devman@kubernetes --cluster=kubernetes --user=devman
# 切換賬戶到devman
[root@master pki]# kubectl config use-context devman@kubernetes
Switched to context "devman@kubernetes".
# 查看dev下pod,發(fā)現(xiàn)沒有權(quán)限
[root@master pki]# kubectl get pods -n dev
Error from server (Forbidden): pods is forbidden: User "devman" cannot list resource "pods" in API group "" in the namespace "dev"
# 切換到admin賬戶
[root@master pki]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".
- 2、創(chuàng)建Role和RoleBinding,為devman用戶授權(quán)
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: dev
name: dev-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: authorization-role-binding
namespace: dev
subjects:
- kind: User
name: devman
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: dev-role
apiGroup: rbac.authorization.k8s.io
[root@master pki]# kubectl create -f dev-role.yaml
role.rbac.authorization.k8s.io/dev-role created
rolebinding.rbac.authorization.k8s.io/authorization-role-binding created
- 3、切換賬戶,再次驗證
# 切換賬戶到devman
[root@master pki]# kubectl config use-context devman@kubernetes
Switched to context "devman@kubernetes".
# 再次查看
[root@master pki]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
nginx-deployment-66cb59b984-8wp2k 1/1 Running 0 4d1h
nginx-deployment-66cb59b984-dc46j 1/1 Running 0 4d1h
nginx-deployment-66cb59b984-thfck 1/1 Running 0 4d1h
# 為了不影響后面的學(xué)習(xí),切回admin賬戶
[root@master pki]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".
準(zhǔn)入控制
通過了前面的認(rèn)證和授權(quán)之后,還需要經(jīng)過準(zhǔn)入控制處理通過之后,apiserver才會處理這個請求。
準(zhǔn)入控制是一個可配置的控制器列表,可以通過在Api-Server上通過命令行設(shè)置選擇執(zhí)行哪些準(zhǔn)入控制器:
--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,
DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds
只有當(dāng)所有的準(zhǔn)入控制器都檢查通過之后,apiserver才執(zhí)行該請求,否則返回拒絕。
當(dāng)前可配置的Admission Control準(zhǔn)入控制如下:
- AlwaysAdmit:允許所有請求
- AlwaysDeny:禁止所有請求,一般用于測試
- AlwaysPullImages:在啟動容器之前總?cè)ハ螺d鏡像
- DenyExecOnPrivileged:它會攔截所有想在Privileged Container上執(zhí)行命令的請求
- ImagePolicyWebhook:這個插件將允許后端的一個Webhook程序來完成admission controller的功能。
- Service Account:實現(xiàn)ServiceAccount實現(xiàn)了自動化
- SecurityContextDeny:這個插件將使用SecurityContext的Pod中的定義全部失效
- ResourceQuota:用于資源配額管理目的,觀察所有請求,確保在namespace上的配額不會超標(biāo)
- LimitRanger:用于資源限制管理,作用于namespace上,確保對Pod進行資源限制
- InitialResources:為未設(shè)置資源請求與限制的Pod,根據(jù)其鏡像的歷史資源的使用情況進行設(shè)置
- NamespaceLifecycle:如果嘗試在一個不存在的namespace中創(chuàng)建資源對象,則該創(chuàng)建請求將被拒絕。當(dāng)刪除一個namespace時,系統(tǒng)將會刪除該namespace中所有對象。
- DefaultStorageClass:為了實現(xiàn)共享存儲的動態(tài)供應(yīng),為未指定StorageClass或PV的PVC嘗試匹配默認(rèn)的StorageClass,盡可能減少用戶在申請PVC時所需了解的后端存儲細(xì)節(jié)
- DefaultTolerationSeconds:這個插件為那些沒有設(shè)置forgiveness tolerations并具有notready:NoExecute和unreachable:NoExecute兩種taints的Pod設(shè)置默認(rèn)的“容忍”時間,為5min
- PodSecurityPolicy:這個插件用于在創(chuàng)建或修改Pod時決定是否根據(jù)Pod的security context和可用的PodSecurityPolicy對Pod的安全策略進行控制