📊 Kubernetes的RBAC权限管理
📊 K8S默认基于sa进行认证
⚙️ 为何需要Service Account
Kubernetes原生(kubernetes-native)托管就支持sa账号,通常需要直接与API Server进行交互以获取必要的信息;
API Server同样需要对这类来自于Pod资源中客户端程序进行身份验证,Service Account也就是设计专用于这类场景的账号;
ServiceAccount是API Server支持的标准资源类型之一
基于资源对象保存ServiceAccount的数据;
认证信息保存于ServiceAccount对象专用的Secret中(v1.23-版本)
隶属名称空间级别,专供集群上的Pod中的进程访问API Server时使用;
⚙️ Pod使用ServiceAccount方式
在Pod上使用ServiceAccount有两种方式:
自动设定:
Service Account通常由API Server自动创建并通过ServiceAccount准入控制器自动关联到集群中创建的每个Pod上;
如果Pop没有定义serviceAccountName字段,则默认使用当前名称空间下的一个"default"的sa账号;
自定义:
在Pod规范上,使用serviceAccountName指定要使用的特定ServiceAccount;
Kubernetes基于三个组件完成Pod上serviceaccount的自动化,分别对应: ServiceAccount Admission Controller,Token Controller,ServiceAccount Controller。
ServiceAccount Admission Controller
API Server准入控制器插件,主要负责完成Pod上的ServiceAccount的自动化。为每个名称空间自动生成一个"default"的sa,若用户未指定sa,则默认使用"default"。
Token Controller:
为每一个sa分配一个token的组件,已经集成到Controller manager的组件中。
ServiceAccount Controller:
为sa生成对应的数据信息,已经集成到Controller manager的组件中。
温馨提示
需要用到特殊权限时,可为Pod指定要使用的自定义ServiceAccount资源对象
⚙️ ServiceAccount Token的不同实现方式
ServiceAccount使用专用的Secret对象(Kubernetes v1.23-)存储相关的敏感信息
Secret对象的类型标识为“kubernetes.io/service-account-token”
该Secret对象会自动附带认证到API Server用到的Token,也称为ServiceAccount Token
ServiceAccount Token的不同实现方式
Kubernetes v1.20-
系统自动生成专用的Secret对象,并基于secret卷插件关联至相关的Pod;
Secret中会自动附带Token且永久有效(安全性低,如果将来获取该token可以长期登录)
Kubernetes v1.21-v1.23
系统自动生成专用的Secret对象,并通过projected卷插件关联至相关的Pod;
Pod不会使用Secret上的Token,被弃用后,在未来版本就不在创建该token。
而是由Kubelet向TokenRequest API请求生成,默认有效期为一年,且每小时更新一次;
Kubernetes v1.24+
系统不再自动生成专用的Secret对象。
而是由Kubelet负责向TokenRequest API请求生成Token,默认有效期为一年,且每小时更新一次;
⚙️ 案例
🔧 创建sa并让pod引用指定的sa
[root@master231 auth]# vim sa-pods.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: lili
---
apiVersion: v1
kind: Pod
metadata:
name: liliyy-pods-sa
spec:
# 使用sa的名称
serviceAccountName: lili
containers:
- name: c1
image: registry.cn-hangzhou.aliyuncs.com/yinzhengjie-k8s/apps:v1
[root@master231 auth]# kubectl apply -f sa-pods.yaml
[root@master231 auth]# kubectl get po,sa -o wide
🔧 验证Pod使用sa的验证身份
[root@master231 auth]# kubectl exec -it liliyy-pods-sa -- sh
/ # ls -l /var/run/secrets/kubernetes.io/serviceaccount
/ # cat /var/run/secrets/kubernetes.io/serviceaccount/token
/ # TOKEN=`cat /var/run/secrets/kubernetes.io/serviceaccount/token`
/ # curl -k -H "Authorization: Bearer ${TOKEN}" https://kubernetes.default.svc.oldboyedu.com;echo
📊 启用authorization模式
在kube-apiserver上使用“--authorization-mode”选项进行定义,多个模块彼此间以逗号分隔。
kubeadm部署的集群,默认启用了Node和RBAC。
API Server中的鉴权框架及启用的鉴权模块负责鉴权:
支持的鉴权模块:
Node:
专用的授权模块,它基于kubelet将要运行的Pod向kubelet进行授权。
ABAC:
通过将属性(包括资源属性、用户属性、对象和环境属性等)组合在一起的策略,将访问权限授予用户。
RBAC:
基于企业内个人用户的角色来管理对计算机或网络资源的访问的鉴权方法。
Webhook:
用于支持同Kubernetes外部的授权机制进行集成。
另外两个特殊的鉴权模块是AlwaysDeny和AlwaysAllow。
📊 RBAC基础概念
⚙️ 实体(Entity)
在RBAC也称为Subject,通常指的是User、Group或者是ServiceAccount;
⚙️ 角色(Role)
承载资源操作权限的容器;
⚙️ 资源(Resource)
在RBAC中也称为Object,指代Subject期望操作的目标,例如Service,Deployments,ConfigMap,Secret、Pod等资源。
仅限于"/api/v1/..."及"/apis///..."起始的路径;
其它路径对应的端点均被视作“非资源类请求(Non-Resource Requests)”,例如"/api"或"/healthz"等端点;
⚙️ 动作(Actions)
Subject可以于Object上执行的特定操作,具体的可用动作取决于Kubernetes的定义。
资源型对象:
只读操作:get、list、watch等;
读写操作:create、update、patch、delete、deletecollection等;
非资源型端点仅支持"get"操作。
⚙️ 角色绑定(Role Binding)
将角色关联至实体上,它能够将角色具体的操作权限赋予给实体;
⚙️ 角色的类型
Namespace级别
称为Role,定义名称空间范围内的资源操作权限集合。
Namespace和Cluster级别
称为ClusterRole,定义集群范围内的资源操作权限集合,包括集群级别及名称空间级别的资源对象。
⚙️ 角色绑定的类型
Cluster级别
称为ClusterRoleBinding,可以将实体(User、Group或ServiceAccount)关联至ClusterRole。
Namespace级别
称为RoleBinding,可以将实体关联至ClusterRole或Role。
即便将Subject使用RoleBinding关联到了ClusterRole上,该角色赋予到Subject的权限也会降级到RoleBinding所属的Namespace范围之内。
⚙️ ClusterRole
启用RBAC鉴权模块时,API Server会自动创建一组ClusterRole和ClusterRoleBinding对象;
多数都以“system:”为前缀,也有几个面向用户的ClusterRole未使用该前缀,如cluster-admin、admin等;
它们都默认使用“kubernetes.io/bootstrapping: rbac-defaults”这一标签;
默认的ClusterRole大体可以分为5个类别:
API发现相关的角色
包括system:basic-user、system:discovery和system:public-info-viewer
面向用户的角色
包括cluster-admin、admin、edit和view
核心组件专用的角色:
包括system:kube-scheduler、system:volume-scheduler、system:kube-controller-manager、system:node和system:node-proxier等
其它组件专用的角色:
包括system:kube-dns、system:node-bootstrapper、system:node-problem-detector和system:monitoring等;
内置控制器专用的角色:
专为内置的控制器使用的角色,具体可参考官网文档;
⚙️ 查看面向用户的四个角色
🔧 查看角色列表
[root@master231 rbac]# kubectl get clusterrole |egrep -v "^system|calico|flannel|metallb|kubeadm|tigera"
🔧 相关角色说明
从权限角度而言,其中cluster-admin相当于Linux的root用户。
其次是admin,edit和view权限依次减小。其中view权限最小,对于的大多数资源只能读取。
🔧 查看集群角色'cluster-admin'相当于Linux的root用户
[root@master231 rbac]# kubectl get clusterrole cluster-admin -o yaml
⚙️ 将自定义的kubeconfig文件的用户进行授权
🔧 环境准备(未授权前)
[root@worker232 ~]# kubectl get pods --kubeconfig=lili-k8s-token.conf
🔧 授权用户
[root@master231 rbac]# kubectl create clusterrolebinding myuser --clusterrole=cluster-admin --user=lili
🔧 查看集群角色绑定信息
[root@master231 rbac]# kubectl get clusterrolebindings myuser
[root@master231 rbac]# kubectl get clusterrolebindings myuser -o yaml
🔧 验证权限
[root@worker232 ~]# kubectl get pods --kubeconfig=lili-k8s-token.conf -n kube-system
[root@worker232 ~]# kubectl get nodes --kubeconfig=lili-k8s-token.conf
🔧 删除绑定关系
[root@master231 rbac]# kubectl get clusterrolebindings myuser
[root@master231 rbac]# kubectl delete clusterrolebindings myuser
[root@master231 rbac]# kubectl get clusterrolebindings myuser
🔧 验证客户端权限会立即生效
[root@worker232 ~]# kubectl get pods --kubeconfig=lili-k8s-token.conf -n kube-system
[root@worker232 ~]# kubectl get nodes --kubeconfig=lili-k8s-token.conf
📊 验证管理员绑定的cluster-admin角色
⚙️ 查看集群角色绑定
[root@master231 rbac]# kubectl get clusterrolebindings cluster-admin -o yaml
⚙️ 查看管理员证书
[root@master231 rbac]# kubectl config view --raw -o jsonpath='{.users[0].user.client-certificate-data}' | base64 -d > /tmp/xixi.cert
[root@master231 rbac]# openssl x509 -in /tmp/xixi.cert -text
📊 Role授权给一个用户类型案例
⚙️ 未授权前测试
[root@worker233 ~]# cp lili-k8s-certs.conf ~/.kube/config
[root@worker233 ~]# kubectl get pods -o wide
[root@worker233 ~]# kubectl config view
⚙️ 创建Role
[root@master231 rbac]# kubectl create role reader --resource=po,svc --verb=get,watch,list -o yaml --dry-run=client
[root@master231 rbac]# kubectl create role reader --resource=po,svc,deploy --verb=get,watch,list
[root@master231 rbac]# kubectl get role
⚙️ 创建角色绑定
[root@master231 rbac]# kubectl create rolebinding lili-as-reader --user=lili --role=reader -o yaml --dry-run=client
[root@master231 rbac]# kubectl create rolebinding lili-as-reader --user=lili --role=reader
[root@master231 rbac]# kubectl get rolebindings -o wide
⚙️ 授权后再次验证
[root@worker233 ~]# kubectl get pods,svc,deploy
[root@worker233 ~]# kubectl delete pods --all
[root@worker233 ~]# kubectl get pods -n kube-system
⚙️ 修改权限的两种方式
🔧 方式一(响应式)
🧩 响应式修改权限
[root@master231 pods]# kubectl create role reader --resource=po,svc,deploy --verb=get,watch,list,delete -o yaml --dry-run=client | kubectl apply -f -
🧩 测试验证
[root@worker233 ~]# kubectl get pods,svc,deploy
[root@worker233 ~]# kubectl delete pods --all
[root@worker233 ~]# kubectl get pods,svc,deploy
🔧 方式二(声明式)
🧩 声明式修改权限
[root@master231 pods]# kubectl create role reader --resource=po,svc --verb=get,watch,list -o yaml --dry-run=client
[root@master231 pods]# kubectl create role reader --resource=po,svc --verb=get,watch,list -o yaml --dry-run=client > /tmp/reader.yaml
[root@master231 pods]# kubectl apply -f /tmp/reader.yaml
🧩 测试验证
[root@worker233 ~]# kubectl get deploy,svc,po -o wide
📊 ClusterRole授权给一个用户组类型案例
⚙️ 授权前测试
[root@worker232 ~]# kubectl config view --kubeconfig=lili-k8s-token.conf
[root@worker232 ~]# kubectl get pods --kubeconfig=lili-k8s-token.conf
⚙️ 创建集群角色
[root@master231 pods]# kubectl create clusterrole reader --resource=deploy,rs,pods --verb=get,watch,list -o yaml --dry-run=client
[root@master231 pods]# kubectl create clusterrole reader --resource=deploy,rs,pods --verb=get,watch,list
[root@master231 pods]# kubectl get clusterrole reader
⚙️ 将集群角色绑定给k3s组
[root@master231 pods]# cat /etc/kubernetes/pki/token.csv
[root@master231 pods]# kubectl create clusterrolebinding k8s-as-reader --clusterrole=reader --group=k3s -o yaml --dry-run=client
[root@master231 pods]# kubectl create clusterrolebinding k8s-as-reader --clusterrole=reader --group=k3s
[root@master231 pods]# kubectl get clusterrolebindings k8s-as-reader
[root@master231 pods]# kubectl get clusterrolebindings k8s-as-reader -o wide
⚙️ 基于kubeconfig测试
[root@worker232 ~]# kubectl get deploy,rs,pod --kubeconfig=./lili-k8s-token.conf
[root@worker232 ~]# kubectl get no --kubeconfig=./lili-k8s-token.conf
⚙️ 基于token测试
[root@worker232 ~]# kubectl --server=https://10.0.0.231:6443 --token=8fd32c.0868709b9e5786a8 --certificate-authority=/etc/kubernetes/pki/ca.crt get deploy -o wide -A
liliyy属于k8s组,不属于k3s组,因此无法访问
[root@worker232 ~]# kubectl --server=https://10.0.0.231:6443 --token=497804.9fc391f505052952 --certificate-authority=/etc/kubernetes/pki/ca.crt get deploy,rs,po -o wide -A
⚙️ 更新权限
[root@master231 pods]# kubectl create clusterrole reader --resource=deploy,pods,no --verb=get,watch,list -o yaml --dry-run=client | kubectl apply -f -
⚙️ 测试验证
[root@worker232 ~]# kubectl get no --kubeconfig=./lili-k8s-token.conf
📊 ClusterRole授权给一个ServiceAccount类型案例
⚙️ 导入镜像
[root@worker233 ~]# wget http://192.168.16.253/Resources/Kubernetes/Case-Demo/Python/python-v3.9.16.tar.gz
[root@worker233 ~]# docker load -i python-v3.9.16.tar.gz
[root@worker233 ~]# docker tag python:3.9.16-alpine3.16 harbor250.oldboyedu.com/case-demo/python:3.9.16-alpine3.16
[root@worker233 ~]# docker push harbor250.oldboyedu.com/case-demo/python:3.9.16-alpine3.16
⚙️ 编写资源清单
root@master231 rbac]# cat lili-sa-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: kube-public
name: lili
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: xiuxian
namespace: kube-public
spec:
replicas: 1
selector:
matchLabels:
app: xiuxian
template:
metadata:
labels:
app: xiuxian
spec:
nodeName: worker232
serviceAccountName: lili
containers:
- image: harbor250.oldboyedu.com/case-demo/python:3.9.16-alpine3.16
command:
- tail
- -f
- /etc/hosts
name: apps
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: reader-lili
rules:
- apiGroups:
- ""
resources:
- pods
- services
verbs:
- get
- watch
- list
- delete
- apiGroups:
- apps
resources:
- deployments
verbs:
- get
- watch
- list
- delete
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: reader-lili-bind
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: reader-lili
subjects:
- kind: ServiceAccount
name: lili
namespace: kube-public
⚙️ 创建资源
[root@master231 rbac]# kubectl apply -f lili-sa-rbac.yaml
[root@master231 rbac]# kubectl get deploy,sa,po -o wide -n kube-public
⚙️ 安装依赖包
[root@master231 rbac]# kubectl -n kube-public exec -it xiuxian-cd5bc9d-5nrx7 -- sh
/ # python -V
Python 3.9.16
/ # pip install kubernetes -i https://pypi.tuna.tsinghua.edu.cn/simple/
...
Successfully installed cachetools-5.5.2 certifi-2025.1.31 charset-normalizer-3.4.1 durationpy-0.9 google-auth-2.38.0 idna-3.10 kubernetes-32.0.1 oauthlib-3.2.2 pyasn1-0.6.1 pyasn1-modules-0.4.2 python-dateutil-2.9.0.post0 pyyaml-6.0.2 requests-2.32.3 requests-oauthlib-2.0.0 rsa-4.9 six-1.17.0 urllib3-2.4.0 websocket-client-1.8.0
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
WARNING: You are using pip version 22.0.4; however, version 25.0.1 is available.
You should consider upgrading via the '/usr/local/bin/python -m pip install --upgrade pip' command.
⚙️ 编写python脚本
/ # cat > view-k8s-resources.py <<EOF
from kubernetes import client, config
with open('/var/run/secrets/kubernetes.io/serviceaccount/token') as f:
token = f.read()
configuration = client.Configuration()
configuration.host = "https://10.0.0.231:6443" # APISERVER地址
configuration.ssl_ca_cert="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" # CA证书
configuration.verify_ssl = True # 启用证书验证
configuration.api_key = {"authorization": "Bearer " + token} # 指定Token字符串
client.Configuration.set_default(configuration)
apps_api = client.AppsV1Api()
core_api = client.CoreV1Api()
try:
print("###### Deployment列表 ######")
#列出default命名空间所有deployment名称
for dp in apps_api.list_namespaced_deployment("kube-public").items:
print(dp.metadata.name)
except:
print("没有权限访问Deployment资源!")
try:
#列出default命名空间所有pod名称
print("###### Pod列表 ######")
for po in core_api.list_namespaced_pod("kube-public").items:
print(po.metadata.name)
except:
print("没有权限访问Pod资源!")
EOF
⚙️ 运行python脚本
/ # python3 view-k8s-resources.py
⚙️ 更新权限
[root@master231 rbac]# kubectl get clusterrolebinding reader-lili-bind -o wide
[root@master231 rbac]# kubectl delete clusterrolebinding reader-lili-bind
[root@master231 rbac]# kubectl get clusterrolebinding reader-lili-bind -o wide
⚙️ 再次测试验证
/ # python3 view-k8s-resources.py