一文讀懂k8s RBAC權限控制


 

內容概覽

k8s API服務器在接收到請求后,會經過 1) 認證插件; 如果其中一個認證插件通過,則認證結束。2) 進入授權流程。3) 進入准入控制鏈,所有注冊的注入控制節點全部通過,則准入結束

如下圖

  

上面流程中:認證插件將返回通過認證的用戶/用戶組;然后將其交給授權信息檢查用戶/用戶組是否有權限執行某個操作。RBAC授權邏輯通過將用戶與角色綁定來決定是否可以執行某項操作。主體(User/ServiceAccount)與角色關聯,角色與資源權限關聯。

如下圖

 

 

下面來逐一看下各節點,我們按照 1) 用戶  2) 角色  3) 綁定 的順序來看

 

RBAC鑒權流程

用戶 and 用戶組

   -  真實用戶User  (k8s不維護相關資源類型,用戶和所屬用戶組全部由外部系統管控)

   - 訪問k8s的服務ServiceAccount (k8s可創建並維護)

   (其中ServiceAccount默認也是一種用戶。作為User使用時名稱為 system:serviceaccount:<ServiceAccountName>,所屬用戶組為 system:serviceaccount:<NamespaceName> )

 

創建ServiceAccount類型的用戶示例

apiVersion: v1
kind: ServiceAccount
metadata:
  name: custom

此時,基礎組件里的token-controller自動(根據--service-account-private-key-file的證書)為ServiceAccount生成 secrets,secrets中包含的token信息,即可用作http token請求中的認證信息。獲取方式如下:

# 獲取secrets名稱
[root ~/custom]# kubectl get serviceaccount custom-job -o jsonpath={.secrets[0].name} 

# 獲取token 
[root ~/custom]#  kubectl get secret <SecretName> -o jsonpath={.data.token}|base64 -d

結尾會有示例代碼

 

Role 和 ClusterRole

apiVersion: rbac.authorization.k8s.io/v1
kind: Role     # ClusterRole這里需要改
metadata:
  name: custom
  namespace: default  # ClusterRole 無namespace限制
rules:
- apiGroups:
  - batch   # jobs 所在apiGroups
  - ""
  resources:
  - jobs
  - configmaps
  verbs:
  - get
  - list

Role 與 ClusterRole 最大區別在於:Role有namespace區分,如果要應用在多個ns,需要每個ns下創建一個Role 或者 選擇ClusterRole

resources 中列出的所有資源 所屬的 apiGroups 必須填寫。apiGroups查看方式

[root@ ~/custom]# kubectl api-resources  | head -1; kubectl api-resources  | grep job 
NAME                              SHORTNAMES   APIGROUP                             NAMESPACED   KIND
cronjobs                          cj           batch                                true         CronJob
jobs                                           batch                                true         Job

結果中 jobs 所在APIGROUP為batch。核心資源所屬為 "",這個需要聲明在列表里。

 

 

RoleBind 和 ClusterRoleBind

有了角色 和 用戶,現在只需要綁定,就可以讓用戶擁有角色權限。

 以serviceaccount custom為例,來看下 User 和 ServiceAccount兩種綁定方式

# User類型綁定
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: custom
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: custom
subjects:
- kind: User
  name: system:serviceaccount:custom
  namespace: default

# ServiceAccount類型綁定
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: custom
namespace: default roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: custom subjects:
- kind: ServiceAccount name: custom-job namespace: default

如上,`roleRef` 為引用的規則, `subject` 為賦予角色的主體(用戶或serviceAccount)。

sujects 的 kind 為主體類型,包含: Group、User、ServiceAccount 三種。

sujects 的 kind 為 Group 時,name 字段有一批內置的字段,抄錄如下

sujects:
- kind: Group
  name: system:serviceaccounts:qa      # 為qa命名空間中所有serviceaccount授權
  apiGroup: rbac.authorization.k8s.io  

name: system:sesrviceaccounts # 為所有命名空間的serviceaccount授權

name: system:authenticated # 為所有已認證用戶授權

name:
system:unauthenticated # 為所有未認證用戶授權

 

上述,一個有權限的賬號創建完成。由於Role和Rolebinding都在default下創建,所以只能訪問default命名空間下的資源(僅限Role中配置的資源和action)。我們測試一下:

 

client 訪問 k8s 服務

python 訪問k8s資源方式

