K8s权限管理

1. RBAC 机制概述

RBAC(Role-Based Access Control)是 Kubernetes 中控制 API 访问权限的核心机制,从 v1.8 起默认启用。核心思想:谁(Subject)可以对什么资源(Resource)做什么操作(Verb)

当请求到达 API Server 时,RBAC 判定流程:

  1. 认证阶段确认请求者身份(User/Group/ServiceAccount)
  2. 遍历所有与该身份相关的 RoleBinding / ClusterRoleBinding
  3. 检查绑定的 Role / ClusterRole 中的规则是否允许该操作
  4. 只要有一条规则匹配即放行,没有匹配则拒绝

💡 提示:RBAC 是累加型的——只能授予权限,不能拒绝。如果需要拒绝某些操作,需配合 NodeRestriction、Pod Security Standards 等准入控制实现。

2. RBAC 核心对象

对象作用域说明
Role命名空间内定义一组权限规则,只作用于单个 namespace
ClusterRole集群级别定义集群范围的权限(如节点、PV 等非命名空间资源,或跨所有 namespace 的权限)
RoleBinding命名空间内将 Role 绑定给 Subject(User/Group/ServiceAccount)
ClusterRoleBinding集群级别将 ClusterRole 绑定给 Subject

关键点:Role + RoleBinding 限定在 namespace 内,ClusterRole + ClusterRoleBinding 作用于整个集群。但 ClusterRole 也可以通过 RoleBinding 在某个 namespace 内引用——这时集群级的权限规则会被"收缩"到该 namespace 范围内。

3. 权限规则结构

一条规则由三部分组成:

YAMLrules:
- apiGroups: ["", "apps"]           # 资源所属的 API 组("" 是核心组)
  resources: ["pods", "deployments"] # 操作的资源类型
  verbs: ["get", "list", "watch"]    # 允许的操作

常见 verbs:getlistwatchcreateupdatepatchdeletedeletecollection

还可以用 resourceNames 字段进一步限定到特定资源实例,比如只允许访问名为 my-config 的 ConfigMap。

4. Subject 类型

RBAC 中 Subject 有三种类型:

  1. User — 外部用户,由集群外的认证系统(如 OIDC、证书)管理,K8s 本身不存储 User 对象
  2. Group — 用户组,同样由外部认证系统提供
  3. ServiceAccount — K8s 内部身份,Pod 通过挂载 token 自动获取,用于 Pod 内进程访问 API Server

5. 创建用户实体与凭证

K8s 没有 User API 对象,用户身份完全依赖外部凭证来表征。整个流程:造证书 → 签名 → 写入 kubeconfig → 绑定权限 → 创建 context → 切换使用

5.1 生成用户私钥和 CSR

Bash# 1. 生成私钥
openssl genrsa -out devuser.key 2048

# 2. 用私钥生成证书签名请求(CSR)
#    -subj 中的 CN 就是 Kubernetes 识别的用户名,O 是组名
openssl req -new -key devuser.key -out devuser.csr \
  -subj "/CN=devuser/O=dev-team/O=developers"

关键字段:

  • CN(Common Name)→ K8s 中的 User
  • O(Organization)→ K8s 中的 Group 名,可以写多个

5.2 用集群 CA 签发证书

方式一:直接用 CA 密钥签发(需要拿到 master 节点的 CA 证书和密钥)

Bashopenssl x509 -req -in devuser.csr \
  -CA /etc/kubernetes/pki/ca.crt \
  -CAkey /etc/kubernetes/pki/ca.key \
  -CAcreateserial \
  -out devuser.crt \
  -days 365

方式二:通过 CSR 审批流程(适用于云托管集群,拿不到 CA key)

Bash# 将 CSR base64 编码
cat devuser.csr | base64 | tr -d '\n'
YAMLapiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: devuser-csr
spec:
  request: <base64 编码的 CSR 内容>
  signerName: kubernetes.io/kube-apiserver-client
  expirationSeconds: 86400
  usages:
  - client auth
Bash# 审批通过
kubectl certificate approve devuser-csr

# 取出签好的证书
kubectl get csr devuser-csr -o jsonpath='{.status.certificate}' | base64 -d > devuser.crt

5.3 创建 RBAC 权限绑定

此时 devuser 还没有任何权限,需要创建 Role + RoleBinding:

YAMLapiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: dev-developer
  namespace: dev
rules:
- apiGroups: ["", "apps"]
  resources: ["pods", "deployments", "services"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
  resources: ["pods/log"]
  verbs: ["get"]
YAMLapiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: dev-developer-binding
  namespace: dev
subjects:
- kind: User
  name: devuser
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: dev-developer
  apiGroup: rbac.authorization.k8s.io

5.4 在 kubeconfig 中设置凭证

Bashkubectl config set-credentials devuser \
  --client-certificate=devuser.crt \
  --client-key=devuser.key

5.5 创建 Context 并切换

Bash# 创建 context
kubectl config set-context devuser-context \
  --cluster=your-cluster-name \
  --user=devuser \
  --namespace=dev

# 切换到新 context
kubectl config use-context devuser-context

# 验证
kubectl auth can-i create deployments
kubectl auth can-i list pods -n dev

5.6 全景流程

openssl genrsa → devuser.key (私钥)
        │
        ▼
openssl req -new → devuser.csr (签名请求,CN=devuser)
        │
        ▼
集群 CA 签发 → devuser.crt (用户证书)
        │
        ├──→ kubectl config set-credentials (写入 kubeconfig users 段)
        ├──→ kubectl config set-context    (组合 cluster + user + ns)
        ├──→ Role + RoleBinding            (授予权限)
        ▼
kubectl config use-context → 就可以操作集群了

6. kubeconfig 文件解析

kubeconfig 是 Kubernetes 客户端的配置文件,默认路径 ~/.kube/config,它本质上就是一组集群、凭证、上下文的映射关系。

6.1 三大顶层段

YAMLapiVersion: v1
kind: Config
preferences: {}
current-context: devuser-context

clusters:     # 集群列表 —— 去哪访问
- name: my-cluster
  cluster:
    server: https://192.168.1.100:6443
    certificate-authority: /etc/kubernetes/pki/ca.crt

users:        # 凭证列表 —— 用什么身份
- name: devuser
  user:
    client-certificate: /path/to/devuser.crt
    client-key: /path/to/devuser.key

contexts:     # 上下文列表 —— 组合集群和凭证
- name: devuser-context
  context:
    cluster: my-cluster
    user: devuser
    namespace: dev

三者的关系:context = cluster + user + namespace

6.2 clusters 段

字段说明
serverAPI Server 的 URL
certificate-authority集群 CA 证书文件路径,验证 API Server 身份
certificate-authority-data同上,base64 内嵌
insecure-skip-tls-verify跳过 TLS 验证,生产环境绝不建议

6.3 users 段认证方式

认证方式字段适用场景
X.509 证书client-certificate + client-key自建集群、用户证书认证
TokentokenServiceAccount token、静态 token
OIDCauth-provideroidc 配置块企业 SSO 对接
Exec 插件exec → 命令 + 参数云厂商 CLI 动态获取凭证

6.4 contexts 段

同一个 user 可以出现在多个 context 中,同一个 cluster 也可以配不同 usernamespace 字段只是默认值,kubectl -n 可以覆盖。

6.5 配置合并与优先级

kubectl 按以下顺序加载配置,后加载的覆盖先加载的:

  1. 系统级配置:/etc/kubernetes/admin.conf
  2. 用户级配置:~/.kube/config
  3. 指定文件:KUBECONFIG=/path/a:/path/b

KUBECONFIG 支持多文件,用 :(Linux)或 ;(Windows)分隔。

6.6 常用操作

Bashkubectl config view              # 查看完整配置(脱敏)
kubectl config view --raw        # 不脱敏,显示证书原文
kubectl config use-context ctx   # 切换 context
kubectl config current-context   # 查看当前 context
kubectl config set-context --current --namespace=kube-system  # 修改当前 context 的 namespace

7. ServiceAccount 详解

ServiceAccount(SA)是 Kubernetes 内置的身份机制,专门给集群内部的进程(Pod)使用,让 Pod 里的程序能以确定身份访问 API Server。

7.1 核心机制

Pod 启动
  │
  ├── 自动挂载 SA 的 token 到 /var/run/secrets/kubernetes.io/serviceaccount/
  │     ├── token      ← JWT 令牌
  │     ├── ca.crt     ← 集群 CA 证书
  │     └── namespace  ← 当前命名空间
  │
  └── Pod 内程序用这个 token 调用 API Server
        │
        └── API Server 根据 SA 身份 + RBAC 规则决定是否放行

Pod 默认使用所在 namespace 的 default SA,除非显式指定。

7.2 创建与使用

YAML# 创建 SA
apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-sa
  namespace: dev
YAML# Pod 中引用 SA
apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  serviceAccountName: my-sa
  automountServiceAccountToken: true  # 默认 true
  containers:
  - name: app
    image: my-app:latest
YAML# 给 SA 绑定权限
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: my-sa-reader
  namespace: dev
subjects:
- kind: ServiceAccount
  name: my-sa
  namespace: dev
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

7.3 SA 的身份标识

SA 的完整标识:system:serviceaccount:{namespace}:{sa-name}

Bashkubectl auth can-i list pods \
  --as=system:serviceaccount:dev:my-sa \
  -n dev

7.4 Token 演进

阶段机制特点
v1.22 之前SA 自动关联 Secret,存永久 token不过期,泄露即永久风险
v1.22+TokenRequest API 动态签发短期 token默认 1 小时过期,Pod 挂载投射卷
手动创建kubectl create token my-sa按需获取临时 token

v1.24 起创建 SA 不再自动生成 Secret:

Bash# 获取临时 token
kubectl create token my-sa -n dev

# 指定有效期
kubectl create token my-sa -n dev --duration=2h

7.5 SA vs User

维度ServiceAccountUser
管理方式K8s API 对象无 API 对象,外部认证系统管理
使用者Pod 内进程kubectl 操作者、CI/CD 系统
认证方式自动挂载 token / TokenRequest证书、OIDC、Webhook 等
作用域命名空间级别集群级别
RBAC Subjectkind: ServiceAccountkind: Userkind: Group

8. 命名空间 SA 与全局权限

ServiceAccount 永远属于某个 namespace,K8s 不存在集群级别的 SA。"全局效果"是 RBAC 绑定造成的错觉。

8.1 "全局效果"的来源

SA 本身是局部的,但通过 ClusterRoleBinding 可以让一个 namespace 内的 SA 获得跨所有 namespace 的权限:

YAMLapiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: my-sa-global-reader
subjects:
- kind: ServiceAccount
  name: my-sa
  namespace: dev
roleRef:
  kind: ClusterRole
  name: view
  apiGroup: rbac.authorization.k8s.io

8.2 两种绑定方式的区别

绑定方式权限范围SA 能操作的范围
RoleBinding + Rolenamespace 内只能操作 SA 所在 namespace
RoleBinding + ClusterRolenamespace 内ClusterRole 规则被收窄到 RoleBinding 所在 namespace
ClusterRoleBinding + ClusterRole集群级别可操作所有 namespace + 集群级资源
SA (namespace: dev)
  │
  ├── RoleBinding(dev) + Role
  │     → 只能操作 dev namespace
  │
  ├── RoleBinding(prod) + ClusterRole
  │     → 规则被限制在 prod namespace
  │
  └── ClusterRoleBinding + ClusterRole
        → 可操作所有 namespace + 集群级资源

8.3 kube-system 下的 SA 不是"全局 SA"

kube-system 下的 SA(coredns、endpoint-controller 等)只是恰好创建在该 namespace 中,通过 ClusterRoleBinding 获得了集群级权限。放到任何 namespace 都能达到同样效果。

8.4 实际设计模式

模式一:每个 namespace 独立 SA + RoleBinding(最常见,最安全)

不同 namespace 同名 SA 是完全独立的两个身份,权限互不干扰。

模式二:一个 SA + ClusterRoleBinding(集群级运维工具、Controller)

适用于 Prometheus、Falco、巡检工具等需要跨 namespace 只读的组件。

模式三:SA 跨 namespace 引用

RoleBinding/ClusterRoleBinding 的 subjects 中指定 SA 的 namespace 即可授权。

9. 排查命令速查

Bash# 检查某个 SA 是否有特定权限
kubectl auth can-i list pods --as=system:serviceaccount:default:my-sa

# 检查某个 User 的权限
kubectl auth can-i list pods --as=devuser

# 查看 Role 的详细规则
kubectl get role pod-reader -n default -o yaml

# 查看集群中所有 ClusterRoleBinding
kubectl get clusterrolebindings -o wide

# 查看当前身份
kubectl auth whoami
目录