news 2026/6/30 3:45:14

从零搭建 K8s 权限体系:开发组只读 + 运维组管理(中集)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零搭建 K8s 权限体系:开发组只读 + 运维组管理(中集)

上集拆解了 RBAC 四个核心概念(User / ServiceAccount / Role / Binding),搞清楚了 Subject → Binding → Role 这条链路。这集中手把手搭建,把概念变成能跑的命令。

建议读完上集再看这篇,概念定义和证书签发流程上集有详细说明。


一、场景设定

  • 开发组dev-team)→devstaging命名空间有只读权限
  • 运维组ops-team)→ 所有命名空间管理权限
  • 日志采集 ServiceAccountprod命名空间 Pod 发现 + 节点信息采集

下面分三个案例,由浅入深:先从最简单的"单独给一个用户授权"讲起,再升级到"给组授权"的生产实战,最后讲"给程序(ServiceAccount)授权"——对应上面三个场景设定。


二、实战案例一:单独给用户授权

对应场景设定里的「新同事入职」——先从最简单的单个 User 讲起,理解 RBAC 三元组怎么串起来。

新同事 zhangsan 入职开发,需要在devstaging有只读权限。完整链路:签发证书(认证)→ 创建 Role(授权)→ RoleBinding(关联)→ 验证

1.1 签发证书——搞定"你是谁"

详细的证书签发流程参考上集「二.1.2 生产实战」,关键点:CSR 里CN=zhangsan就是用户名,RBAC 绑定时用kind: Username: zhangsan匹配。

cat>zhangsan-csr.json<<EOF { "CN": "zhangsan", "key": { "algo": "rsa", "size": 2048 }, "names": [{ "C": "CN", "ST": "BeiJing", "L": "BeiJing", "OU": "System" }] } EOF# 找 CA → 签发 → 生成 kubeconfig(参考上集二.1.2 第 1-4 步)

拿到zhangsan.kubeconfig后,用户已经能连上集群——但kubectl get pods会报 403,因为还没授权。

1.2 创建 Role + RoleBinding——搞定"能干啥"

# rbac-zhangsan.yamlcat>rbac-zhangsan.yaml <<EOF# 1. dev 命名空间的只读 RoleapiVersion:rbac.authorization.k8s.io/v1kind:Rolemetadata:name:dev-readernamespace:devrules:-apiGroups:[""]resources:["pods","services","configmaps"]verbs:["get","list","watch"]-apiGroups:["apps"]resources:["deployments","replicasets"]verbs:["get","list","watch"]---# 2. RoleBinding:把 User zhangsan 绑到 dev-reader角色apiVersion:rbac.authorization.k8s.io/v1kind:RoleBindingmetadata:name:zhangsan-dev-readernamespace:devsubjects:-kind:User# ← 注意:绑的是 User,不是 Groupname:zhangsan# 匹配证书 CN 字段apiGroup:rbac.authorization.k8s.ioroleRef:kind:Rolename:dev-readerapiGroup:rbac.authorization.k8s.io---# 3. staging 命名空间也要创建同名 Role(Role 是命名空间级资源,跨 ns 引用不到)apiVersion:rbac.authorization.k8s.io/v1kind:Rolemetadata:name:dev-readernamespace:stagingrules:-apiGroups:[""]resources:["pods","services","configmaps"]verbs:["get","list","watch"]-apiGroups:["apps"]resources:["deployments","replicasets"]verbs:["get","list","watch"]---# 4. staging 的 RoleBindingapiVersion:rbac.authorization.k8s.io/v1kind:RoleBindingmetadata:name:zhangsan-staging-readernamespace:stagingsubjects:-kind:Username:zhangsanapiGroup:rbac.authorization.k8s.ioroleRef:kind:Rolename:dev-readerapiGroup:rbac.authorization.k8s.io EOF
kubectl apply-frbac-zhangsan.yaml

1.3 验证