# python3 環境 首先安裝 kubernetes(18.20.0)包
#
!/usr/bin/env python # -*- coding: utf-8 -*- from kubernetes.client import api_client from kubernetes.client.api import core_v1_api from kubernetes import client ApiToken = "" configuration = client.Configuration() configuration.host = "https://<apiServer>:<Port>" configuration.verify_ssl = False configuration.api_key = {"authorization": "Bearer " + ApiToken} client1 = api_client.ApiClient(configuration=configuration) api = core_v1_api.CoreV1Api(client1) #ret = api.list_namespaced_pod(async_req=True) # 報錯 ret = api.list_namespaced_config_map(namespace="default", async_req=True) result = ret.get() print(result)

代碼運行后將打印 default下的所有configmap信息。 如果執行注釋內容,則返回:

kubernetes.client.exceptions.ApiException: (403)
Reason: Forbidden
HTTP response headers: HTTPHeaderDict({'Content-Type': 'application/json', 'X-Content-Type-Options': 'nosniff', 'Date': 'Wed, 27 Oct 2021 11:18:46 GMT', 'Content-Length': '289'})
HTTP response body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"pods is forbidden: User \"system:serviceaccount:default:custom\" cannot list resource \"pods\" in API group \"\" in the namespace \"kube-system\"","reason":"Forbidden","details":{"kind":"pods"},"code":403}

 

 內置的權限環境

來看下為什么kubectl時,我們為什么可以查看集群所有資源

# 查看kubectl上下文配置

[root@ ~/custom]# kubectl config view apiVersion: v1 clusters: - cluster: certificate-authority-data: DATA+OMITTED server: https://9.215.152.23:60002 name: local contexts:- context: cluster: local user: admin name: master current-context: master kind: Config preferences: {} users: - name: admin user: token: ***
contexts 是所有用戶上下文,current-context是當前使用上下文,對應用戶admin

用戶與角色綁定關系在名為admin的ClusterRoleBinding中
[root@ ~/custom]# kubectl get clusterrolebinding admin -n kube-system -o yaml 
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  ...
  name: admin
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin
  namespace: kube-system

 

看下這個角色 ClusterRole

[root@ ~/custom]# kubectl get ClusterRole -n kube-system cluster-admin -o yaml 
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  ...
  name: cluster-admin
rules:
- apiGroups:
  - '*'
  resources:
  - '*'
  verbs:
  - '*'
- nonResourceURLs:
  - '*'
  verbs:
  - '*'

 



再看下為什么pod內默認也可以訪問當前ns下的信息
隨意打開一個未掛載serviceAccount的pod,可以發現一些volume信息
# containers信息
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-z2gm7 (ro) ...
# pod信息 Volumes: default
-token-z2gm7: Type: Secret (a volume populated by a Secret) SecretName: default-token-z2gm7 Optional: false

如上,有名為 `default-token-z2gm7` 的Secret 被掛載到容器的 `/var/run/secrets/kubernetes.io/serviceaccount` 下。 根據名稱規律,我們在命名空間下找到 `default` 的ServiceAccount

[root@ ~]# kubectl describe sa default -n enqtest 
Name:                default
Namespace:           test
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   default-token-z2gm7
Tokens:              default-token-z2gm7

進入容器查看這個目錄:

[root@test  /run/secrets/kubernetes.io/serviceaccount]# ll
lrwxrwxrwx 1 root root 13 7月  20 13:14  ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root root 16 7月  20 13:14  namespace -> ..data/namespace
lrwxrwxrwx 1 root root 12 7月  20 13:14  token -> ..data/token

捋一下流程:

   1) 用戶創建ns

   2) Service Account Controller 監聽到NS創建,為其生成 default 名稱的ServiceAccount

   3) Token Controller 監聽到SA創建,會用 API私鑰(kube-controller組件的 --service-account-private-key-file) 創建一個token,並用此token、API server的CA證書(用來檢測服務器返回的准確性)、和命名空間信息,打包為一個secret對象,放在default ServiceAccount里

   4) 創建未聲明serviceAccount的pod,准入控制插件(ServiceAccount)檢測到,修改pod掛載信息注入ServiceAccount


訪問樣例
[root@ ~]# curl -H "Authorization: Bearer $TOKEN" https://<service kubernetes 的 clusterIP>:443 -k


另一個類型 User 創建流程好像是自己用證書創建,最終展現在k8s環境就是context, 后續再填坑。

債見


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM