Skip to content

RBAC 与安全

生产集群里 admin.conf 到处复制、所有组件默认拿 cluster-admin,这两种做法会把权限面打得很开——任何人拿到这个 kubeconfig 就能删任意资源、读所有 Secret、改集群配置。RBAC 做的就是把"谁能做什么"收紧到最小范围。

RBAC 的对象模型不复杂,但和 ServiceAccount、Pod 安全上下文、审计日志放在一起,才能覆盖一条完整的 API 请求链路——谁、用什么身份、访问什么资源、做了什么操作、事后能不能追溯到。

RBAC 四类对象

对象作用范围说明
Rolenamespace 内定义在某 namespace 里能做什么
ClusterRole集群级定义集群范围资源(nodes、PV、namespaces)或跨 namespace 操作
RoleBindingnamespace 内把 Role 或 ClusterRole 授权给 namespace 内的主体
ClusterRoleBinding集群级把 ClusterRole 授权到全集群
ServiceAccountnamespace 内Pod 访问 API Server 时用的身份

RoleBinding 可以引用 ClusterRole 但只在一个 namespace 内生效。这个设计允许定义一个"只读 Pod"的 ClusterRole,然后在每个 namespace 里分别绑给不同的人——不用在每个 namespace 都建一份 Role。

只读示例

给用户在 demo namespace 里只读 Pod 和 Pod 日志:

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: demo
rules:
  - apiGroups: [""]              # 核心 API 组的 apiGroup 是空字符串
    resources: ["pods", "pods/log"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-reader
  namespace: demo
subjects:
  - kind: User
    name: ops-readonly
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

验证权限——kubectl auth can-i 走 SubjectAccessReview API,直接问 apiserver "这个身份能不能做这个操作":

bash
kubectl auth can-i list pods -n demo --as=ops-readonly
kubectl auth can-i delete pods -n demo --as=ops-readonly    # 预期 no

ServiceAccount

Pod 访问 API Server 默认用的是所在 namespace 的 default ServiceAccount。生产里给不同组件单独建 SA 并绑定最小权限:

yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-reader
  namespace: demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
  namespace: demo
spec:
  template:
    spec:
      serviceAccountName: app-reader

给控制器、采集组件、CI Runner 分配 SA 时,先想清楚它需要读什么(get/list/watch)、是否需要写(create/update/patch/delete)、是否需要删(delete/deletecollection)。只读场景给读写权限是多余的。

Secret 权限

get secret 的人基本上能拿到 Secret 里的所有明文内容(base64 不是加密)。Secret 保护要从多个层面看:

防护层解决的问题
RBAC谁能通过 API 读取 Secret
etcd 加密Secret 在 etcd 存储层是否明文
审计日志事后能否追溯谁读了 Secret
CI/CDCI 流程是否把 Secret 打印到日志里
Git明文 Secret 是否被提交到了仓库

Pod 安全上下文

Pod 和容器级别的安全配置通过 securityContext 设置:

yaml
securityContext:             # Pod 级别
  runAsNonRoot: true
  runAsUser: 10001
  fsGroup: 10001
containers:
  - name: app
    image: harbor.example.com/demo/app:v1.0.0
    securityContext:         # 容器级别
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop:
          - ALL

高风险配置值得定期审计:

配置暴露的风险
privileged: true容器几乎等同宿主机 root
hostPath 挂载敏感目录直接读写宿主机文件系统
hostNetwork: true使用宿主机网络命名空间
hostPID: true能看到宿主机所有进程
挂载 Docker/containerd socket可以在容器内控制宿主机上的所有容器
capabilities.add: ["SYS_ADMIN", "NET_ADMIN"]接近 privileged 的权限面

审计日志

审计策略决定 API Server 记录什么请求:

yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  - level: Metadata
    verbs: ["get", "list", "watch"]
  - level: RequestResponse   # 记录完整请求体和响应体
    verbs: ["create", "update", "patch", "delete"]
    resources:
      - group: ""
        resources: ["secrets"]

API Server 参数:

yaml
- --audit-policy-file=/etc/kubernetes/audit-policy.yaml
- --audit-log-path=/var/log/kubernetes/audit.log
- --audit-log-maxage=30
- --audit-log-maxbackup=10
- --audit-log-maxsize=100

RequestResponse 级别会记录请求和响应的具体内容——如果包含 Secret、token,审计日志本身就成了敏感数据源。策略要根据资源敏感度分层:对 Secret 的读写用 RequestResponse,对普通 Pod 的 get/list 用 Metadata

权限排查

查权限时先确认身份,再查绑定链:

bash
kubectl auth can-i create pods -n demo --as=alice
kubectl auth can-i get secrets -A --as=system:serviceaccount:demo:app-reader
kubectl describe rolebinding -n demo
kubectl describe clusterrolebinding

排查顺序:

  1. 确认身份(User、Group、ServiceAccount)
  2. 查 RoleBinding/ClusterRoleBinding 指向哪些 Role/ClusterRole
  3. 看 Role/ClusterRole 里的具体 rules
  4. kubectl auth can-i 验证单项操作

生产里至少把人为操作、系统组件和 CI/CD 的身份分开。共用 admin.conf 的问题不只是权限过大,而是误删和误改之后无法追溯到人。