Kubernetes-一文詳解ServiceAccount與RBAC權限控制

一、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
    ...
    Bash
  • ServiceAccount是給運行在Pod的程序使用的身份認證,Pod容器的進程需要訪問API Server時用的就是ServiceAccount賬戶;ServiceAccount僅侷限它所在的namespace,每個namespace創建時都會自動創建一個default service account;創建Pod時,如果沒有指定Service Account,Pod則會使用default Service Account。

     

2.Secret 與 SA(ServiceAccount) 的關係

Kubernetes設計了一種Secret資源,分爲兩類,一種是用於 ServiceAccount 的 kubernetes.io/ service-account-token,就是上邊說的 SA,每創建一個SA,就會隨之創建一個Secret;另一種就是用戶自定義的保密信息Opaque。

3.默認的Service Account

ServiceAccount僅侷限它所在的namespace,所以在創建namespace時會自動創建一個默認的 SA,而 SA 創建時,也會創建對應的 Secret,下面操作驗證下:

創建名稱空間

[root@Centos8 .kube]# kubectl create ns vfan
namespace/vfan created
Bash

查看SA

[root@Centos8 .kube]# kubectl get sa -n vfan
NAME      SECRETS   AGE
default   1         67s
Bash

查看 SA 的 Secret

[root@Centos8 .kube]# kubectl describe sa default -n vfan
Name:                default
Namespace:           vfan
Labels:              
Annotations:         
Image pull secrets:  
Mountable secrets:   default-token-wwbc8
Tokens:              default-token-wwbc8
Events:              

[root@Centos8 ~]# kubectl get secret -n vfan
NAME                  TYPE                                  DATA   AGE
default-token-wwbc8   kubernetes.io/service-account-token   3      3m15s
Bash

可以看到,創建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
YAMLCopy
[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
...
Bash

在不指定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端的驗證
Bash

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:              
Annotations:         
Image pull secrets:  
Mountable secrets:   vfansa-token-9s8f7
Tokens:              vfansa-token-9s8f7
Events:              

[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    # 加入此參數
YAMLCopy
[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
...
Bash

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

 

Bash

將 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

 

Bash

查看 SA 的 Image pull secrets

[root@Centos8 rbac]# kubectl describe sa vfansa -n vfan 
Name:                vfansa
Namespace:           vfan
Labels:              
Annotations:         
Image pull secrets:  myregistrykey  #已添加成功
Mountable secrets:   vfansa-token-9s8f7
Tokens:              vfansa-token-9s8f7
Events:   

 

Bash

這個時候,只要是使用此 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"] #賦予的權限

 

YAML

以上Role策略表示在名字爲 vfan namespace 中,對Pods有get,watch,list的權限

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"]

 

YAML

以上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
test-clusterrole                                                       30s

 

Bash

可以看到,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

 

YAML

此策略表示,將名稱爲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

 

YAML

以上策略表示,將名稱爲test-clusterrole的ClusterRole的資源權限賦予給了名稱爲vfan的用戶,雖然賦予的是ClusterRole,但是由於Role僅作用於單個namespace,所以此資源策略僅僅對vfan namespace有效

創建ClusterRoleBinding

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

 

YAML

以上策略表示,將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?

 

Bash

默認肯定是訪問不到的,如果想要訪問,必須要創建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/

 

Bash

創建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"
    }
  ]
}

 

Bash

開始創建訪問證書

[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

 

Bash

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.

 

Bash

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

 

YAML

把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/

 

Bash

切換上下文,使kubectl讀取到config的信息

[vfan@Centos8 .kube]$ kubectl config use-context kubernetes --kubeconfig=config 
Switched to context "kubernetes".

 

Bash

開始測試權限

[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"

 

Bash

可以get pod,但是不可以get service,因爲之前的Role中明確的表示了自己只有get,watch,list Pod的權限

在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

 

Bash

可以看到,vfan用戶也可以查看到相對應的Pod,因爲vfan用戶在get pod時並沒有指定名稱空間,所以可以證明vfan用戶的默認名稱空間即是vfan

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章