kubectl auth can-i get pods-ndev--aszhangsan# → yeskubectl auth can-i delete pods-ndev--aszhangsan# → no——Role 里没有 deletekubectl auth can-i get pods-nprod--aszhangsan# → no——prod 没授权

💡 这种方式的缺点:每来一个新同事,都要写一套 RoleBinding。人多了之后 YAML 里全是一堆 User 绑定,改都改不过来。解决办法——案例二。


三、实战案例二:给组授权——开发组只读 + 运维组管理

3.1 核心原理:证书的O字段 = RBAC 的 Group name

生产环境通过 Group 管权限,不针对单个 User。组名从哪里来?——证书签发时的O字段。

# zhangsan(开发){"CN":"zhangsan","O":"dev-team"# ← 这个 O 值就是 RBAC 的 Group name}# lisi(运维){"CN":"lisi","O":"ops-team"}

签发证书后,kubeconfig 里的客户端证书自动带上O=dev-team,无需额外配置。

角色CSR 里O字段权限范围
开发dev-teamdev、staging 只读
运维ops-team全集群管理

3.2 新人入职:签发证书(以 lisi 为例)

原理清楚了,下面实际操作一把。假设运维组新来一个同事 lisi,给他签发证书——O=ops-team,签完 kubeconfig 里自动带上组信息。

#编写证书签名请求(CSR)cat>lisi-csr.json<<EOF { "CN": "lisi", "hosts": [], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "ST": "BeiJing", "L": "BeiJing", "O": "ops-team", "OU": "System" } ] } EOF#用集群 CA 签发客户端证书cfssl gencert\-ca=/etc/kubernetes/ssl/ca.pem\-ca-key=/etc/kubernetes/ssl/ca-key.pem\-config=ca-config.json\-profile=kubernetes lisi-csr.json|cfssljson-barelisi#生成 kubeconfig 文件# 4a. 写入集群信息kubectl config set-cluster kubernetes\--certificate-authority=/etc/kubernetes/ssl/ca.pem\--embed-certs=true\--server=https://192.168.91.254:6443\--kubeconfig=lisi.kubeconfig# 4b. 写入用户凭证kubectl config set-credentials lisi\--client-certificate=lisi.pem\--client-key=lisi-key.pem\--embed-certs=true\--kubeconfig=lisi.kubeconfig# 4c. 创建上下文(关联用户 + 集群)kubectl config set-context lisi@kubernetes\--cluster=kubernetes\--user=lisi\--kubeconfig=lisi.kubeconfig# 4d. 设为默认上下文kubectl config use-context lisi@kubernetes\--kubeconfig=lisi.kubeconfig

注意:这时 RBAC 一个字符都不用动。RoleBinding/ClusterRoleBinding 绑的是 Groupops-team,不是 lisi 这个人。lisi 证书签完,自动继承运维组全部权限。

3.3 开发组:dev 和 staging 只读

# rbac-dev-group.yamlcat>rbac-dev-group.yaml <<EOF# 1. 创建只读 ClusterRole(可被多个 命名空间 复用)apiVersion:rbac.authorization.k8s.io/v1kind:ClusterRolemetadata:name:read-onlyrules:-apiGroups:[""]resources:["pods","services","configmaps","secrets","endpoints"]verbs:["get","list","watch"]-apiGroups:["apps"]resources:["deployments","replicasets","statefulsets","daemonsets"]verbs:["get","list","watch"]---# 2和3 RoleBinding:把 dev-team 组绑定到 dev 命名空间和stagingapiVersion:rbac.authorization.k8s.io/v1kind:RoleBindingmetadata:name:dev-team-readonlynamespace:devsubjects:-kind:Groupname:dev-team# ← 组名,匹配证书 O=dev-teamapiGroup:rbac.authorization.k8s.ioroleRef:kind:ClusterRolename:read-onlyapiGroup:rbac.authorization.k8s.io---# 3. staging 也绑一次apiVersion:rbac.authorization.k8s.io/v1kind:RoleBindingmetadata:name:dev-team-readonlynamespace:stagingsubjects:-kind:Groupname:dev-teamapiGroup:rbac.authorization.k8s.ioroleRef:kind:ClusterRolename:read-onlyapiGroup:rbac.authorization.k8s.io EOF
kubectl apply-frbac-dev-group.yaml

