CodeRoad Map 程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。
由 程序员柏风 独立维护 · 关于作者
学习 更多
RBAC 与安全基础
这一课你将能做到
说清 RBAC 四件套(ServiceAccount/Role/Binding 及其 Cluster 版本)如何组合出权限,并实际创建一套「CI 专用最小权限」
用 kubectl auth can-i 与 --as 模拟(impersonation)验证任意身份的权限
让一个容器以非 root 运行(securityContext),并说出镜像、密钥、网络三道防线的入门清单
为什么要学
集群里「谁能删 Deployment」「Pod 能不能读所有 Secret」直接决定爆炸半径。本站如果多人维护、CI 要自动发布,绝不能人人都绑 cluster-admin——一次误 apply 到错误 namespace、一次 CI 凭证泄漏,都可能是删库级事故。
RBAC(Role-Based Access Control) 是 K8s 内置的授权模型:主体(人/机器)通过绑定获得角色,角色定义「对哪些资源能做哪些动作」。在 RBAC 之上,容器自身还有第二道防线:运行身份(别用 root)、镜像来源(别用来路不明的镜像)、网络边界(默认全通的 Pod 网络)。这些是面试安全题的主战场,更是将来带团队时的基本功。
先建立图像
主体(Subject) 权限(规则) 粘合
User / Group ┌ Role ┐
(人:证书/OIDC) │ verbs × │ ── RoleBinding ──→ 授权(命名空间内)
ServiceAccount │ resources │
(Pod/CI 机器账号) └ ClusterRole ┘ ── ClusterRoleBinding → 授权(全集群)
范围 权限对象 绑定对象 典型用途 命名空间内 Role RoleBinding 业务团队的日常运维 全集群 ClusterRole ClusterRoleBinding 平台管理员、监控采集
人话:Role 写「能干什么」,Binding 写「谁能干」。有 Role 没 Binding = 没权限 ,这是新手第一个混淆点。
跟着做
步骤 1:先自查「我现在是谁、能干什么」
kubectl config current-context
kubectl auth can-i create deployments --namespace default
kubectl auth can-i get secrets --namespace default
kubectl auth can-i "*" "*" --all-namespaces
本地 minikube 里第三条大概率是 yes(你即管理员)——学习环境正常,生产环境这必须是极少数人。
步骤 2:创建 CI 专用 ServiceAccount
sa-ci.yaml:
apiVersion: v1
kind: ServiceAccount
metadata:
name: ci-bot
namespace: default
人话:ServiceAccount 是「给程序用的账号」。Pod 默认挂 default SA;CI 流水线、运维机器人应各配专用 SA——账号能审计、能单独吊销。
kubectl apply -f sa-ci.yaml
步骤 3:写最小权限 Role 并绑定
rbac-ci.yaml(ci-bot 只能管理 default 命名空间的工作负载,不能读 Secret、不能删命名空间):
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: deploy-manager
namespace: default
rules:
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["pods", "pods/log", "services"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ci-bot-deploy-manager
namespace: default
subjects:
- kind: ServiceAccount
name: ci-bot
namespace: default
roleRef:
kind: Role
name: deploy-manager
apiGroup: rbac.authorization.k8s.io
kubectl apply -f rbac-ci.yaml
注意 apiGroups: [""] 的空串表示核心组(Pod/Service 等);Deployment 在 apps 组——写错组名是最常见的「有 Role 却不生效」原因。
步骤 4:用模拟(impersonation)验证权限边界 管理员可以「扮演」任意身份做验证——这是排查 RBAC 的利器:
kubectl get pods --as=system:serviceaccount:default:ci-bot # yes
kubectl create deployment t --image=nginx:1.27-alpine \
--as=system:serviceaccount:default:ci-bot # yes
kubectl get secrets --as=system:serviceaccount:default:ci-bot # Forbidden
kubectl delete namespace kube-system \
--as=system:serviceaccount:default:ci-bot # Forbidden
两个 yes、两个 Forbidden = 权限边界与设计完全一致。CI 的 kubeconfig 就用这个 SA 的凭证,泄漏时吊销它的 Binding 即可,不影响任何人。
kubectl delete deployment t
步骤 5:让容器拒绝 root 运行 先故意制造失败——给 nginx 加 runAsNonRoot: true(而官方 nginx 镜像默认以 root 跑):
# pod-root.yaml
apiVersion: v1
kind: Pod
metadata:
name: root-test
spec:
containers:
- name: web
image: nginx:1.27-alpine
securityContext:
runAsNonRoot: true
kubectl apply -f pod-root.yaml
kubectl get pod root-test # STATUS: CreateContainerConfigError
kubectl describe pod root-test # Events: container has runAsNonRoot and image will run as root
# pod-nonroot.yaml
apiVersion: v1
kind: Pod
metadata:
name: nonroot-test
spec:
containers:
- name: web
image: nginxinc/nginx-unprivileged:1.27-alpine
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
kubectl apply -f pod-nonroot.yaml
kubectl get pod nonroot-test # Running
kubectl delete pod root-test nonroot-test
规则总结:securityContext 在 Pod 级管所有容器,也可在 container 级单独覆盖;「镜像本身用非 root 用户」+「runAsNonRoot」双管齐下才是可落地的方案。
步骤 6:网络边界概念(NetworkPolicy) 许多集群默认 Pod 之间随便连 ——被攻破一个 Pod 就能横向扫描全集群。NetworkPolicy 可以收紧:
# 概念示例:backend 只允许被 platform 访问(需 CNI 支持才生效)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-allow-platform
spec:
podSelector:
matchLabels:
app: backend
policyTypes: ["Ingress"]
ingress:
- from:
- podSelector:
matchLabels:
app: platform
ports:
- port: 8080
本课不要求真跑通(minikube 默认 CNI 不执行策略),记住两个事实即可:① 未配策略 = 全通;② 策略生效依赖 CNI(Calico/Cilium 等)。
讲清楚要点
授权看的是 Binding 不是 Role :Role 只是权限模板,RoleBinding 才把「谁」和「能干什么」连起来;检查权限永远从 Binding 入手。
ClusterRole 级对象慎用 :给 CI 或新人绑 ClusterRoleBinding 到 cluster-admin 是经典事故源;能命名空间内解决的绝不全局。
Secret 可读即泄密 :get secrets 权限要单独严控——读到一个 Secret 就等于拿到它的全部内容,与「能进 Pod」不是一回事。
容器默认常以 root 运行 :显式 securityContext + 镜像内置非 root 用户 + 关闭提权,把逃逸成本抬高一个量级。
镜像供应链仍是安全一环 :本站镜像来自 CI,基础镜像要可信、要扫描(Trivy 等)、要固定 tag/digest;K8s 不管镜像怎么来的。
RBAC 不替代应用层安全 :Spring Security 的认证授权、MySQL 的账号权限各自独立——K8s 权限再小,应用自己的弱口令照样出事。
你可能会懵的地方
User 和 ServiceAccount 差别?
User 是集群外的人/系统(通过证书、OIDC 等认证,K8s 本身不存 User 对象);ServiceAccount 是集群内对象,给 Pod 与程序用。运维人和开发用 User,CI 和应用用 SA。
can-i 返回 yes 就代表安全吗?
不。它只证明「当前身份有权限」,不证明「这个权限应该存在」。定期用 can-i 扫一遍 CI 与服务账号,是权限收敛的日常动作。
Pod Security Admission 是什么?
集群级策略(privileged/baseline/restricted 三档),强制命名空间里的 Pod 满足安全基线(非 root、禁特权等)。入门先手动做好 securityContext,团队大了再上 PSA。
K8s RBAC 和云 IAM 什么关系?
两层不同体系:云 IAM 管「谁能操作云资源/登录集群」,K8s RBAC 管「进了集群后能操作哪些对象」。节点 IAM 角色过宽同样危险,别只盯集群内。
为什么默认网络全通?
K8s 把「如何连」交给 CNI 插件,把「谁能连」交给 NetworkPolicy——都需要显式声明。安全从来不是默认赠送的。
错法对照 错法 问题 正解 所有成员共用 cluster-admin 一次误操作全集群买单 按职责拆 Role + Binding 应用 Pod 挂 default SA 且能读全 ns Secret 被攻破即横向移动 专用 SA + 最小 Role 基础镜像随手 pull 不扫描 带着已知漏洞上线 CI 集成镜像扫描 + 固定版本 容器以 root 跑 逃逸面大 runAsNonRoot + 非 root 镜像 以为 Namespace 就能隔离风险 网络/权限并未隔离 Namespace + RBAC + NetworkPolicy
卡点急救
操作报 Forbidden :按四要素自查——身份(current-context / SA)、apiGroup、resource、verb 是否都在 Role 规则里,Binding 的 subjects/roleRef 是否指向正确;用 --as 逐步缩小是哪一项不匹配。
Pod 卡 CreateContainerConfigError 提示 runAsNonRoot :镜像默认用户是 root——换非特权镜像,或在 Dockerfile 里 USER 指定 UID(数字 UID 比用户名可靠),或在 securityContext 显式 runAsUser。
CI 部署突然 401/403 :SA 的凭证过期或 Binding 被改/删——用 kubectl get rolebinding -o yaml 核对,再用 can-i --as 复现 CI 的身份定位差异。
面试常问
解释 K8s RBAC 的核心对象。
四件套:Role(命名空间内权限规则:apiGroups × resources × verbs);ClusterRole(集群级规则,也可被 RoleBinding 引用以复用);RoleBinding(把主体绑到 Role,作用于命名空间);ClusterRoleBinding(绑定到 ClusterRole,作用于全集群)。主体三种:User、Group、ServiceAccount。判定流程:请求 → 认证 → 鉴权(遍历该主体所有 Binding 聚合出的规则,allow 之和,默认拒绝)。
User 和 ServiceAccount 的区别?CI 该用哪种?
User 面向集群外的人(证书/OIDC 认证,无对应 API 对象);ServiceAccount 是集群内 API 对象,面向 Pod 与程序,有可管理的凭证与 Token。CI 用专用 ServiceAccount + 命名空间级最小 Role:权限可审计、可单独吊销、不依赖任何个人账号(避免「离职删号 CI 瘫痪」)。
K8s 的网络默认安全吗?
不安全:多数 CNI 下所有 Pod 间网络互通,无默认隔离。需要用 NetworkPolicy 显式声明(基于 label 的 L3/L4 规则),且生效依赖 CNI 支持策略执行。纵深防御组合:NetworkPolicy 收网络 + RBAC 收 API + securityContext 收容器 + Secret/密管收凭证。
自测三问
Role 和 ClusterRole 如何选?ClusterRole 一定更危险吗?
为什么 CI 流水线应该用专用 ServiceAccount 而不是某个人的 kubeconfig?
列出三件「即使 RBAC 配好也仍然要做」的安全措施。
小结一句话 RBAC 用 Role+Binding 回答「谁能对哪些资源做什么」,再叠加非 root 运行、镜像扫描与网络策略构成纵深防御——下一课把全部知识串起来,完成 backend 的完整部署验收。
延伸