k8s之安全機制的使用及說明
機制說明
- Kubernetes 作為一個分布式集群的管理工具,保證集群的安全性是其一個重要的任務。API Server 是集群內(nèi)部各個組件通信的中介, 也是外部控制的入口。所以 Kubernetes 的安全機制基本就是圍繞保護 API Server 來設計的。
- 比如 kubectl 如果想向 API Server 請求資源,需要過三關,第一關是認證(Authentication),第二關是鑒權(Authorization), 第三關是準入控制(Admission Control),只有通過這三關才可能會被 K8S 創(chuàng)建資源。
一、認證(Authentication)
HTTP Token 認證:通過一個 Token 來識別合法用戶,通常是單向認證
- HTTP Token 的認證是用一個很長的特殊編碼方式的并且難以被模仿的 Token 字符串來表達客戶的一種方式。
- Token 是一個很長的很復雜的字符串,每一個 Token 對應一個用戶名存儲在 API Server 能訪問的文件中。
- 當客戶端發(fā)起 API 調(diào)用請求時,需要在 HTTP Header 里放入 Token。
HTTP Base 認證:通過用戶名+密碼的方式認證,通常是單向認證
- 用戶名:密碼 用 BASE64 算法進行編碼后的字符串放在 HTTP Request 中的 Heather Authorization 域里發(fā)送給服務端, 服務端收到后進行解碼,獲取用戶名及密碼。
HTTPS 證書認證(最嚴格):基于 CA 根證書簽名的客戶端身份認證方式??梢詫崿F(xiàn)雙向認證
注意:Token 認證和 Base 認證方式只能進行服務端對客戶端的單向認證,而客戶端不知道服務端是否合法;而 HTTPS 證書認證方式 則可以實現(xiàn)雙向認證。
1、需要被認證的訪問類型
- Kubernetes 組件對 API Server 的訪問:kubectl、kubelet、kube-proxy
- Kubernetes 管理的 Pod 對容器的訪問:Pod(coredns,dashborad 也是以 Pod 形式運行)
2、安全性說明
- Controller Manager、Scheduler 與 API Server 在同一臺機器,所以直接使用 API Server 的非安全端口訪問(比如 8080 端口)
- kubectl、kubelet、kube-proxy 訪問 API Server 就都需要證書進行 HTTPS 雙向認證,端口號使用 6443
3、證書頒發(fā)
- 手動簽發(fā):使用二進制部署時,需要先手動跟 CA 進行簽發(fā) HTTPS 證書
- 自動簽發(fā):kubelet 首次訪問 API Server 時,使用 token 做認證,通過后,Controller Manager 會為 kubelet 生成一個證書, 以后的訪問都是用證書做認證了
4、kubeconfig
- kubeconfig 文件包含集群參數(shù)(CA 證書、API Server 地址),客戶端參數(shù)(上面生成的證書和私鑰),集群 context 上下文參數(shù) (集群名稱、用戶名)。Kubenetes 組件(如 kubelet、kube-proxy)通過啟動時指定不同的 kubeconfig 文件可以切換到不同的集群 ,連接到 apiserver。也就是說 kubeconfig 文件既是一個集群的描述,也是集群認證信息的填充。
- kubeconfig默認路徑:
~/.kube/config,其中~表示當前用戶的主目錄
5、Service Account
- Service Account由 Kubernetes 自動創(chuàng)建,用來訪問 APIServer 的 Secret,所有 Pod 會默認使用這個 Secret 與 APIServer 通信。
- Service Account是為了方便 Pod 中的容器訪問API Server。因為 Pod 的創(chuàng)建、銷毀是動態(tài)的,所以要為它手動生成證書就不可行了。 Kubenetes 使用了Service Account解決 Pod 訪問API Server的認證問題。
6、Secret 與 SA 的關系
6.1 Kubernetes 設計了一種資源對象叫做 Secret,分為兩類
- 用于 ServiceAccount 的 service-account-token
- 用于保存用戶自定義保密信息的 Opaque
6.2 Service Account 中包含三個部分
- Token:是使用 API Server 私鑰簽名的 Token 字符串(JWT),用于訪問 API Server 時,Server 端認證
- ca.crt:根證書,用于 Client 端驗證 API Server 發(fā)送的證書
- namespace:標識這個 service-account-token 的作用域名空間
默認情況下,每個 namespace 都會有一個 Service Account,如果 Pod 在創(chuàng)建時沒有指定 Service Account,就會使用 Pod 所屬的 namespace 的 Service Account。每個 Pod 在創(chuàng)建后都會自動設置 spec.serviceAccount 為 default(除非指定了其他 Service Accout)。
二、鑒權(Authorization)
- 之前的認證(Authentication)過程,只是確認通信的雙方都確認了對方是可信的,可以相互通信。而鑒權是確定請求方有哪些資源的權限。
- API Server 目前支持以下幾種授權策略:(通過 API Server 的啟動參數(shù) “–authorization-mode” 設置)
1、鑒權訪問的類型
- AlwaysDeny:表示拒絕所有的請求,一般用于測試
- AlwaysAllow:允許接收所有請求,如果集群不需要授權流程,則可以采用該策略,一般用于測試
- ABAC(Attribute-Based Access Control):基于屬性的訪問控制,表示使用用戶配置的授權規(guī)則對用戶請求進行匹配和控制(缺點是:是一對一的關系、并且會重啟資源)
- Webbook:通過調(diào)用外部 REST 服務對用戶進行授權,即在集群外部對K8S進行鑒權
- RBAC(Role-Based Access Control):基于角色的訪問控制,K8S自1.6版本起默認使用規(guī)則
2、關于RBAC(Role-Based Access Control)
2.1 RBAC 相對其它訪問控制方式,擁有以下優(yōu)勢
- 對集群中的資源和非資源均擁有完整的覆蓋
- 整個 RBAC 完全由幾個 API 對象完成,同其它 API 對象一樣,可以用 kubectl 或 API 進行操作
- 可以在運行時進行調(diào)整,無需重啟 API Server,而 ABAC 則需要重啟 API Server
2.2 RBAC 的 API 資源對象說明
- RBAC 引入了 4 個新的頂級資源對象:Role、ClusterRole、RoleBinding、ClusterRoleBinding,4 種對象類型均可以通過 kubectl 與 API Server 操作。
https://kubernetes.io/docs/reference/access-authn-authz/rbac/ #官方文檔
3、角色
- Role:授權指定命名空間的資源控制權限,(一對一,單獨的命名空間);
- ClusterRole:可以授權所有命名空間的資源控制權限;
- Role是命名空間級別的,僅對特定命名空間中的資源有效;而ClusterRole是集群級別的,對整個Kubernetes集群都有效。
- 根據(jù)需要管理和控制的資源范圍,可以選擇使用Role或ClusterRole。如果只需要在特定命名空間中定義權限,可以使用Role;如果需要為整個集群定義權限,或者需要跨命名空間定義權限,應該使用ClusterRole。
3.1 角色綁定
- RoleBinding:將角色綁定到主體(即subject)
- ClusterRoleBinding:將集群角色綁定到主體
- RoleBinding是命名空間級別的,僅對特定命名空間中的資源有效;而ClusterRoleBinding是集群級別的,對整個Kubernetes集群都有效。
- 根據(jù)需要管理和控制的資源范圍,可以選擇使用RoleBinding或ClusterRoleBinding。如果只需要在特定命名空間中定義權限,可以使用RoleBinding;如果需要為整個集群定義權限,或者需要跨命名空間定義權限,應該使用ClusterRoleBinding。
3.2 主體(subject)
- User:用戶
- Group:用戶組
- ServiceAccount:服務賬號
User 使用字符串表示,它的前綴 system: 是系統(tǒng)保留的,集群管理員應該確保普通用戶不會使用這個前綴格式;Group 書寫格式與 User 相同,同樣 system: 前綴也為系統(tǒng)保留。
Pod使用 ServiceAccount 認證時,service-account-token 中的 JWT 會保存用戶信息。 有了用戶信息,再創(chuàng)建一對角色/角色綁定(集群角色/集群角色綁定)資源對象,就可以完成權限綁定了。

