第38 篇 k8s之RBAC 与 ServiceAccount 实战

0 阅读8分钟

IT策士 10余年一线大厂经验,专注 IT 思维、架构、职场进阶。我会在各个平台持续发布最新文章,助你少走弯路。


在前面的 37 篇文章中,我们一直在“用”Kubernetes——创建 Pod、配置 Deployment、管理存储、设置调度策略。但有一个问题一直被我刻意忽略了:谁有权限做这些事? 到目前为止,你一直在以 cluster-admin(集群管理员)的身份操作,拥有集群的最高权限。

在一个真实的生产集群中,会有多个人、多个团队、多个自动化系统同时操作。开发团队只应该有权更新自己命名空间下的 Deployment,CI/CD 系统只应该有权触发滚动更新,监控系统只应该有权读取 Pod 指标。如果所有人都用 cluster-admin,一次误操作就可能导致全集群故障。

Kubernetes 提供了两套机制来解决权限控制问题:RBAC(Role-Based Access Control,基于角色的访问控制)决定“谁能做什么”,ServiceAccount 决定“Pod 以什么身份与 API Server 交互”。今天这篇,我们从最核心的 RBAC 概念讲起,结合实战为贯穿案例的应用创建最小权限的访问规则。

一、理解 RBAC 的核心组件

RBAC 是 K8s 授权机制的核心,它的设计可以用一句话概括:一个 Subject(主体)通过 RoleBinding(角色绑定)获得 Role(角色)中定义的权限,在指定的命名空间或集群范围内执行特定操作

1.1 四大核心概念

把 RBAC 想象成一个公司的门禁系统,可以帮你快速理解这四个概念:

Role 和 ClusterRole 的区别在于作用范围:

  • Role 作用在特定命名空间内,适合“开发团队只能管理自己的 Pod”这类需求。

  • ClusterRole 作用在整个集群范围,适合访问集群级资源(Node、PV、StorageClass)或需要在所有命名空间生效的权限。

1.2 RBAC 的工作方式

K8s 的 RBAC 遵循默认拒绝原则:如果你没有明确授予某个用户或 ServiceAccount 某项权限,它就是被拒绝的。这与“默认允许,再逐步限制”的安全模型完全相反——更安全,但初次使用时更容易遇到“权限不足”的困惑。

当你执行 kubectl apply -f deployment.yaml 时,API Server 会依次完成:

  1. 认证(Authentication):确认“你是谁”,验证客户端证书或 Bearer Token。

  2. 授权(Authorization):检查你是否拥有执行该操作的 Role。API Server 遍历所有 RoleBinding,检查你是否有对应的权限。

  3. 准入控制(Admission Control):在请求被真正执行前,做最后的校验和修改(如资源配额检查、注入 Sidecar)。

RBAC 就是第二步“授权”的具体实现。

二、实战:为一个“只读用户”创建 Role

场景:新来的运维实习生只需要查看 default 命名空间的 Pod 和 Service 信息,不能做任何修改。

2.1 创建 ServiceAccount

ServiceAccount 是 K8s 为 Pod 内部进程提供的一种身份,也可以用于外部用户。这里我们为实习生创建一个 ServiceAccount:

kubectl create serviceaccount readonly-sa

查看 ServiceAccount:

kubectl get sa readonly-sa
# NAME          SECRETS   AGE
# readonly-sa   0         10s

创建 ServiceAccount 时,K8s 会自动创建一个对应的 Token(存储在 Secret 中),供外部认证使用:

# 获取 Token(K8s v1.24+ 使用方式)
kubectl create token readonly-sa --duration=24h
# eyJhbGciOiJSUzI1NiIsImtpZCI6...(长 Token 字符串)

这个 Token 就是实习生的“门禁卡”——持卡人可以在集群中执行 Token 所关联 ServiceAccount 被授权的操作。

2.2 创建 Role

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: readonly-role
  namespace: default
rules:
  - apiGroups: [""]
    resources: ["pods", "services", "pods/log"]
    verbs: ["get", "list", "watch"]

解读:

  • apiGroups: [""]:核心 API 组(Pod、Service 等核心资源属于空字符串组)。其他常见组包括 apps(Deployment)、batch(Job/CronJob)、networking.k8s.io(NetworkPolicy)。

  • resources:可以访问的资源类型。pods/log 允许查看日志。

  • verbs:允许的操作。get(获取单个资源)、list(列出资源)、watch(监听资源变化)。

2.3 绑定 Role 到 ServiceAccount

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: readonly-binding
  namespace: default
subjects:
  - kind: ServiceAccount
    name: readonly-sa
    namespace: default
roleRef:
  kind: Role
  name: readonly-role
  apiGroup: rbac.authorization.k8s.io

一个 RoleBinding 包含两部分:subjects 指定权限的接收者(可以是多个),roleRef 引用已定义的 Role。两者通过 RoleBinding 关联,实现权限的动态授予和回收。

kubectl apply -f readonly-role.yaml
kubectl apply -f readonly-binding.yaml

2.4 验证只读权限

首先,用 kubectl auth can-i 命令检查权限(这是调试 RBAC 最高效的工具):

kubectl auth can-i get pods --as=system:serviceaccount:default:readonly-sa
# yes

kubectl auth can-i delete pods --as=system:serviceaccount:default:readonly-sa
# no