3.4 运维组:全集群管理

# rbac-ops-group.yamlcat>rbac-ops-group.yaml <<EOF# 利用 K8s 内置的 cluster-admin,直接 ClusterRoleBindingapiVersion:rbac.authorization.k8s.io/v1kind:ClusterRoleBindingmetadata:name:ops-team-adminsubjects:-kind:Groupname:ops-team# ← 证书里 O=ops-team 的人自动获得apiGroup:rbac.authorization.k8s.ioroleRef:kind:ClusterRolename:cluster-admin# K8s 内置超级管理员apiGroup:rbac.authorization.k8s.io EOF
kubectl apply-frbac-ops-group.yaml

如果运维只需特定权限(如管理 Node、PV,但不能删 Namespace),可自定义 ClusterRole 替代cluster-admin,按最小权限原则来。

3.5 验证

# 开发 zhangsan:dev + staging 可读,prod 进不去kubectl auth can-i get pods-ndev--aszhangsan# → yeskubectl auth can-i get pods-nstaging--aszhangsan# → yeskubectl auth can-i get pods-nprod--aszhangsan# → nokubectl auth can-i delete pods-ndev--aszhangsan# → no# 运维 lisi——注意要用 KUBECONFIG 或 --as-group,不能只用 --as# ⚠️ --as lisi 只模拟 User "lisi",不会带上证书里的 Group "ops-team"# 运维的权限是通过 Group 绑定的,直接用 lisi 的 kubeconfig 最准确:KUBECONFIG=lisi.kubeconfig kubectl auth can-i get pods-nprod# → yesKUBECONFIG=lisi.kubeconfig kubectl auth can-i delete pods-ndev# → yesKUBECONFIG=lisi.kubeconfig kubectl auth can-i get nodes# → yes# 或者用 --as + --as-group 显式指定组kubectl auth can-i get pods-nprod--aslisi --as-group ops-team# → yes

🔑 关键区别:案例一绑的是kind: User--as zhangsan就够了。案例二绑的是kind: Group--as lisi只模拟 User 身份、不带上 Group,必须加--as-group ops-team或直接用 kubeconfig 文件验证。

3.6 核心价值:人动权限不动

王五入职开发组: ① 写 CSR,O=dev-team ② cfssl 签发 → 生成 kubeconfig ③ 结束。RBAC 一个字符都不用改 → 因为 RoleBinding 绑的是 Group dev-team,不是 User 王五 王五转岗到运维: ① 重新签发证书,O 改成 ops-team ② 权限自动从只读变管理 ③ 还是不用改 RBAC

生产铁律:永远通过 Group 分配权限。证书里的O字段就是天然的 RBAC Group。


四、实战案例三:给程序授权(ServiceAccount)

前面两个案例讲的都是"人"的身份(User + Group),日常kubectl操作靠它们。但集群里跑的日志/监控 Agent(Filebeat、Prometheus)是程序自动跑的——没有真人敲命令,用的是ServiceAccount

4.1 创建 SA + 授权

以 Filebeat 为例:它的 DaemonSet 跑在每个节点上,需要发现新 Pod → 拿到 Pod 元数据(标签、ns)→ 给日志打标才能送到 Elasticsearch。这些操作全是调 K8s API,default SA 零权限,直接 403。按最小权限原则,只给刚好够的:

