Kubernetes技术详解-从理论到实践-(9)-访问控制-ControllingAccess
Kubernetes API访问控制摘要 Kubernetes通过API Server实现访问控制,主要分为认证、授权和准入控制三个阶段。API Server提供REST接口处理kubectl、Dashboard等客户端的请求,支持多种认证方式(x509证书、Bearer Token等)。授权模式中RBAC是默认方式,通过角色绑定实现权限管理。访问控制流程为:客户端请求→认证→授权→准入→etcd
1 ControllingAccess访问控制简介
Controlling Access,即Kubernetes API的访问控制,它属于Kubernetes的Security安全大类。我们前面经常用到的kubectl,以及下一章要讲的Dashboard,都是在向Kubernetes API Server发送请求,由API Server进行一系列处理后将结果返回kubectl或Dashboard。为避免不可信客户端发起API Server访问请求,Kubernetes在API访问过程中引入了Controlling Access访问控制机制。
2 Kubernetes API Server和访问控制
API Server是Kubernetes集群中的核心组件之一,它负责接收客户端的请求,处理这些请求,并将结果返回给客户端。这里的客户端,可以是kubectl这种命令行工具,可以是调用API Server库的程序,也可以是调用REST请求的程序(如Dashboard或curl)。REST API访问的主体可以是用户(human users)或服务账号(Kubernetes service accounts)。
2.1 API Server主要功能
API Server的主要功能如下:
| 功能 | 说明 |
|---|---|
| REST接口 | 提供HTTPS+JSON/YAML接口(/api/v1/…),供kubectl、Dashboard、Operator调用。 |
| 认证&授权 | 验证证书/BearerToken/WebHook,然后走RBAC/WebHook决定能否操作。 |
| 准入控制 | Admission Controller链(Mutating/Validating)在写入etcd前做校验/修改。 |
| 总调度器 | kube-scheduler是API Server的一个插件,API Server把待调度资源推给scheduler,再把结果写回。 |
| etcd前端 | 与etcd后端交互的组件,其他组件通过API Server间接读写集群状态。 |
2.2 API Server常用访问路径
(1) 核心 API(/api/v1)
| 功能 | 子路径 |
|---|---|
| Pod 列表 | /api/v1/namespaces/{ns}/pods |
| 单 Pod | /api/v1/namespaces/{ns}/pods/{name} |
| Pod 日志 | /api/v1/namespaces/{ns}/pods/{name}/log |
| Pod exec | /api/v1/namespaces/{ns}/pods/{name}/exec |
| Service 列表 | /api/v1/namespaces/{ns}/services |
| ConfigMap | /api/v1/namespaces/{ns}/configmaps |
| Namespace 列表 | /api/v1/namespaces |
| Node 列表 | /api/v1/nodes |
(2) 命名空间外(集群级)
| 功能 | 子路径 |
|---|---|
| 集群健康 | /api/v1/healthz |
| metrics | /metrics |
| 版本信息 | /version |
(3) API 组(/apis/<group><version>)
| 功能 | 子路径 |
|---|---|
| Deployment | /apis/apps/v1/namespaces/{ns}/deployments |
| Job | /apis/batch/v1/namespaces/{ns}/jobs |
| CustomResource | /apis/<group>/<version>/namespaces/{ns}/<plural> |
(4) 子资源(功能级)
| 功能 | 子路径 |
|---|---|
| Pod exec | /api/v1/namespaces/{ns}/pods/{name}/exec |
| Pod logs | /api/v1/namespaces/{ns}/pods/{name}/log |
| Pod port-forward | /api/v1/namespaces/{ns}/pods/{name}/portforward |
| Status | /api/v1/namespaces/{ns}/pods/{name}/status |
(5) 节点代理
| 功能 | 子路径 |
|---|---|
| 节点 Pod列表 | /api/v1/proxy/nodes/{node}/pods |
| 节点 stats | /api/v1/proxy/nodes/{node}/stats |
| 节点 exec | /api/v1/proxy/nodes/{node}/exec |
2.3 API Server请求的访问控制流程
当API Server收到一个请求时(以kubectl为例,其他客户端也一样),将执行如下处理流程:
kubectl -> HTTPS -> API Server -> 认证 -> 授权 -> 准入 -> etcd -> 返回结果
在这个调用链中,HTTPS属于HTTP协议本身的认证,etcd属于访问控制后的业务逻辑单元,不算是K8s的访问控制。
K8s的访问控制为认证(Authentication)、授权(Authorization)和准入(Admission Control)这三个阶段。
注意,K8s的认证、授权、准入虽然三个字母都是A开头,但和计算机网络安全3A还是不同的(3A概念:认证Authentication、授权Authentication、审计Audit),不要搞混。
2.4 认证(Authentication)
在TLS连接建立后,会进行认证处理,如果请求认证失败,会拒绝该请求并返回401错误码;如果认证成功,将进行到鉴权的部分。
Kubernetes支持的客户端认证方式有很多,例如:x509客户端证书、Bearer Token、基于用户名密码的认证、OpenID认证等。其中x509客户端证书和Bear Token我们本章会用到。
2.5 授权(Authorization)
认证通过后仅代表客户端被API Server信任,能访问到API Server,但客户端是否拥有操作资源对象的权限,还需要进行授权操作。
Kubernetes支持多种授权模式,如ABAC模式,RBAC模式和Webhook模式等。
这几种模式中最常见的是RBAC,它也是K8s默认使用的授权模式,本章后面会详细介绍。
在创建集群时,可以直接为kube-apiserver传递参数(如:–authorization-mode=RBAC)配置授权模式。
2.6 准入控制(Admission Control)
发往API Server的请求,在通过认证和授权后,将会准备创建资源对象并写入etdc进行持久化存储。
在进行资源对象创建前,Kubernetes提供了一种Webhook机制,可以让资源对象被持久化前任意修改资源对象并进行自定义的校验,这就是准入控制。
准入控制有多种控制策略,不同的策略代表着对请求的不同处理,即使前面的认证和授权都通过了,但是准入策略配置了拒绝该请求也是会被立马拒绝。以下是最常用的三种策略:
- Always:允许所有的请求
- AlwaysPullmages:在启动容器之前总是尝试重新下载镜像
- AlwaysDeny:禁止所有请求
准入通过准入控制器(Admission Controller)起作用,准入控制器在API请求到达API服务器之前拦截它们,并根据一系列的策略和规则来决定是否允许这些请求通过,常用于验证配置的正确性、修改 API 对象、记录日志等。
Kubernetes提供了一些内置的Admission Controller,如:
- NamespaceLifecycle:确保命名空间的存在性。
- LimitRanger:确保请求不会超过设置的资源限制。
- ResourceQuota:确保请求不会超过设置的资源配额。
- DefaultStorageClass:为持久卷设置默认的存储类。
- ValidatingAdmissionWebhook:允许通过Webhook的方式自定义验证资源对象是否符合规则。
- MutatingAdmissionWebhook:允许通过Webhook的方式自定义修改资源对象并验证是否符合规则。
3 RBAC授权模式
在Kubernetes中,RBAC(Role-Based Access Control,基于角色的访问控制)是一种权限管理机制,用于控制用户、系统进程或系统组件对Kubernetes资源的访问权限。
RBAC是一种角色-绑定-权限的体系,在该体系下可以创建不同的角色,每个角色赋予一组特定的资源操作权限,将一个用户与角色绑定,该用户就具有了操作资源的权限。这个过程可以用下面的一幅图来概况。
这幅图中,Subjects是用户,Role和ClusterRole是角色,RoleBingding和ClusterRoleBinding是绑定动作,Resources是要操作的资源对象,Operations是操作类型。
Resources↓
┌────────────┐
│ Pod │
Subjects↓ /│ Service │
┌───────┐ ┌────────────────────┐ ┌─────────────┐ / │ Deployment │
│ User │ │ RoleBinding │ │ Role │/ └────────────┘
│ Group │<-->│ │<-->│ │ Operations↓
│ SA │ │ ClusterRoleBinding │ │ ClusterRole │\ ┌────────────┐
└───────┘ └────────────────────┘ └─────────────┘ \ │ get │
\│ list │
│ watch │
└────────────┘
RBAC有三类比较重要的概念:
Subject:主体。可以理解为用户,实际上又分为普通用户(组)和K8s系统用户。
Role、ClusterRole:角色、集群角色。主要是定义了一组资源访问控制规则。
RoleBinding、ClusterRoleBinding:角色绑定、集群角色绑定。将主体与角色绑定,赋予用户操作权限。
在主体里面,K8s系统用户有自己特定的名字,叫做Service Account,它本身存储在K8s中,是一种资源对象,kind类型为ServiceAccount。
Role、ClusterRole、RoleBinding、ClusterRoleBinding也是K8s的资源对象,kind类型分别为:Role、ClusterRole、RoleBinding、ClusterRoleBinding。
3.1 主体Subject
Subject是RBAC体系里访问Kubernetes API的实体,有普通用户(User,human users)、用户组(Group,由多个普通用户组成)和服务账号(SA, Service Accounts)三种类型。
- User:由外部系统(如X.5089证书,静态Token、LDAP等)提供,不在K8s内存储,典型用途为管理员、开发人员、CI脚本等
- Group:多个User可以组成一个Group,常用于批量授权
- SA:由Kubernetes自身提供,可以使用kubectl creata/delete管理,常用于Pod内进程访问API
3.1.1 示例:创建及删除ServiceAccounts账户
下面将通过yaml配置文件及命令行两种方式创建两个SA账户
# 通过yaml配置文件方式创建ServiceAccounts,配置文件如下
[root@master 9-controlling-access]# cat test-sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: test-sa
namespace: default
# 系统只有一个Service Account, 集群部署时默认创建的default账户
[root@master 9-controlling-access]# kubectl get serviceaccounts
NAME SECRETS AGE
default 0 4h54m
# sa是serviceaccounts的缩写
[root@master 9-controlling-access]# kubectl get sa
NAME SECRETS AGE
default 0 4h54m
# 使用yaml创建一个sa账户
[root@master 9-controlling-access]# kubectl apply -f test-sa.yaml
serviceaccount/test-sa created
# 已创建成功
[root@master 9-controlling-access]# kubectl get sa
NAME SECRETS AGE
default 0 4h54m
test-sa 0 3s
# 使用命令行创建一个sa账户
[root@master 9-controlling-access]# kubectl create sa cli-test-sa
serviceaccount/cli-test-sa created
# cli-test-sa账户已创建
[root@master 9-controlling-access]# kubectl get sa
NAME SECRETS AGE
cli-test-sa 0 2s
default 0 4h55m
test-sa 0 34s
# 删除刚创建的两个账户
[root@master 9-controlling-access]# kubectl delete sa cli-test-sa
serviceaccount "cli-test-sa" deleted
[root@master 9-controlling-access]# kubectl delete sa test-sa
serviceaccount "test-sa" deleted
# 已删除
[root@master 9-controlling-access]# kubectl get sa
NAME SECRETS AGE
default 0 4h55m
3.2 Role和ClusterRole
Role和ClusterRole都是角色,角色是一组资源访问控制规则的集合。Role和ClusterRole的区别是,Role只在当前命名空间有效,而ClusterRole则在整个集群都有效。
3.2.1 Role和ClusterRole资源清单
一个典型的Role对象资源清单如下:
[root@master 9-controlling-access]# cat role-pod-ro.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: role-pod-ro
namespace: default
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]
该资源清单的含义是,创建一个Role对象,可以操作default命名空间下的Pod资源,只能读这些资源,无法更新、删除或打补丁。
使用kubectl apply -f role-pod-ro.yaml可以创建这个对象。
使用如下命令行也可以创建一个Role对象,该对象角色可以对default命名空间下的Service资源进行读取、删除、更新、打补丁等操作:kubectl create role svc-full -n default --verb=get,list,watch,create,update,patch,delete --resource=services
如果想操作本命名空间下的所有资源,可以使用--resources=*通配符,如果想对本命名空间下的所有资源拥有所有操作权限,可以使用--verb=*通配符。
一个典型的ClusterRole对象资源清单如下:
[root@master 9-controlling-access]# cat clusterrole-pod-deploy-full.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: clusterrole-pod-deploy-full
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch","create","update","patch","delete"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get","list","watch","create","update","patch","delete"]
该资源清单的含义是,创建一个ClusterRole对象,可以操作所有命名空间下的pods和deployments资源,可以对这些资源读取、删除、更新、打补丁等所有操作。
使用kubectl apply -f clusterrole-pod-deploy-full.yaml可以创建这个对象。
使用如下命令行也可以创建一个ClusterRole对象:kubectl create clusterrole clusterrole-pod-deploy-ro --verb=get,list,watch --resource=pods,deployments
3.2.2 示例:创建及删除Role、ClusterRole对象
下面使用yaml及命令行两种方式创建Role、ClusterRole对象。
# 查看集群中现有的Role
[root@master 9-controlling-access]# kubectl get role
No resources found in default namespace.
# 查看集群中现有的ClusterRole,由于默认创建的ClusterRole资源太多,这里使用grep过滤
[root@master 9-controlling-access]# kubectl get clusterrole | grep clusterrole-pod-deploy
[root@master 9-controlling-access]# ls
clusterrole-pod-deploy-full.yaml role-pod-ro.yaml test-sa.yaml
# Role资源清单
[root@master 9-controlling-access]# cat role-pod-ro.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: role-pod-ro
namespace: default
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]
# ClusterRole资源清单
[root@master 9-controlling-access]# cat clusterrole-pod-deploy-full.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: clusterrole-pod-deploy-full
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch","create","update","patch","delete"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get","list","watch","create","update","patch","delete"]
# 创建Role
[root@master 9-controlling-access]# kubectl apply -f role-pod-ro.yaml
role.rbac.authorization.k8s.io/role-pod-ro created
# 创建ClusterRole
[root@master 9-controlling-access]# kubectl apply -f clusterrole-pod-deploy-full.yaml
clusterrole.rbac.authorization.k8s.io/clusterrole-pod-deploy-full created
# 查看Role
[root@master 9-controlling-access]# kubectl get role
NAME CREATED AT
role-pod-ro 2025-08-20T04:53:41Z
# 查看ClusterRole
[root@master 9-controlling-access]# kubectl get clusterrole | grep clusterrole-pod-deploy
clusterrole-pod-deploy-full 2025-08-20T04:53:46Z
# 命令行创建一个名称为svc-full的Role对象
[root@master 9-controlling-access]# kubectl create role role-svc-full -n default --verb=get,list,watch,create,update,patch,delete --resource=services
role.rbac.authorization.k8s.io/svc-full created
# 命令行创建一个名称为clusterrole-pod-deploy-ro的ClusterRole对象
[root@master 9-controlling-access]# kubectl create clusterrole clusterrole-pod-deploy-ro --verb=get,list,watch --resource=pods,deployments
clusterrole.rbac.authorization.k8s.io/clusterrole-pod-deploy-ro created
# 查看创建的两个Role和两个ClusterRole
[root@master 9-controlling-access]# kubectl get role
NAME CREATED AT
role-pod-ro 2025-08-20T04:53:41Z
role-svc-full 2025-08-20T04:54:41Z
[root@master 9-controlling-access]# kubectl get clusterrole | grep clusterrole-pod-deploy
clusterrole-pod-deploy-full 2025-08-20T04:53:46Z
clusterrole-pod-deploy-ro 2025-08-20T04:54:57Z
# 查看资源详情,可以看到规则
[root@master 9-controlling-access]# kubectl describe role role-pod-ro
Name: role-pod-ro
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get list watch]
[root@master 9-controlling-access]# kubectl describe role role-svc-full
Name: role-svc-full
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
services [] [] [get list watch create update patch delete]
[root@master 9-controlling-access]# kubectl describe clusterrole clusterrole-pod-deploy-full
Name: clusterrole-pod-deploy-full
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get list watch create update patch delete]
deployments.apps [] [] [get list watch create update patch delete]
[root@master 9-controlling-access]# kubectl describe clusterrole clusterrole-pod-deploy-ro
Name: clusterrole-pod-deploy-ro
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get list watch]
deployments.apps [] [] [get list watch]
Role和ClusterRole的删除操作如下:
注意我们只删除命令行创建的Role和ClusterRole,通过yaml创建的对象先不删除,下一节角色和主体绑定时会用到。
[root@master 9-controlling-access]# kubectl delete role svc-full
role.rbac.authorization.k8s.io "svc-full" deleted
[root@master 9-controlling-access]# kubectl get clusterrole| grep deploy
clusterrole-pod-deploy-full 2025-08-20T04:53:46Z
clusterrole-pod-deploy-ro 2025-08-20T04:54:57Z
system:controller:deployment-controller 2025-08-19T23:05:58Z
[root@master 9-controlling-access]# kubectl delete clusterrole clusterrole-pod-deploy-ro
clusterrole.rbac.authorization.k8s.io "clusterrole-pod-deploy-ro" deleted
3.3 RoleBinding和ClusterRoleBinding
RoleBinding和ClusterRoleBinding用于将角色和主体绑定,其中RoleBinding的作用范围为指定命名空间,ClusterRoleBinding的作用范围为整个集群。
3.3.1 RoleBinding和ClusterRoleBinding资源清单
一个典型的RoleBinding对象资源清单如下:
[root@master 9-controlling-access]# cat rolebinding-alice.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: alice-read
namespace: default
subjects:
- kind: User
name: Alice
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: role-pod-ro
apiGroup: rbac.authorization.k8s.io
该资源清单含义为,创建一个绑定关系,该绑定关系名为alice-read,主体为普通用户(User) Alice,绑定的角色为role-pod-ro,绑定之后,Alice在default命名空间就拥有role-pod-ro规则描述的操作权限。如果我们想让Alice同时在default和kube-system命名空间拥有权限,就需要用到ClusterRoleBinding,可以跨命名空间绑定角色。
可以使用kube-ctl apply -f rolebinding-alice.yaml创建绑定关系。RoleBinding也可以使用命令行创建,如:kubectl create rolebinding bob-readwrite -n default --role=role-pod-rw --user=Bob
一个典型的ClusterRoleBinding对象资源清单如下:
[root@master 9-controlling-access]# cat clusterrolebinding-test-sa.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-sa-cluster-full
subjects:
- kind: ServiceAccount
name: test-sa
namespace: default
roleRef:
kind: ClusterRole
name: clusterrole-pod-deploy-full
apiGroup: rbac.authorization.k8s.io
该资源清单含义为:创建一个绑定关系,该绑定关系名为test-sa-cluster-full,主体为Service Account,test-sa,绑定的角色为clusterrole-pod-deploy-full,绑定之后,test-sa拥有角色clusterrole-pod-deploy-full描述的操作权限。
可以使用kube-ctl apply -f clusterrolebinding-ci-bot.yaml创建绑定关系。ClusterRoleBinding也可以使用命令行创建,如:kubectl create clusterrolebinding test1-sa-cluster-read --clusterrole=clusterrole-pod-deploy-read --serviceaccount=default:test1-sa
3.3.2 示例:创建及删除RoleBinding和ClusterRoleBinding对象
下面示例为主体和角色的绑定过程。
注意:在执行绑定前,需要保证主体及角色都已经存在,如果不存在,则会报错,因为RBAC绑定是即时校验,主体或角色不存在立即404。
# 创建一个Service Account账号
[root@master 9-controlling-access]# kubectl apply -f test-sa.yaml
serviceaccount/test-sa created
[root@master 9-controlling-access]# kubectl get sa
NAME SECRETS AGE
default 0 6h41m
test-sa 0 3s
# role-pod-ro为上一节创建的Role
[root@master 9-controlling-access]# kubectl get role
NAME CREATED AT
role-pod-ro 2025-08-20T04:53:41Z
# clusterrole-pod-deploy-full为上一节创建的ClusterRole
[root@master 9-controlling-access]# kubectl get clusterrole | grep clusterrole-pod-deploy
clusterrole-pod-deploy-full 2025-08-20T04:53:46Z
[root@master 9-controlling-access]# ls
clusterrolebinding-test-sa.yaml clusterrole-pod-deploy-full.yaml rolebinding-alice.yaml role-pod-ro.yaml test-sa.yaml
# RoleBinding资源清单文件
[root@master 9-controlling-access]# cat rolebinding-alice.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: alice-read
namespace: default
subjects:
- kind: User
name: Alice
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: role-pod-ro
apiGroup: rbac.authorization.k8s.io
# ClusterRoleBinding资源清单文件
[root@master 9-controlling-access]# cat clusterrolebinding-test-sa.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-sa-cluster-full
subjects:
- kind: ServiceAccount
name: test-sa
namespace: default
roleRef:
kind: ClusterRole
name: clusterrole-pod-deploy-full
apiGroup: rbac.authorization.k8s.io
# 创建普通用户Alice和Role的绑定关系
[root@master 9-controlling-access]# kubectl apply -f rolebinding-alice.yaml
rolebinding.rbac.authorization.k8s.io/alice-read created
[root@master 9-controlling-access]# kubectl get rolebinding
NAME ROLE AGE
alice-read Role/role-pod-ro 9s
# 查看绑定关系
[root@master 9-controlling-access]# kubectl describe rolebinding alice-read
Name: alice-read
Labels: <none>
Annotations: <none>
Role:
Kind: Role
Name: role-pod-ro
Subjects:
Kind Name Namespace
---- ---- ---------
User Alice
# 创建SA test-sa账户和ClusterRole的绑定关系
[root@master 9-controlling-access]# kubectl apply -f clusterrolebinding-test-sa.yaml
clusterrolebinding.rbac.authorization.k8s.io/test-sa-cluster-full created
[root@master 9-controlling-access]# kubectl get clusterrolebinding | grep test-sa-cluster-full
test-sa-cluster-full ClusterRole/clusterrole-pod-deploy-full 31s
# 查看绑定关系
[root@master 9-controlling-access]# kubectl describe clusterrolebinding test-sa-cluster-full
Name: test-sa-cluster-full
Labels: <none>
Annotations: <none>
Role:
Kind: ClusterRole
Name: clusterrole-pod-deploy-full
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount test-sa default
RoleBinding和ClusterRoleBinding对象删除:
# 删除RoleBinding资源对象
[root@master 9-controlling-access]# kubectl delete rolebinding alice-read
rolebinding.rbac.authorization.k8s.io "alice-read" deleted
# 删除ClusterRoleBinding资源对象
[root@master 9-controlling-access]# kubectl delete clusterrolebinding test-sa-cluster-full
clusterrolebinding.rbac.authorization.k8s.io "test-sa-cluster-full" deleted
3.4 RBAC角色规则之常见资源(resources)
创建一个RBAC Role/ClusterRole,需要填写如下字段:
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]
这个resources就是K8s资源,常见值有下面几种:
(1) 原生资源
| 资源 | 缩写 | 示例 |
|---|---|---|
| pods | po | --resource=pods |
| services | svc | --resource=services |
| configmaps | cm | --resource=configmaps |
| secrets | --resource=secrets |
|
| deployments | deploy | --resource=deployments |
| statefulsets | sts | --resource=statefulsets |
| daemonsets | ds | --resource=daemonsets |
| replicasets | rs | --resource=replicasets |
| jobs | --resource=jobs |
|
| cronjobs | cj | --resource=cronjobs |
| endpoints | ep | --resource=endpoints |
| namespaces | ns | --resource=namespaces |
| nodes | no | --resource=nodes |
| endpoints | ep | --resource=endpoints |
| events | ev | --resource=events |
| limitranges | lr | --resource=limitranges |
| resourcequotas | quota | --resource=resourcequotas |
| networkpolicies | netpol | --resource=networkpolicies |
| poddisruptionbudgets | pdb | --resource=poddisruptionbudgets |
(2) 子资源
| 子资源 | 示例 |
|---|---|
| pods/log | --resource=pods/log |
| pods/status | --resource=pods/status |
| services/proxy | --resource=services/proxy |
| deployments/scale | --resource=deployments/scale |
| pods/exec | --resource=pods/exec |
(3) 全资源(以通配符*表示)--resource=*
3.5 RBAC角色规则之动词(verbs)
创建一个RBAC Role/ClusterRole,需要填写如下字段:
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]
这个verbs就是对资源的操作方式,常见值有下面几种:
(1) 常见动词
| 动词 | 作用 |
|---|---|
| get | 读取单个资源 |
| list | 读取集合(多数资源) |
| watch | 监听变化(长连接) |
| create | 新建资源 |
| update | 整体替换资源 |
| patch | 局部修改资源 |
| delete | 删除单个资源 |
| deletecollection | 删除集合(多数资源) |
(2) 特殊动词
| 动词 | 作用 |
|---|---|
| proxy | 代理到 Pod/Service/Node |
| use | 使用子资源(如 pods/exec、pods/portforward) |
(3) 所有动词
| 动词 | 作用 |
|---|---|
| *(通配符) | 所有动词(慎用) |
4 综合示例:普通用户账户认证和授权
我们知道,Kubernetes API可以通过多种方式访问,前面我们介绍的都是kubectl方式,这里我们介绍使用curl工具直接发送REST请求的方式。
查看集群REST服务地址:
得到地址为https://127.0.0.1:6443
[root@master 9-controlling-access]# kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://127.0.0.1:6443
name: default
contexts:
- context:
cluster: default
user: default
name: default
current-context: default
kind: Config
preferences: {}
users:
- name: default
user:
client-certificate-data: DATA+OMITTED
client-key-data: DATA+OMITTED
4.1 普通用户账户认证
(1) 直接访问K8s API Server
使用curl直接访问API Server该地址,报以下错误
[root@master 9-controlling-access]# curl https://127.0.0.1:6443/api/v1/namespaces
curl: (60) SSL certificate problem: self signed certificate in certificate chain
More details here: https://curl.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
这是因为HTTPS环节出了问题,访问HTTPS地址,需要传入一个证书,这个证书在k3s的证书目录/var/lib/rancher/k3s/server/tls/server-ca.crt
(2) 传入证书访问API Server
我们传入这个证书,访问API Server:
[root@master 9-controlling-access]# curl --cacert /var/lib/rancher/k3s/server/tls/server-ca.crt https://127.0.0.1:6443/api/v1/namespaces
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
}
HTTPS通过,服务端有返回值,这里返回401表示API Server还不认识这个客户端用户。下一步就需要认证。
(3) 创建用户证书
1. 生成私钥
生成 2048 位 RSA 私钥,后续用于签名 CSR。
[root@master 9-controlling-access]# mkdir testuser && cd testuser
[root@master testuser]# openssl genrsa -out testuser.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
..........................+++++
..........................................+++++
e is 65537 (0x010001)
[root@master testuser]# ls
testuser.key
2. 生成 CSR(证书签名请求)
用私钥生成 CSR,CN=testuser 即用户名(RBAC 绑定用)。
[root@master testuser]# openssl req -new -key testuser.key -out testuser.csr -subj "/CN=testuser"
[root@master testuser]# ls
testuser.csr testuser.key
3. 清理旧 CSR
若之前存在同名 CSR,先删除,避免冲突。
[root@master testuser]# kubectl delete csr testuser 2>/dev/null
4. 提交 CSR 到 K8s
把 CSR 以 CertificateSigningRequest 资源提交,Base64 纯文本
若想把这段yaml保存成文件,需要先替换`$(base64 -w0 testuser.csr)`为csr文件的base64编码值
[root@master testuser]# cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: testuser
spec:
request: $(base64 -w0 testuser.csr)
signerName: kubernetes.io/kube-apiserver-client
usages: ["client auth"]
EOF
certificatesigningrequest.certificates.k8s.io/testuser created
5. 手动批准证书
让 kube-controller-manager 用 client-ca 签发证书,证书写入 CSR.status.certificate。
[root@master testuser]# kubectl certificate approve testuser
certificatesigningrequest.certificates.k8s.io/testuser approved
6. 提取证书
把 Base64 证书 解码为 PEM 文件,即可用于 kubectl/curl 访问 API。
[root@master testuser]# kubectl get csr testuser -o jsonpath='{.status.certificate}' | base64 -d > testuser.crt
[root@master testuser]# ls
testuser.crt testuser.csr testuser.key
(4) 使用用户证书访问API Server
这里可以看到,认证已经通过,不再返回401错误,而是返回403错误,没有权限,需要授权
[root@master testuser]# curl --cacert /var/lib/rancher/k3s/server/tls/server-ca.crt --cert testuser.crt --key testuser.key https://127.0.0.1:6443/api/v1/namespaces
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "namespaces is forbidden: User \"testuser\" cannot list resource \"namespaces\" in API group \"\" at the cluster scope",
"reason": "Forbidden",
"details": {
"kind": "namespaces"
},
"code": 403
}
4.2 普通用户账户授权
下面将创建一个ClusterRole角色,赋予该角色访问namespaces资源的权限,并将该角色与普通账户testuser绑定。
(1) 创建一个ClusterRole角色kubectl create clusterrole testuserclusterrole --resource=namespaces --verb=get,list,watch
该命令行效果与如下yaml文件等价
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: testuserclusterrole
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get","list","watch"]
(2) 创建ClusterRoleBinding绑定关系kubectl create clusterrolebinding testuser --clusterrole=testuserclusterrole --user=testuser
该命令行效果与如下yaml文件等价
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: testuser
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: testuserclusterrole
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: testuser
(3) 查看绑定关系
[root@master testuser]# kubectl describe clusterrolebinding testuser
Name: testuser
Labels: <none>
Annotations: <none>
Role:
Kind: ClusterRole
Name: testuserclusterrole
Subjects:
Kind Name Namespace
---- ---- ---------
User testuser
(4) 访问API Server
# 授权成功,可以访问namespaces资源
[root@master testuser]# curl --cacert /var/lib/rancher/k3s/server/tls/server-ca.crt --cert testuser.crt --key testuser.key https://127.0.0.1:6443/api/v1/namespaces | grep \"name\"
"name": "default",
"name": "kube-node-lease",
"name": "kube-public",
"name": "kube-system",
# 与kubectl查询到的namespaces资源相同
[root@master testuser]# kubectl get namespaces
NAME STATUS AGE
default Active 8h
kube-node-lease Active 8h
kube-public Active 8h
kube-system Active 8h
# 由于没有对pods资源授权,这里还是返回403 Forbidden
[root@master testuser]# curl --cacert /var/lib/rancher/k3s/server/tls/server-ca.crt --cert testuser.crt --key testuser.key https://127.0.0.1:6443/api/v1/pods
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "pods is forbidden: User \"testuser\" cannot list resource \"pods\" in API group \"\" at the cluster scope",
"reason": "Forbidden",
"details": {
"kind": "pods"
},
"code": 403
}
5 综合示例:ServiceAccount账户认证和授权
5.1 ServiceAccount账户认证
(1) 创建ServiceAccount账户testsauser
[root@master 9-controlling-access]# mkdir testsauser && cd testsauser
[root@master testsauser]# kubectl create sa testsauser
serviceaccount/testsauser created
[root@master testsauser]# kubectl get sa
NAME SECRETS AGE
default 0 8h
test-sa 0 116m
testsauser 0 3s
[root@master testsauser]#
kubectl create sa testsauser为创建SA账户的命令,该命令效果与如下yaml文件等价:
apiVersion: v1
kind: ServiceAccount
metadata:
name: testsauser
namespace: default
(2) 创建ServiceAccount账户testsauser对应的token
SA访问API Server需要用到token,为了方便,写入环境变量,后续直接引用
[root@master testsauser]# TEST_SA_USER_TOKEN=$(kubectl create token testsauser -n default --duration=24h)
[root@master testsauser]# echo $TEST_SA_USER_TOKEN
eyJhbGciOiJSUzI1NiIsImtpZCI6Im41N0FLdzVqTnpsZUU5MGYyR0ZBc2tlUlV0dkYzdVhFQTBuTzJ1VWg4cFEifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiLCJrM3MiXSwiZXhwIjoxNzU1NzYyMzM5LCJpYXQiOjE3NTU2NzU5MzksImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0Iiwic2VydmljZWFjY291bnQiOnsibmFtZSI6InRlc3RzYXVzZXIiLCJ1aWQiOiI4MTg2MzhlYy1mZTM1LTQzYjMtODRkZC0wNjE1NWMwZTAzOWUifX0sIm5iZiI6MTc1NTY3NTkzOSwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6dGVzdHNhdXNlciJ9.p366DuuOLgYhiYfgeC4Wv-x2esP0DzfdvX9Ipnlwq7BPq7tQi8wo92WT3RM4mCgXqx3dIfTYc1KebT2cLmMx1EMgF3R2G-RYlcPfsfETzo_0333hfM2WrqwszrTQwdR3owOx6jejt_StrMfHGDpjCVkXH48DdHyfRiNKtj0nZX-fQ--CQ0Ez8yb3y8BXNf7-CKPm_C_5dFa89ZMF6zlIu7DvPp1UIBNGhIwitau6e22SEb5jXw7hHX_u26hZTjkdu3_0XNafImrmffFlovFiOYIss1OxGFFM0XYFYQG92OoSH9gWof5ldoB6mGehtBDE_SGS1mNf3nW7kCkm5fN0nQ
kubectl create token testsauser -n default --duration=24h为创建testsauser这个SA账户token的命令,该命令效果与如下yaml文件相似:
apiVersion: v1
kind: Secret
metadata:
name: testsa-token
namespace: default
annotations:
kubernetes.io/service-account.name: testsauser
type: kubernetes.io/service-account-token
但是命令行创建的token立即返回,不会创建Secret对象,也不会持久化保存,–duration参数决定了其有效期。Secret对象创建的Token会持久化,可以多次使用,这个我们在后面的示例会有演示。
(3) 不使用token访问API Server
返回401,未认证通过。
[root@master testsauser]# curl --cacert /var/lib/rancher/k3s/server/tls/server-ca.crt https://127.0.0.1:6443/api/v1/pods
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
}
(4) 使用token访问API Server
返回403 Forbidden,认证通过,但没有访问资源的权限,需要授权。
[root@master testsauser]# curl --cacert /var/lib/rancher/k3s/server/tls/server-ca.crt -H "Authorization: Bearer $TEST_SA_USER_TOKEN" https://127.0.0.1:6443/api/v1/pods
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "pods is forbidden: User \"system:serviceaccount:default:testsauser\" cannot list resource \"pods\" in API group \"\" at the cluster scope",
"reason": "Forbidden",
"details": {
"kind": "pods"
},
"code": 403
}
5.2 ServiceAccount账户授权
创建一个ClusterRole,可以访问Pod资源,再创建一个ClusterRoleBinding,将ClusterRole与ServiceAccount testsauser绑定。
(1) 创建ClusterRole对象
[root@master testsauser]# kubectl create clusterrole testsauserclusterrole --resource=pods --verb=get,list,watch
clusterrole.rbac.authorization.k8s.io/testsauserclusterrole created
该命令等价于如下yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: testsauserclusterrole
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]
(2) 创建ClusterRoleBinding对象
将testsauser与testsauserclusterrole绑定。
[root@master testsauser]# kubectl create clusterrolebinding testsauser --clusterrole=testsauserclusterrole --serviceaccount=default:testsauser
clusterrolebinding.rbac.authorization.k8s.io/testsauser created
该命令等价于如下yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: testsauser
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: testsauserclusterrole
subjects:
- kind: ServiceAccount
name: testsauser
namespace: default
(3) 查看绑定关系
[root@master testsauser]# kubectl describe clusterrolebinding testsauser
Name: testsauser
Labels: <none>
Annotations: <none>
Role:
Kind: ClusterRole
Name: testsauserclusterrole
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount testsauser default
(4) 访问API Server
可以查看到集群中所有命名空间下的所有Pod。由于没有为namespaces资源授权,所以这里无法查看namespaces资源,返回403错误。
[root@master testsauser]# curl --cacert /var/lib/rancher/k3s/server/tls/server-ca.crt -H "Authorization: Bearer $TEST_SA_USER_TOKEN" https://127.0.0.1:6443/api/v1/pods | grep \"name\"
"name": "coredns-6799fbcd5-hnz2f",
"name": "coredns-6799fbcd5",
"name": "config-volume",
"name": "coredns",
"name": "custom-config-volume",
(。。。查询到的是集群所有的Pod,较多,部分内容略。。。)
"name": "kube-api-access-hjdhk",
"name": "local-path-provisioner",
[root@master testsauser]# curl --cacert /var/lib/rancher/k3s/server/tls/server-ca.crt -H "Authorization: Bearer $TEST_SA_USER_TOKEN" https://127.0.0.1:6443/api/v1/namespaces
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "namespaces is forbidden: User \"system:serviceaccount:default:testsauser\" cannot list resource \"namespaces\" in API group \"\" at the cluster scope",
"reason": "Forbidden",
"details": {
"kind": "namespaces"
},
"code": 403
}
6 综合示例:使用Secret对象持久化保存Token
我们知道kubectl create token testsauser -n default --duration=24h可以产生token,但并不持久化,duration时间过后就失效了,如果想持久化token,可以使用Secret对象,下面我们用一个例子演示一下。
(1) 创建testaaa SA对象和Secret对象的资源清单
[root@master 9-controlling-access]# mkdir secret-token && cd secret-token
[root@master secret-token]# cat testaaa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: testbbb
namespace: default
---
apiVersion: v1
kind: Secret
metadata:
name: testbbb-token
namespace: default
annotations:
kubernetes.io/service-account.name: testbbb
type: kubernetes.io/service-account-token
(2) 创建这个两个对象
注:在Kubernetes v1.24版本前,SA创建后Secret将会自动创建,但这个功能自1.24及之后的版本就没有了,需要手动创建Secret。
[root@master secret-token]# kubectl apply -f testbbb.yaml
serviceaccount/testbbb created
secret/testbbb-token created
(3) 查看创建的SA
[root@master secret-token]# kubectl get sa
NAME SECRETS AGE
default 0 8h
test-sa 0 131m
testbbb 0 5s
testsauser 0 14m
(4) 查看创建的Secret
[root@master secret-token]# kubectl get secret
NAME TYPE DATA AGE
testbbb-token kubernetes.io/service-account-token 3 70s
(5) 查看Secret对象详情
[root@master secret-token]# kubectl describe secret bbb-token
Name: testbbb-token
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name: testbbb
kubernetes.io/service-account.uid: ba8f8137-1551-4a10-a3ab-affc517bbb99
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 570 bytes
namespace: 7 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6Im41N0FLdzVqTnpsZUU5MGYyR0ZBc2tlUlV0dkYzdVhFQTBuTzJ1VWg4cFEifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImJiYi10b2tlbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJ0ZXN0YWFhIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiYmE4ZjgxMzctMTU1MS00YTEwLWEzYWItYWZmYzUxN2JiYjk5Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6dGVzdGFhYSJ9.UbjSQa6fz89y5KSN3fCH_-qqfE3XkE2UwzZ3_H9KIVbm0mWY1ccrbstELi1MPd0Ol-b7iuCNNEUyTmKvYrKr785qNszaay8PmeyR-2aNz-y9KOFmKncYQu4kn0ezoEn0ZKJ4sHnVWgBNl951UpQIEMZxvrC_BNJ6tftrZ31mjrkm4TWJo2sdvIB0HOg3kSzGUZWcitN7mdi93wTGx3nsGntxBcS7Sy2RymlTUflgd2SQRz4pNCQO4tis6Q2omdJVLimovAWGN3i3yykKD3O6Kr0A4x6D7ilI3IfnVVaOX8qAFzfc30vWwnAzUVcEIOFGuvU-I_VYc_CcGruEVqysgA
(6) 提取token
[root@master secret-token]# kubectl -n default get secret testbbb-token -o jsonpath='{.data.token}' | base64 -d
eyJhbGciOiJSUzI1NiIsImtpZCI6Im41N0FLdzVqTnpsZUU5MGYyR0ZBc2tlUlV0dkYzdVhFQTBuTzJ1VWg4cFEifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImJiYi10b2tlbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJ0ZXN0YWFhIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiYmE4ZjgxMzctMTU1MS00YTEwLWEzYWItYWZmYzUxN2JiYjk5Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6dGVzdGFhYSJ9.UbjSQa6fz89y5KSN3fCH_-qqfE3XkE2UwzZ3_H9KIVbm0mWY1ccrbstELi1MPd0Ol-b7iuCNNEUyTmKvYrKr785qNszaay8PmeyR-2aNz-y9KOFmKncYQu4kn0ezoEn0ZKJ4sHnVWgBNl951UpQIEMZxvrC_BNJ6tftrZ31mjrkm4TWJo2sdvIB0HOg3kSzGUZWcitN7mdi93wTGx3nsGntxBcS7Sy2RymlTUflgd2SQRz4pNCQO4tis6Q2omdJVLimovAWGN3i3yykKD3O6Kr0A4x6D7ilI3IfnVVaOX8qAFzfc30vWwnAzUVcEIOFGuvU-I_VYc_CcGruEVqysgA
更多推荐

所有评论(0)