kubectl auth can-i create deployments --as=system:serviceaccount:default:readonly-sa
# no

如果你拿到 Token 并配置了 kubeconfig(高级操作,此处不展开),实习生只能查看 Pod 和 Service,无法删除或创建任何资源。这就是最小权限原则的体现。

三、ClusterRole 和 ClusterRoleBinding

Role 和 RoleBinding 的作用范围是特定命名空间。如果你需要访问集群级别的资源(如 Node、PersistentVolume),或者需要在所有命名空间中生效,就需要 ClusterRole 和 ClusterRoleBinding。

例如,部署一个集群级别的日志查看器,需要读取所有命名空间的 Pod 日志:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: logs-reader
rules:
  - apiGroups: [""]
    resources: ["pods/log"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: logs-reader-binding
subjects:
  - kind: ServiceAccount
    name: log-viewer-sa
    namespace: default
roleRef:
  kind: ClusterRole
  name: logs-reader
  apiGroup: rbac.authorization.k8s.io

四、实战:为 Flask 应用创建最小权限的 ServiceAccount

到目前为止,我们的 Flask Pod 一直使用 default 命名空间中的 default ServiceAccount——这个 SA 的权限比较宽松。生产环境的最佳实践是为每个应用创建一个专用的 ServiceAccount,并授予最小必要权限

4.1 创建专用 ServiceAccount

kubectl create serviceaccount flask-sa

4.2 创建最小权限 Role

Flask 应用通常不需要直接访问 K8s API(除非代码中包含 K8s 客户端),但它的 Pod 可能需要读取自己的 ConfigMap 或 Secret:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: flask-app-role
  namespace: default
rules:
  - apiGroups: [""]
    resources: ["configmaps", "secrets"]
    verbs: ["get", "list"]
    resourceNames: ["flask-counter-config", "flask-secret"]

resourceNames 字段将权限限制到特定资源实例。这意味着即使 Role 允许 get secrets,也只能访问列表中的 Secret,而不是整个命名空间的所有 Secret。

4.3 绑定并应用到 Deployment

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: flask-app-binding
  namespace: default
subjects:
  - kind: ServiceAccount
    name: flask-sa
roleRef:
  kind: Role
  name: flask-app-role
  apiGroup: rbac.authorization.k8s.io

在 Deployment 中引用 ServiceAccount:

spec:
  template:
    spec:
      serviceAccountName: flask-sa
      containers:
        - name: flask
          image: flask-redis-counter:3.0
kubectl apply -f flask-deployment-with-sa.yaml
kubectl get pod <pod-name> -o jsonpath='{.spec.serviceAccountName}'
# flask-sa

现在 Flask Pod 使用的身份是 flask-sa,如果应用代码尝试访问未授权的 K8s API(如列出所有 Pod),API Server 会返回 403 Forbidden。这就避免了某个被攻破的 Pod 利用过高权限访问集群资源。

五、RBAC 排错指南

kubectl 返回 forbidden 时,按以下步骤排查:

# 1. 确认当前用户/SA 身份
kubectl auth whoami

# 2. 检查是否能执行特定操作
kubectl auth can-i create pods --as=<user>

# 3. 查看某个 Role 的完整权限
kubectl describe role <role-name>

# 4. 查看某个 RoleBinding 的绑定关系
kubectl describe rolebinding <binding-name>

# 5. 检查集群中所有 RoleBinding(搜索特定 SA)
kubectl get rolebinding --all-namespaces -o wide | grep <sa-name>

六、与 Docker Compose 的安全对比

Compose 本身没有用户和权限系统,安全性完全依赖宿主机的 Docker Daemon 权限(通常需要 root 或 docker 组成员)。这意味着任何能运行 docker compose 命令的人,都能看到所有容器的环境变量(包括明文密码)、挂载任意宿主机目录、甚至提权到 root。

K8s 的 RBAC 体系将集群操作权限精细控制到“谁能对哪些资源执行什么操作”,是多租户环境下安全管理的基石。配合 ServiceAccount 机制,Pod 默认无法访问 K8s API,从根本上消除了容器逃逸后横向移动的风险。

七、命令速查表

八、本篇总结

  • RBAC 的四个核心:Role(权限集合)、Subject(用户/SA)、RoleBinding(绑定关系)、ClusterRole(集群级权限)。三者缺一不可。

  • 命名空间与集群作用域:Role 限定命名空间,ClusterRole 跨越所有命名空间。日常应用授权使用 Role 即可,集群级工具(监控、日志)才需要 ClusterRole。

  • ServiceAccount:Pod 与 K8s API 交互的身份凭证,每个 Pod 必须关联一个 ServiceAccount。为应用创建专属 SA 并授予最小必要权限,是安全最佳实践。

  • 最小权限原则:永远只授予应用所需的最小权限。用 resourceNames 限制到具体资源实例,用命名空间级 Role 限制作用范围。

本篇是 K8s 核心系列(第 19-38 篇)的最后一篇。至此,你已经完整掌握了从 Pod、控制器、Service、Ingress,到配置管理、存储、资源管理、调度策略和 RBAC 安全体系。下一篇——第 39 篇:Helm 入门:包管理工具与 Chart,我们将进入 K8s 生态与实战阶段,学习如何用 Helm 统一打包和管理复杂的 K8s 应用。

想了解更多还可以去各个平台搜索「IT策士」,一起升级 IT 思维 !