# log-collector-sa.yaml —— 一个文件三段,SA → Role → RoleBinding 一步到位cat>log-collector-sa.yaml << EOF# ===== 第 1 段:创建 ServiceAccount =====apiVersion:v1kind:ServiceAccountmetadata:name:log-collectornamespace:prod# SA 是命名空间级,日志 Agent 部署在哪个 ns 就建哪个 ns---# ===== 第 2 段:定义权限 =====apiVersion:rbac.authorization.k8s.io/v1kind:Rolemetadata:name:log-readernamespace:prodrules:-apiGroups:[""]# 核心 API 组(Pod/Node 在这)resources:["pods"]verbs:["get","list","watch"]# get/list:拉取当前 Pod 列表,拿到 Pod 名、命名空间、标签等元数据# watch:监听 Pod 增删,新 Pod 一创建 Filebeat 马上开始采日志-apiGroups:[""]resources:["nodes"]verbs:["get","list"]# 拿到节点名、IP 等信息,日志记录里能标注"这条日志来自哪个节点"---# ===== 第 3 段:绑定 SA 到 Role =====apiVersion:rbac.authorization.k8s.io/v1kind:RoleBindingmetadata:name:log-collectornamespace:prodsubjects:-kind:ServiceAccountname:log-collectornamespace:prodroleRef:kind:Rolename:log-readerapiGroup:rbac.authorization.k8s.io EOF
kubectl apply-flog-collector-sa.yaml

到这里 SA 和权限就位了——log-collector这个ServiceAccount能看 Pod 和 Node 信息,但不能改任何东西。但 Pod 怎么用这个 SA 呢?往下看。

4.2 Pod 如何使用 SA

DaemonSet 里serviceAccountName一行搞定,K8s 自动把凭证挂进每个节点的日志采集 Pod

# filebeat-daemonset.yamlcat>filebeat-daemonset.yaml << EOFapiVersion:apps/v1kind:DaemonSetmetadata:name:filebeatnamespace:prodspec:selector:matchLabels:app:filebeattemplate:metadata:labels:app:filebeatspec:serviceAccountName:log-collector# ← 一行指定身份,不写默认用 default(零权限)containers:-name:filebeatimage:docker.elastic.co/beats/filebeat:8.15.0 EOF kubectl apply-f filebeat-daemonset.yaml

K8s 调度这个 Pod 时自动做三件事——把三个关键文件挂进容器:

文件路径用途
Token/var/run/secrets/.../token认证凭证,Filebeat 拿它调 API 证明"我是 log-collector"
CA 证书/var/run/secrets/.../ca.crt验证 API Server 身份,防中间人
命名空间/var/run/secrets/.../namespace知道自己在哪个 ns

Filebeat 进程启动后读这三个文件,就能调 K8s API 拉 Pod 列表、监听 Pod 变化。用 default SA 的话——刚启动就 403,日志采集直接废掉。

那什么时候需要自定义 SA、什么时候用 default 就行?