4、Role and ClusterRole
- 在 RBAC API 中,Role 表示一組規(guī)則權限,權限只能增加(累加權限),不存在一個資源一開始就有很多權限而通過 RBAC 對其進行減少的操作。也就是說只有白名單權限,而沒有黑名單權限的概念。
- Role 只能定義在一個 namespace 中,如果想要跨 namespace 則可以創(chuàng)建 ClusterRole,也就是說定義 ClusterRole 不需要綁定 namespace。
4.1 Role 示例
apiVersion: rbac.authorization.k8s.io/v1 #指定 core API 組和版本 kind: Role #指定類型為 Role metadata: namespace: default #使用默認命令空間 name: pod-reader #Role 的名稱 rules: #定義規(guī)則 - apiGroups: [""] #""表示 apiGroups 和 apiVersion 使用相同的 core API 組,即 rbac.authorization.k8s.io resources: ["pods"] #資源對象為 Pod 類型 verbs: ["get", "watch", "list"] #被授予的操作權限 #以上配置的意義是,如果把 pod-reader 這個 Role 賦予給一個用戶,那么這個用戶將在 default 命令空間中具有對 Pod 資源對象 進行 get(獲取)、watch(監(jiān)聽)、list(列出)這三個操作權限。
4.2 ClusterRole 示例
apiVersion: rbac.authorization.k8s.io/v1 #這里使用的是 rbac.authorization.k8s.io/v1,這是 RBAC API 的穩(wěn)定版本。 kind: ClusterRole #ClusterRole資源類型 metadata: # "namespace" 被忽略,因為 ClusterRoles 不受名字空間限制 name: secret-reader rules: #定義了角色的權限規(guī)則。 - apiGroups: [""] #指定了 API 組,"" 表示核心 API 組 resources: ["secrets"] #資源對象為 Secret 類型 verbs: ["get", "watch", "list"] #指定允許的操作
5、RoleBinding and ClusterRoleBinding
- RoloBinding 可以將角色中定義的權限授予用戶或用戶組,RoleBinding 包含一組主體(subject),subject 中包含有不同形式的待授予權限資源類型(User、Group、ServiceAccount);
- RoloBinding 同樣包含對被綁定的 Role 引用;
- RoleBinding 適用于某個命名空間內(nèi)授權,而 ClusterRoleBinding 適用于集群范圍內(nèi)的授權。
5.1 RoleBinding 示例1
apiVersion: rbac.authorization.k8s.io/v1 #這里使用的是 rbac.authorization.k8s.io/v1,這是 RBAC API 的穩(wěn)定版本。 kind: RoleBinding #ClusterRole資源類型 metadata: name: read-pods namespace: default subjects: - kind: User name: zhangsan apiGroup: rbac.authorization.k8s.io #組類信息 roleRef: kind: Role #類型 name: pod-reader #名稱 apiGroup: rbac.authorization.k8s.io #將 default 命名空間的 pod-reader Role 授予 zhangsan 用戶,此后 zhangsan 用戶在 default 命名空間中將具有 pod-reader 的權限。
5.2 RoleBinding 示例2
- RoleBinding 同樣可以引用 ClusterRole 來對當前 namespace 內(nèi) User、Group 或 ServiceAccount 進行授權, 這種操作允許集群管理員在整個集群內(nèi)定義一些通用的 ClusterRole,然后在不同的 namespace 中使用 RoleBinding 來引用。
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: read-secrets namespace: kube-public subjects: - kind: User name: lisi apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: secret-reader apiGroup: rbac.authorization.k8s.io #以上 RoleBinding 引用了一個 ClusterRole,這個 ClusterRole 具有整個集群內(nèi)對 secrets 的訪問權限;但是其授權用戶 lisi 只能訪問 kube-public 空間中的 secrets(因為 RoleBinding 定義在 kube-public 命名空間)。 #使用 ClusterRoleBinding 可以對整個集群中的所有命名空間資源權限進行授權
5.2 ClusterRoleBinding 示例
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding 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 #以上 ClusterRoleBinding 授權 manager 組內(nèi)所有用戶在全部命名空間中對 secrets 進行訪問。
6、Resources
Kubernetes 集群內(nèi)一些資源一般以其名稱字符串來表示,這些字符串一般會在 API 的 URL 地址中出現(xiàn); 同時某些資源也會包含子資源,例如 log 資源就屬于 pods 的子資源,API 中對 Pod 日志的請求 URL 樣例如下:
GET /api/v1/namespaces/{namespace}/pods/{name}/log
#在這里,pods 對應名字空間作用域的 Pod 資源,而 log 是 pods 的子資源。
#如果要在 RBAC 授權模型中控制這些子資源的訪問權限,可以通過 / 分隔符來分隔資源和子資源實現(xiàn)。
#以下是一個定義允許某主體讀取 pods 同時訪問這些 Pod 的 log 子資源的 Role 定義樣例: apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: default name: pod-and-pod-logs-reader rules: - apiGroups: [""] resources: ["pods", "pods/log"] verbs: ["get", "list"] #rules.verbs有:"get", "list", "watch", "create", "update", "patch", "delete", "exec" #rules.resources有:"services", "endpoints", "pods", "secrets", "configmaps", "crontabs", "deployments", "jobs", "nodes", "rolebindings", "clusterroles", "daemonsets", "replicasets", "statefulsets", "horizontalpodautoscalers", "replicationcontrollers", "cronjobs" #rules.apiGroups有:"","apps", "autoscaling", "batch"
三、準入控制(Admission Control)
- 相當于k8s的安全機制
- 準入控制是 API Server 的一個準入控制器插件列表,通過添加不同的插件,實現(xiàn)額外的準入控制規(guī)則。發(fā)送到 API Server 的請求都需要經(jīng)過這個列表中的每個準入控制器插件的檢查,檢查不通過,則拒絕請求。
- 一般建議直接采用官方默認的準入控制器。
1、官方準入控制器推薦列表(不同版本各有不同)
NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,NodeRestriction
2、列舉幾個插件的功能
- NamespaceLifecycle:用于命令空間回收,防止在不存在的 namespace 上創(chuàng)建對象,防止刪除系統(tǒng)預置 namespace,刪除 namespace 時,連帶刪除它的所有資源對象。
- LimitRanger:用于配額管理,確保請求的資源不會超過資源所在 Namespace 的 LimitRange 的限制。
- ServiceAccount:用于在每個 Pod 中自動化添加 ServiceAccount,方便訪問 API Server。
- ResourceQuota:基于命名空間的高級配額管理,確保請求的資源不會超過資源的 ResourceQuota 限制。
- NodeRestriction: 用于 Node 加入到 K8S 群集中以最小權限運行。
https://kubernetes.io/zh/docs/reference/access-authn-authz/admission-controllers/ #官方文檔參考
四、創(chuàng)建一個用戶只能管理指定的命令空間
1、創(chuàng)建一個用戶
useradd liu #新建用戶 passwd liu #修改密碼

