一、ServiceAccount
1.ServiceAccount 介紹
首先Kubernetes中賬戶區分為:User Accounts(使用者賬戶) 和 Service Accounts(服務賬戶) 兩種,它們的設計及用途如下:
-
UserAccount是給kubernetes叢集外部使用者使用的,例如運維或者叢集管理人員,使用kubectl命令時用的就是UserAccount賬戶;UserAccount是全域性性。在叢集所有namespaces中,名稱具有唯一性,預設情況下使用者為admin;
使用者名稱稱可以在kubeconfig中檢視
[root@Centos8 ~]# cd ~/.kube/ [root@Centos8 .kube]# ls cache config http-cache [root@Centos8 .kube]# cat config users: - name: kubernetes-admin
- ServiceAccount是給執行在Pod的程式使用的身份認證,Pod容器的程式需要訪問API Server時用的就是ServiceAccount賬戶;ServiceAccount僅侷限它所在的namespace,每個namespace都會自動建立一個default service account;建立Pod時,如果沒有指定Service Account,Pod則會使用default Service Account。
2.Secret 與 SA 的關係
Kubernetes設計了一種Secret資源,分為兩類,一種是用於 ServiceAccount 的 kubernetes.io/ service-account-token,就是上邊說的 SA,另一種就是使用者自定義的保密資訊Opaque。
3.預設的Service Account
ServiceAccount僅侷限它所在的namespace,所以在建立namespace時會自動建立一個預設的 SA,而 SA 建立時,也會建立對應的 Secret,下面操作驗證下:
建立名稱空間
[root@Centos8 .kube]# kubectl create ns vfan
namespace/vfan created
檢視SA
[root@Centos8 .kube]# kubectl get sa -n vfan NAME SECRETS AGE default 1 67s
檢視 SA 的 Secret
[root@Centos8 .kube]# kubectl describe sa default -n vfan Name: default Namespace: vfan Labels: <none> Annotations: <none> Image pull secrets: <none> Mountable secrets: default-token-wwbc8 Tokens: default-token-wwbc8 Events: <none> [root@Centos8 ~]# kubectl get secret -n vfan NAME TYPE DATA AGE default-token-wwbc8 kubernetes.io/service-account-token 3 3m15s
可以看到,建立ns時預設建立了SA,SA預設建立了一個 kubernetes.io/service-account-token型別的secret
建立一個Pod
vim pods.yaml
apiVersion: v1 kind: Pod metadata: name: test-sa namespace: vfan spec: containers: - name: test-sa image: nginx:1.2.1 imagePullPolicy: IfNotPresent ports: - containerPort: 80
[root@Centos8 rbac]# kubectl create -f pods.yaml pod/test-sa created [root@Centos8 rbac]# kubectl get pod -n vfan NAME READY STATUS RESTARTS AGE test-sa 1/1 Running 0 12s [root@Centos8 rbac]# kubectl describe pod test-sa -n vfan ... Containers: test-sa: Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-wwbc8 (ro) Volumes: default-token-wwbc8: Type: Secret (a volume populated by a Secret) SecretName: default-token-wwbc8 Optional: false ...
在不指定SA的情況下,當前 ns下面的 Pod 會預設使用 “default” 這個 SA,對應的 Secret 會自動掛載到 Pod 的 /var/run/secrets/kubernetes.io/serviceaccount/ 目錄中,我們可以在 Pod 裡面獲取到用於身份認證的資訊。
進入Pod Container內,檢視 SA
[root@Centos8 rbac]# kubectl exec -it test-sa -n vfan -- /bin/bash root@test-sa:/# cd /var/run/secrets/kubernetes.io/serviceaccount/ root@test-sa:/var/run/secrets/kubernetes.io/serviceaccount# ls ca.crt namespace token ### 可以看到有三個檔案,作用分別為 ca.crt:根證書,用於Client端驗證API Server傳送的證書 namespace:標識這個service-account-token的作用域空間 token:使用API Server私鑰簽名的JWT,用於訪問API Server時,Server端的驗證
4.使用自定義SA
建立一個 SA
[root@Centos8 rbac]# kubectl create sa vfansa -n vfan serviceaccount/vfansa created [root@Centos8 rbac]# kubectl get sa -n vfan NAME SECRETS AGE default 1 19m vfansa 1 7s [root@Centos8 rbac]# kubectl describe sa vfansa -n vfan Name: vfansa Namespace: vfan Labels: <none> Annotations: <none> Image pull secrets: <none> Mountable secrets: vfansa-token-9s8f7 Tokens: vfansa-token-9s8f7 Events: <none> [root@Centos8 rbac]# kubectl get secret -n vfan NAME TYPE DATA AGE default-token-wwbc8 kubernetes.io/service-account-token 3 19m vfansa-token-9s8f7 kubernetes.io/service-account-token 3 49s
同樣,建立SA後,自動建立了對應的Secret
更新Pod,使用新建立的SA
vim pods.yaml
apiVersion: v1 kind: Pod metadata: name: test-sa namespace: vfan spec: containers: - name: test-sa image: nginx:1.2.1 imagePullPolicy: IfNotPresent ports: - containerPort: 80 serviceAccountName: vfansa
[root@Centos8 rbac]# kubectl create -f pods.yaml pod/test-sa created [root@Centos8 rbac]# kubectl describe pod test-sa -n vfan ... Mounts: /var/run/secrets/kubernetes.io/serviceaccount from vfansa-token-9s8f7 (ro) Volumes: vfansa-token-9s8f7: Type: Secret (a volume populated by a Secret) SecretName: vfansa-token-9s8f7 Optional: false ...
5.ServiceAccount中新增Image pull secrets
在筆者之前的部落格中:Secret介紹及演示( https://www.cnblogs.com/v-fan/p/13269433.html )中提及到,可以使用Secret來儲存映象倉庫的登入資訊,來達到免登入獲取image的效果,同樣,可以將建立好的Secret直接與SA進行繫結,繫結完成後,只要使用此 SA 的 Pod,都可達到免登入獲取image的效果
建立 docker-registry 的 Secret
[root@Centos8 rbac]# kubectl create secret docker-registry myregistrykey --docker-server=hub.vfancloud.com --docker-username=admin --docker-password=admin@123 --docker-email=vfan8991@163.com -n vfan secret/myregistrykey created [root@Centos8 rbac]# kubectl get secret -n vfan NAME TYPE DATA AGE default-token-wwbc8 kubernetes.io/service-account-token 3 62m myregistrykey kubernetes.io/dockerconfigjson 1 7s vfansa-token-9s8f7 kubernetes.io/service-account-token 3 43m
將 docker-registry 的 Secret 新增到SA
kubectl edit sa vfansa -n vfan
apiVersion: v1 kind: ServiceAccount metadata: creationTimestamp: "2020-08-30T03:38:47Z" name: vfansa namespace: vfan resourceVersion: "471829" selfLink: /api/v1/namespaces/vfan/serviceaccounts/vfansa uid: 8a44df93-b2d6-4e61-ad2e-25bc5852f66e secrets: - name: vfansa-token-9s8f7 imagePullSecrets: - name: myregistrykey
檢視 SA 的 Image pull secrets
[root@Centos8 rbac]# kubectl describe sa vfansa -n vfan
Name: vfansa
Namespace: vfan
Labels: <none>
Annotations: <none>
Image pull secrets: myregistrykey
Mountable secrets: vfansa-token-9s8f7
Tokens: vfansa-token-9s8f7
Events: <none>
這個時候,只要是使用此 SA 的Pod,都可以在docker-registry拉取映象了,同樣,可以把此 Secret 新增到default 的 SA 中,達到相同的效果
二、RBAC許可權控制
1.RBAC介紹
在Kubernetes中,所有資源物件都是通過API物件進行操作,他們儲存在etcd裡。而對etcd的操作我們需要通過訪問 kube-apiserver 來實現,上面的Service Account其實就是APIServer的認證過程,而授權的機制是通過RBAC:基於角色的訪問控制實現。
2.Role and ClusterRole
在RBAC API中,Role表示一組規則許可權,許可權只會增加(累加許可權),不存在一個資源開始就有很多許可權而通過RBAC對其進行減少的操作:Role 是定義在一個 namespace 中,而 ClusterRole 是叢集級別的。
下面我們定義一個Role:
vim roles.yaml
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: test-role namespace: vfan rules: - apiGroups: [""] # 為空表示為預設的core api group resources: ["pods"] # 資料來源型別 verbs: ["get","watch","list"] #賦予的許可權 - apiGroups: ["apps"] resources: ["deployments"] verbs: ["get","list","create","update","patch","delete","watch"]
以上Role策略表示在名字為 vfan ns中,對Pods有get,watch,list的許可權,對Deployment有......許可權
ClusterRole 具有與 Role 相同許可權角色控制能力,不同的就是 Cluster Role是叢集級別,它可以用於:
- 叢集級別的資源控制(例如 node 訪問許可權)
- 非資源型 endpoints(例如對某個目錄或檔案的訪問:/healthz)
- 所有名稱空間資源控制(Pod、Deployment等)
vim clusterroles.yaml
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: test-clusterrole rules: - apiGroups: [""] resources: ["services"] verbs: ["get","create","list"]
以上Cluster role策略表示,有get,create,list整個叢集service的許可權
下面開始建立
## role [root@Centos8 rbac]# kubectl create -f roles.yaml role.rbac.authorization.k8s.io/test-rbac created [root@Centos8 rbac]# kubectl get role -n vfan NAME AGE test-rbac 27s ## cluster role [root@Centos8 rbac]# kubectl get clusterrole -n vfan NAME AGE admin 141d cluster-admin 141d edit 141d flannel 141d ingress-nginx 90d ingress-nginx-admission 90d system:aggregate-to-admin 141d system:aggregate-to-edit 141d system:aggregate-to-view 141d
可以看到,role和cluster role都已經建立成功,但是clusterrole除了這次建立的還有許多,其中以system開頭的全部是系統所用的,其他的都是在裝一些外掛時自動新增的,也要注意,我們自己建立cluster role時不要以system開通,以免分不清楚
3.RoleBinding and ClusterRoleBinding
RoleBinding可以將角色中定義的許可權授予使用者或使用者組,RoleBinding包含一組許可權列表(Subjects),許可權列表中包含有不同形式的待授予許可權資源型別(users,groups, or Service Account):Rolebinding 同樣包含對被 Bind 的 Role 引用;RoleBinding 適用於某個名稱空間內授權,ClusterRoleBinding適用於叢集範圍內的授權。
建立RoleBinding
vim rolebindings.yaml
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: test-rolebinding namespace: vfan subjects: - kind: User # 許可權資源型別 name: vfan # 名稱 apiGroup: rbac.authorization.k8s.io roleRef: kind: Role #要繫結的Role的型別(可以是Role或ClusterRole) name: test-role # Role的名稱 apiGroup: rbac.authorization.k8s.io
此策略表示,將名稱為test-role的Role的許可權資源賦予名為vfan的使用者,僅作用於vfan namespace。
RoleBinding同樣可以引用ClusterRole來對當前 namespace 內使用者、使用者組或SA來進行授權,這種操作允許管理員在整個叢集中定義一些通用的ClusterRole,然後在不同的namespace中使用RoleBinding繫結。
vim rolebindings2.yaml
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: test-rolebinding2 namespace: vfan subjects: - kind: User name: vfan apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: test-clusterrole apiGroup: rbac.authorization.k8s.io
以上策略表示,將名稱為test-clusterrole的ClusterRole的資源許可權賦予給了名稱為vfan的使用者,雖然賦予的是ClusterRole,但是由於Role僅作用於單個namespace,所以此資源策略僅僅對vfan namespace有效
vim clusterrolebindings.yaml
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: test-clusterrolebinding subjects: - kind: Group name: vfan apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: test-clusterrole apiGroup: rbac.authorization.k8s.io
以上策略表示,將name為test-clusterrole的ClusterRole的資源許可權賦予給groupname為vfan的使用者組,此使用者組下所有使用者擁有對整個叢集的 test-clusterrole內的資源許可權
實踐:建立一個使用者只能管理名為 vfan 的NameSpace
1.建立系統使用者
[root@Centos8 rbac]# useradd vfan [root@Centos8 rbac]# su - vfan ## 進入vfan使用者測試訪問k8s叢集 [vfan@Centos8 ~]$ kubectl get pod The connection to the server localhost:8080 was refused - did you specify the right host or port?
預設肯定是訪問不到的,如果想要訪問,必須要建立vfan使用者的訪問證書
2.為 vfan 使用者建立訪問證書
## 下載證書生成工具 cfssl [root@Centos8 bin]# wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 [root@Centos8 bin]# wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 [root@Centos8 bin]# wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 ## 改名,給執行許可權 [root@Centos8 bin]# mv cfssl_linux-amd64 cfssl [root@Centos8 bin]# mv cfssljson_linux-amd64 cfssljson [root@Centos8 bin]# mv cfssl-certinfo_linux-amd64 cfssl-certinfo [root@Centos8 bin]# chmod +x * [root@Centos8 bin]# ll -h 總用量 19M -rwxr-xr-x 1 root root 9.9M 3月 30 2016 cfssl -rwxr-xr-x 1 root root 6.3M 3月 30 2016 cfssl-certinfo -rwxr-xr-x 1 root root 2.2M 3月 30 2016 cfssljson [root@Centos8 bin]# mkdir /usr/local/vfancert [root@Centos8 bin]# cd /usr/local/vfancert/
建立CA證書籤名請求JSON檔案
vim vfan-csr.json
{ "CN": "vfan", # 使用者名稱稱 "hosts": [], # 主機地址,不填表示所有主機都可使用 "key": { "algo": "rsa", # 加密演算法 "size": 2048 }, "names": [ { "C": "CN", "L": "BeiJing", "O": "Ctyun", "ST": "BeiJing", "OU": "System" } ] }
開始建立訪問證書
[root@Centos8 vfancert]# cd /etc/kubernetes/pki/ [root@Centos8 pki]# cfssl gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes /usr/local/vfancert/vfan-csr.json | cfssljson -bare vfanuser 2020/09/02 22:08:51 [INFO] generate received request 2020/09/02 22:08:51 [INFO] received CSR 2020/09/02 22:08:51 [INFO] generating key: rsa-2048 2020/09/02 22:08:51 [INFO] encoded CSR 2020/09/02 22:08:51 [INFO] signed certificate with serial number 191102646650271030964539871811792985454770130197 2020/09/02 22:08:51 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitable for websites. For more information see the Baseline Requirements for the Issuance and Management of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org); specifically, section 10.2.3 ("Information Requirements"). ## 建立成功,pki目錄下多出vfanuser-key.pem、vfanuser.pem和vfanuser.csr檔案 [root@Centos8 pki]# ls vfanuser.csr vfanuser-key.pem vfanuser.pem
3.為 vfan 使用者生成叢集配置檔案
## 設定api server的環境變數 [root@Centos8 vfancert]# export KUBE_APISERVER="https://192.168.152.53:6443" ## 建立kubeconfig檔案,以下詳細引數資訊可通過kubectl config set-cluster --help檢視 [root@Centos8 vfancert]# kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs=true --server=${KUBE_APISERVER} --kubeconfig=vfan.kubeconfig Cluster "kubernetes" set. ## 配置檔案生成 [root@Centos8 vfancert]# ls vfan-csr.json vfan.kubeconfig ## 設定客戶端引數,繫結使用者資訊至kubeconfig中 [root@Centos8 vfancert]# kubectl config set-credentials vfanuser \ > --client-certificate=/etc/kubernetes/pki/vfanuser.pem \ > --client-key=/etc/kubernetes/pki/vfanuser-key.pem \ > --embed-certs=true \ > --kubeconfig=vfan.kubeconfig User "vfanuser" set. ## 設定上下文引數 [root@Centos8 vfancert]# kubectl config set-context kubernetes \ > --cluster=kubernetes \ > --user=vfan \ > --namespace=vfan \ > --kubeconfig=vfan.kubeconfig Context "kubenetes" created.
4.進行RoleBinding 驗證許可權生效
vim vfanrolebind.yaml
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: test-rolebinding namespace: vfan subjects: - kind: User name: vfan apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: test-rbac # 繫結上文中建立的名稱為 test-rbac 的Role,具體許可權,往上翻下哈 apiGroup: rbac.authorization.k8s.io
把kubeconfig檔案複製到 vfan 使用者的家目錄的.kube下
[root@Centos8 vfancert]# mkdir -p /home/vfan/.kube [root@Centos8 vfancert]# cp vfan.kubeconfig /home/vfan/.kube/config [root@Centos8 vfancert]# cd /home/vfan/.kube/ [root@Centos8 .kube]# ls config ## 修改檔案所有者 [root@Centos8 vfan]# chown -R vfan:vfan .kube/
切換上下文,使kubectl讀取到config的資訊
[vfan@Centos8 .kube]$ kubectl config use-context kubernetes --kubeconfig=config Switched to context "kubernetes".
開始測試許可權
[vfan@Centos8 .kube]$ kubectl get pod No resources found. [vfan@Centos8 .kube]$ kubectl get svc Error from server (Forbidden): services is forbidden: User "vfan" cannot list resource "services" in API group "" in the namespace "vfan"
可以get pod,但是不可以get service,因為之前的Role中明確的表示了自己的許可權
在vfan名稱空間下建立測試Deployment
## root使用者下建立 [root@Centos8 k8sYaml]# kubectl run deployment test-vfan --replicas=3 --image=nginx:1.2.1 --namespace=vfan [root@Centos8 k8sYaml]# kubectl get pod -n vfan NAME READY STATUS RESTARTS AGE deployment-7b89b946d-5dtvp 1/1 Running 0 17s deployment-7b89b946d-jpr5v 1/1 Running 0 17s deployment-7b89b946d-r8k4l 1/1 Running 0 17s ## 前往vfan使用者檢視 [vfan@Centos8 .kube]$ kubectl get pod NAME READY STATUS RESTARTS AGE deployment-7b89b946d-5dtvp 1/1 Running 0 67s deployment-7b89b946d-jpr5v 1/1 Running 0 67s deployment-7b89b946d-r8k4l 1/1 Running 0 67s
可以看到,vfan使用者也可以檢視到相對應的Pod,因為vfan使用者在get pod時並沒有指定名稱空間,所以可以證明vfan的預設名稱空間即是vfan