一文读懂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