2、使用新建用戶驗證登錄
su - liu #切換用戶 kubectl get pod #查看資源信息 #使用這個用戶進行資源操作,會發(fā)現(xiàn)連接 API Server 時被拒絕訪問請求

3、準備需要的證書
mkdir /opt/liu
#新建目錄
cd /opt/liu/
#切換目錄
#上傳需要的cfssl證書工具
chmod +x *
#添加執(zhí)行權限
mv ./* /usr/local/bin/
#移動需要的證書到/usr/local/bin/目錄
#先上傳證書生成工具 cfssl、cfssljson、cfssl-certinfo 到 /usr/local/bin 目錄中
---------------------------------------------------------------------------------------------------------
#編輯創(chuàng)建用于用戶連接到 API Server 所需的證書
vim user-cert.sh
cat > liu-csr.json <<EOF
{
"CN": "liu",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
EOF
#API Server 會把客戶端證書的 CN 字段作為 User,把 names.O 字段作為 Group
cd /etc/kubernetes/pki/
cfssl gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes /opt/liu/liu-csr.json | cfssljson -bare liu
#使用 cfssl 工具生成 TLS 證書和私鑰
---------------------------------------------------------------------------------------------------------
chmod +x user-cert.sh
#添加執(zhí)行權限
./user-cert.sh
#執(zhí)行
#/etc/kubernetes/pki/ 目錄中會生成 liu-key.pem、liu.pem、liu.csr



4、編輯創(chuàng)建用于用戶連接到 API Server 所需的 kubeconfig 文件
cd /opt/liu
#切換目錄
-------------------------------------------------------------------------------------------------------
#編輯需要的kubeconfig文件
vim rbac-kubeconfig.sh
APISERVER=$1
# 設置集群參數(shù)
export KUBE_APISERVER="https://$APISERVER:6443"
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=liu.kubeconfig
# 設置客戶端認證參數(shù)
kubectl config set-credentials liu \
--client-key=/etc/kubernetes/pki/liu-key.pem \
--client-certificate=/etc/kubernetes/pki/liu.pem \
--embed-certs=true \
--kubeconfig=liu.kubeconfig
# 設置上下文參數(shù)
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=liu \
--namespace=xxxx \
--kubeconfig=liu.kubeconfig
# 使用上下文參數(shù)生成 liu.kubeconfig 文件
kubectl config use-context kubernetes --kubeconfig=liu.kubeconfig
-------------------------------------------------------------------------------------------------------
kubectl create namespace xxxx
#創(chuàng)建命名空間
chmod +x rbac-kubeconfig.sh
#添加權限
./rbac-kubeconfig.sh 192.168.10.11
#執(zhí)行

5、準備config配置文件
cat liu-kubeconfig #查看證書 mkdir /home/liu/.kube #新建目錄 cp liu.kubeconfig /home/liu/.kube/config #復制配置文件到指定目錄 chown -R liu:liu /home/liu/.kube/ #修改屬主屬組


6、RBAC授權
#編輯yaml配置文件,RBAC授權 vim rbac.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: xxxx name: pod-reader rules: - apiGroups: [""] resources: ["pods"] verbs: ["get","watch","list","create","delete"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: read-pods namespace: xxxx subjects: - kind: User name: liu apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io kubectl apply -f rbac.yaml #創(chuàng)建資源 kubectl get role,rolebinding -n xxxx #查看資源信息

7、驗證測試
su - liuyanfen
#切換用戶,測試操作權限
#編輯創(chuàng)建pod資源清單
vim pod-test.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-test
spec:
containers:
- name: nginx
image: nginx
kubectl create -f pod-test.yaml
#創(chuàng)建資源
kubectl get pod -o wide
#創(chuàng)建pod資源詳細信息
kubectl get svc
#查看svc資源信息,訪問 svc 資源就會被拒絕
kubectl get pods -n default
#也無法訪問 default 命名空間
kubectl get pods --all-namespaces -owide
#使用 root 用戶查看
#由此可以看出 RoleBinding 的用戶只能管理指定的命令空間中的資源
kubectl create rolebinding liu-admin-binding --clusterrole=admin --user=liu --namespace=xxxx
#也可以通過綁定 admin 角色,來獲得管理員權限



總結(jié)
K8S安全機制
- 認證,鑒權,準入控制
認證
- Token認證:使用很長很復雜Token字符串做認證,通常是單向認證
- Basic認證:使用賬號和密碼的格式通過base64編碼和解碼認證,通常是單向認證
- https認證:使用通過CA機構簽發(fā)的證書,進行https認證,可以實現(xiàn)雙向認證
K8S認證(Kubectl、Kubelet、Controller-Manager、Scheduler等)與APIServer通信,是使用https證書認證,默認使用6443端口通信,使用Kubeconfig配置文件就知道使用了什么證書連接到哪個K8S集群的APIServer
Pod形式運行的組件(Dashboard、CoreDNS、外置存儲存儲插件(PROVISIONER))與APIServer通信,使用的是ServiceAccount作為Pod的服務賬號來去訪問APIServer,每個Pod都會有一個ServiceAccount服務賬號,可以創(chuàng)建Pod資源的時候去指定ServiceAccount字段
鑒權
- AlwaysDeny、AlwaysAllow、ABAC、WebHook、RBAC(默認控制策略)
RBAC四個資源對象
角色Role、ClusterRole都可以是實現(xiàn)定義角色的賦予某些資源(Rules、Resource)的操作權限(Rules、Verbs)
- Role 受命名空間影響,只能在某一個命名空間中有效
- ClusterRole 默認可以在K8S當中所有命名空間有效,配置中不需要定義NameSpace
角色綁定 RoleBinding、ClusterRoleBinding 把賬戶主題綁定Subject(User、Group、ServiceAccount)和角色進行綁定,使主體和賬戶具有相關資源的操作權限
- RoleBinding:和同一個命名空間的Role去綁定的話,可以使主體賬戶在這個空間中具有相關資源的操作權限,和ClusterRole綁定,以主體賬戶在RoleBinding所在的命名空間中具有相關資源的操作權限
- ClusterRoleBinding: 和ClusterRole綁定,可以使主體賬戶在K8S所有的命名空間中具有資源的相關操作權限
創(chuàng)建RBAC鑒權
- 先創(chuàng)建Role ClusterRole 定義角色賦予某些資源的操作權限
- 再創(chuàng)建RoleBinding和ClusterRoleBinding 把主體和角色進行綁定
準入控制
- 添加準入控制插件,實現(xiàn)額外的準入控制規(guī)則對資源進行請求做檢查
舉例:
如果你想讓一個Pod、Service、ConfigMap、Secret等普通用戶,具有接入K8s集群相關資源的操作權限
創(chuàng)建Service Account或者用戶
做認證 Token 證書認證
- Service Account 會自動生成Service Account Token的Secret資源
- 用戶需要創(chuàng)建證書,把cfssl等工具通過CA證書和私鑰文件生成證書和私鑰,使用CA證書和私鑰文件創(chuàng)建Kubeconfig配置文件,把Kubeconfig配置文件導入自動的家目錄中,kube/config文件中
做RBAC鑒權 RoleClusterRole 創(chuàng)建角色賦予給資源的操作權限,RoleBinding|ClusterRoleBinding 把用戶(主體)和角色進行綁定,此后Pod或者用戶就具有相關的命名空間中對相關資源有了操作權限
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