Pod 类型用哪个 SA原因
纯业务 Pod(Nginx、MySQL、Redis、Java 服务)default(甚至关掉 Token 挂载)不调 K8s API,不需要任何权限
CI/CD 流水线(GitLab Runner、Jenkins Agent)自定义 SA(如cicd-deployer要 update Deployment、create ConfigMap
日志/监控采集(Filebeat、Prometheus)自定义 SA需要 get/watch pods、nodes 做服务发现
Operator / Controller(cert-manager、etcd-operator)自定义 SA需要 CRUD 自定义资源
Ingress Controller(nginx-ingress)自定义 SA需要 get/watch services、endpoints、secrets
外部密钥同步(External Secrets Operator)自定义 SA需要 create/update secrets
备份工具(Velero)自定义 SA需要 get/list 全集群资源
自己写的调 API 的应用自定义 SA按需给,如查 Pod 列表、动态创建 Job

一句话:Pod 里程序只要curl https://kubernetes.default.svc调 K8s API,就不能用 default(零权限),必须自定义 SA + 绑 Role。反过来,跑纯业务的 Pod 用 default 完全够,更建议设automountServiceAccountToken: false关掉 Token 挂载——安全,又少一个攻击面。

4.3 获取 SA 的 Token(给集群外工具用)

Pod 内程序自动有 Token,但有些场景需要在集群外用这个 SA——比如调试时从本机 curl API 拉 Pod 列表:

# 一条命令生成 Token,直接打印到终端kubectl create token log-collector-nprod--duration=720h

输出就是一长串 JWT 字符串,拿来当 Bearer Token 用。

版本说明kubectl create token需要 kubectl ≥ 1.24。如果 kubectl 是 1.23(create token还不存在),但服务器是 1.24+(不再自动生成 Secret),就手动建一个 Secret 兜底。

那什么时候需要手动拿 Token?

场景需要手动拿?原因
Pod 里用这个 SA(serviceAccountName: log-collectorK8s 自动把 Token 注入容器,程序直接读文件即可
集群外工具用这个 SA(本机脚本、调试)没有 Pod、没有自动挂载,得先create token拿到凭证

一句话:SA 是身份注册,Token 是出门证。在集群内(Pod)自动发证,在集群外(笔记本)得自己领。

4.4 验证 SA 权限——从两个角度测一遍

角度一:集群内测试(kubectl auth can-i)

SA 在 K8s 内部的完整身份是system:serviceaccount:<ns>:<sa-name>

# Filebeat 能不能看 Pod 列表?(预期 yes)kubectl auth can-i get pods-nprod\--assystem:serviceaccount:prod:log-collector# → yes# Filebeat 能不能删 Pod?(预期 no——只读 SA,不该有删除权限)kubectl auth can-i delete pods-nprod\--assystem:serviceaccount:prod:log-collector# → no# Filebeat 能不能操作 Deployment?(预期 no——日志采集碰不到 Deployment)kubectl auth can-i get deployments-nprod\--assystem:serviceaccount:prod:log-collector# → no# 列出 log-collector 的全部权限kubectl auth can-i--list-nprod\--assystem:serviceaccount:prod:log-collector# Resources Verbs# pods [get list watch]# nodes [get list]# ↑ 就两行,干净利落。没有 delete、没有 create、没有 update。# 日志 Agent 只需要"看",不需要改任何东西。

角度二:集群外测试(curl 模拟本机脚本)

从其他服务器模拟:不带 Token 和带上 Token 各调一次 API:

# ① 不带 Token → 401,API Server 不知道你是谁curl-khttps://192.168.91.254:6443/api/v1/namespaces/prod/pods# {"status": "Failure", "message": "Unauthorized", "code": 401}# ② 带上 Token → 200,log-reader Role 允许 get podsTOKEN=$(kubectl create token log-collector-nprod--duration=720h)curl-k-H"Authorization: Bearer$TOKEN"\https://192.168.91.254:6443/api/v1/namespaces/prod/pods# 返回 prod 下 Pod 列表 JSON ← 认证 + 授权都通过# ③ 有 Token 但越权 → 403,认证过了,权限不够curl-k-H"Authorization: Bearer$TOKEN"\-XDELETE\https://192.168.91.254:6443/api/v1/namespaces/prod/pods/some-pod# {"status": "Failure", "message": "Forbidden", "code": 403}

三条命令串起完整认知:没 Token → 401(不知道你是谁)、有 Token → 200(认证+授权通过)、越权操作 → 403(认证通过但权限不够)。Token 管认证,Role 管授权,各干各的。

SA identity 格式速记system:serviceaccount:<ns>:<sa-name>。所有 SA 自动属于system:serviceaccounts这个 Group,可按此做统一授权。例如给所有命名空间的 SA 批量开只读:

subjects: - kind: Group name: system:serviceaccounts apiGroup: rbac.authorization.k8s.io

五、总结

  • RBAC 三条链路缺一不可:身份(User/SA)→ 绑定(RoleBinding)→ 权限(Role),断任何一条都是 403。
  • 生产永远用 Group 授权:新人入职只改证书 O 字段,RBAC 一个字不用动;百人团队 RoleBinding 还是那几行。
  • SA 是程序的身份,不是人的替代品:人用 kubectl 走证书,程序调 API 走 SA Token,两回事。
  • 配完权限必须验证kubectl auth can-i查集群内,curl + Token查集群外,别猜。

中集小结:三个案例走完了从零搭建权限体系的完整流程。案例一理解三元组,案例二是生产真玩法——Group 授权新人入职只签发证书、RBAC 不用动,案例三讲程序身份 ServiceAccount——Pod 里的日志/监控采集器怎么安全调 K8s API。

📺下集预告:「K8s RBAC 进阶避坑指南」——最小权限原则、聚合 ClusterRole、SA Token 1.24 变化、安全审计巡检、apiGroups 排坑、6 条踩坑经验 + 落地清单。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/30 3:44:45

Web安全双雄:XSS与CSRF攻击原理与立体防御实战

1. 项目概述&#xff1a;从“小把戏”到“大麻烦”的Web安全双雄在Web应用开发与安全防护的日常工作中&#xff0c;有两个名字总是如影随形&#xff0c;它们不像SQL注入那样直接“掏空”数据库&#xff0c;也不像DDoS那样声势浩大&#xff0c;却像潜伏在阴影中的刺客&#xff0…

作者头像 李华
网站建设 2026/6/30 3:42:52

近400家美国报纸状告OpenAI和微软,AI版权纠纷成结构性产业冲突

【近400家美国报纸状告OpenAI和微软&#xff1a;偷内容不付钱】近日&#xff0c;曼哈顿联邦法院收到一份长达55页的诉状&#xff0c;代表近400家美国报纸的出版商联盟将OpenAI和微软告上法庭。原告名单涵盖《纽约每日新闻》等知名报纸&#xff0c;以及众多美国本地小报。出版商…

作者头像 李华
网站建设 2026/6/30 3:41:36

3步掌握小说下载器:你的个人数字图书馆终极指南

3步掌握小说下载器&#xff1a;你的个人数字图书馆终极指南 【免费下载链接】novel-downloader 一个可扩展的通用型小说下载器。 项目地址: https://gitcode.com/gh_mirrors/no/novel-downloader 你是否曾遇到过这样的情况&#xff1a;追更的小说突然下架&#xff0c;付…

作者头像 李华
网站建设 2026/6/30 3:40:54

Sand.ai曹越:每代模型押注非共识,视频模型是通往世界模型重要路径

曹越与Sand.ai的创业历程“每一代模型&#xff0c;我们都在押注一个非共识。” Sand.ai创始人曹越不太关心自己站在共识的哪一边。Sand.ai是一家视频生成模型和产品公司&#xff0c;成立于2024年1月。在上一段创业“光年之外”结束后&#xff0c;曹越投入到Sand.ai的创业中&…

作者头像 李华
网站建设 2026/6/30 3:40:41

THS7530EVM评估板实战指南:全差分放大器高速电路设计与调试

1. 项目概述&#xff1a;从评估板到实战设计在模拟电路设计&#xff0c;尤其是高速信号链的构建中&#xff0c;全差分放大器&#xff08;FDA&#xff09;是一个绕不开的核心器件。它不像普通的单端运放那样“接地气”&#xff0c;其差分输入和输出的架构&#xff0c;天生就是为…

作者头像 李华
网站建设 2026/6/30 3:39:29

IP2336H至为芯支持C口双向快充的18W多串锂电池充放电芯片

英集芯IP2336H是一款用于蓝牙音箱、电动工具、移动电源等充电方案的锂电池充放电管理SOC芯片。升压充电兼容5V/3A、9V/2.2A&#xff1b;反向降压放电同样支持 5V/3A、9V/2.2A 输出&#xff0c;充放电功率高达18W。硬件可灵活定制&#xff0c;适配2~6串锂电池配置。集成PD3.0、Q…

作者头像 李华