RBAC 权限控制流程

概述

RBAC (Role-Based Access Control) 是 Kubernetes 默认的授权模式,通过 Role 和 RoleBinding 来控制用户对资源的访问权限。

核心概念

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
┌─────────────────────────────────────────────────────────────────────────────┐
│ Role (角色) │
│ 定义一组权限规则 (PolicyRules),包含 verbs、resources、apiGroups │
│ pkg/apis/rbac/types.go │
└─────────────────────────────────────────────────────────────────────────────┘

│ 绑定

┌─────────────────────────────────────────────────────────────────────────────┐
│ RoleBinding (角色绑定) │
│ 将 Role 绑定到 Subject (User/Group/ServiceAccount) │
│ 作用域: Namespace 内 │
└─────────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────────┐
│ ClusterRole (集群角色) │
│ 集群级别的 Role,可访问集群范围资源 │
│ 可被 RoleBinding 引用 (跨命名空间授权) │
└─────────────────────────────────────────────────────────────────────────────┘

│ 绑定

┌─────────────────────────────────────────────────────────────────────────────┐
│ ClusterRoleBinding (集群角色绑定) │
│ 将 ClusterRole 绑定到 Subject,集群范围生效 │
└─────────────────────────────────────────────────────────────────────────────┘

核心数据结构

Role/ClusterRole

1
2
3
4
5
6
7
8
9
10
11
12
// pkg/apis/rbac/types.go
type PolicyRule struct {
Verbs []string // 操作: get, list, create, update, delete, patch, watch
APIGroups []string // API 组: "", "apps", "batch" 等
Resources []string // 资源: pods, deployments, secrets 等
ResourceNames []string // 资源名称 (可选)
NonResourceURLs []string // 非资源 URL: /healthz, /metrics 等
}

type Role struct {
Rules []PolicyRule
}

RoleBinding

1
2
3
4
5
6
7
8
9
10
type RoleBinding struct {
Subjects []Subject // 绑定目标
RoleRef RoleRef // 引用的 Role
}

type Subject struct {
Kind string // "User", "Group", "ServiceAccount"
Name string
Namespace string // ServiceAccount 需要指定命名空间
}

授权检查流程

主入口

  • 文件: plugin/pkg/auth/authorizer/rbac/rbac.go
  • 函数: RBACAuthorizer.Authorize()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
┌──────────────────────────────────────────────────────────────────────────────┐
│ 授权请求 │
│ RBACAuthorizer.Authorize(ctx, attributes) │
└──────────────────────────────────────────────────────────────────────────────┘


┌──────────────────────────────────────────────────────────────────────────────┐
│ 遍历用户的权限规则 │
│ authorizationRuleResolver.VisitRulesFor(user, namespace, visitor) │
└──────────────────────────────────────────────────────────────────────────────┘


┌──────────────────────────────────────────────────────────────────────────────┐
│ 检查规则是否匹配 │
│ RuleAllows(requestAttributes, rule) │
│ - 匹配 Verb │
│ - 匹配 APIGroup │
│ - 匹配 Resource │
│ - 匹配 ResourceName (如果指定) │
│ - 匹配 NonResourceURL (非资源请求) │
└──────────────────────────────────────────────────────────────────────────────┘

┌───────────────┴───────────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 允许访问 │ │ 拒绝访问 │
│ DecisionAllow │ │ DecisionDeny │
└──────────────┘ └──────────────┘

规则解析器

  • 文件: pkg/registry/rbac/rest/mapping.go
  • 作用: 解析用户绑定的所有 Role 和 ClusterRole
1
2
3
4
5
6
7
8
9
10
11
12
13
1. 获取用户信息 (User.Info)
├── 用户名 (GetName)
├── 用户组 (GetGroups)
└── 额外信息 (GetExtra)

2. 查找绑定的 Role
├── RoleBindings (命名空间内)
│ └── 匹配 Subject -> 获取 Role
└── ClusterRoleBindings (集群范围)
└── 匹配 Subject -> 获取 ClusterRole

3. 合并所有 PolicyRules
└── 返回规则列表供授权检查

关键代码路径

1. RBAC 授权器

  • 文件: plugin/pkg/auth/authorizer/rbac/rbac.go
  • 核心函数:
    • Authorize() - 授权检查入口 (第 75 行)
    • RuleAllows() - 规则匹配检查

2. 规则解析

  • 文件: pkg/registry/rbac/rest/mapping.go
  • 接口: RequestToRuleMapper
  • 方法:
    • RulesFor() - 获取用户所有规则
    • VisitRulesFor() - 遍历用户规则

3. 规则匹配

  • 文件: pkg/apis/rbac/validation/rule.go
  • 函数: Covers() - 检查规则覆盖范围

4. Subject 匹配

  • 文件: pkg/registry/rbac/rest/mapping.go
  • 函数: subjectsMatch() - 检查用户是否匹配 Subject

权限检查示例

示例 1: 用户获取 Pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 请求属性
User: "alice"
Verb: "get"
Resource: "pods"
APIGroup: ""
Namespace: "default"
Name: "my-pod"

# 检查流程
1. 查找 alice 的所有 RoleBinding
2. 获取对应的 Role/ClusterRole
3. 遍历 PolicyRules:
- Rule: verbs=["get"], resources=["pods"], apiGroups=[""]
- 匹配成功

示例 2: ServiceAccount 创建 Secret

1
2
3
4
5
6
7
8
9
10
11
12
13
# 请求属性
User: "system:serviceaccount:my-ns:my-sa"
Verb: "create"
Resource: "secrets"
APIGroup: ""
Namespace: "my-ns"

# 检查流程
1. 查找 ServiceAccount RoleBinding
2. 获取 Role
3. 遍历 PolicyRules:
- Rule: verbs=["create"], resources=["secrets"]
- 匹配成功

权限聚合规则

1. 多个 RoleBinding 聚合

用户的所有 RoleBinding 和 ClusterRoleBinding 的权限会累加:

  • 有 get 权限 + 有 create 权限 = 有 get 和 create 权限

2. ClusterRole 的命名空间降级

ClusterRole 可以被 RoleBinding 引用,此时权限被限制在命名空间内:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# ClusterRole
rules:
- verbs: ["get"]
resources: ["secrets"]

# RoleBinding (在 namespace-a)
roleRef:
kind: ClusterRole
name: secret-reader
subjects:
- kind: User
name: alice

# 结果: alice 只能在 namespace-a 中 get secrets

常见权限配置

1. 只读权限

1
2
3
4
5
6
7
8
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: view
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps"]
verbs: ["get", "list", "watch"]

2. 管理员权限

1
2
3
4
5
6
7
8
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: admin
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]

3. 命名空间管理员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: namespace-admin
namespace: my-ns
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: admin-binding
namespace: my-ns
subjects:
- kind: User
name: alice
roleRef:
kind: Role
name: namespace-admin

调试技巧

1. 检查用户权限

1
2
3
4
5
# 模拟授权检查
kubectl auth can-i get pods --as=alice -n default

# 检查 ServiceAccount 权限
kubectl auth can-i create secrets --as=system:serviceaccount:my-ns:my-sa

2. 查看绑定的角色

1
2
3
4
5
# 查看 RoleBinding
kubectl get rolebinding -n my-ns -o yaml

# 查看 ClusterRoleBinding
kubectl get clusterrolebinding -o yaml

3. 排查权限问题

1
2
3
4
5
6
# 查看 apiserver 日志 (需要 v=5 级别)
kube-apiserver --v=5

# 日志示例
# RBAC: no rules authorize user "alice" with groups ["system:authenticated"]
# to "get" resource "pods" in namespace "default"

性能优化

1. 规则缓存

RBAC Authorizer 会缓存规则解析结果,减少 etcd 查询:

  • 文件: staging/src/k8s.io/apiserver/pkg/authorization/cel

2. 索引优化

RoleBinding 按 Subject 建立索引:

  • 文件: pkg/registry/rbac/rest/rest.go

相关文件清单

文件路径 说明
plugin/pkg/auth/authorizer/rbac/rbac.go RBAC 授权器实现
pkg/apis/rbac/types.go RBAC API 类型定义
pkg/registry/rbac/rest/mapping.go 规则解析器
pkg/registry/rbac/rest/rest.go RBAC REST API
pkg/apis/rbac/validation/rule.go 规则验证
staging/src/k8s.io/apiserver/pkg/authorization/authorizer/ 授权器接口

面试题

基础题

1. RBAC 的核心概念有哪些?

参考答案:

  • Role:命名空间级别的权限规则集合
  • ClusterRole:集群级别的权限规则集合
  • RoleBinding:将 Role 绑定到 Subject(命名空间内)
  • ClusterRoleBinding:将 ClusterRole 绑定到 Subject(集群范围)
  • Subject:权限绑定的目标(User、Group、ServiceAccount)

2. Role 和 ClusterRole 有什么区别?

参考答案:

特性 Role ClusterRole
作用范围 单个命名空间 整个集群
可访问资源 命名空间资源 命名空间资源 + 集群资源
可被引用 RoleBinding RoleBinding + ClusterRoleBinding
典型场景 命名空间内权限 集群管理、跨命名空间权限

3. Subject 有哪几种类型?

参考答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
subjects:
# 1. User(用户)
- kind: User
name: "alice@example.com"
apiGroup: rbac.authorization.k8s.io

# 2. Group(用户组)
- kind: Group
name: "system:authenticated"
apiGroup: rbac.authorization.k8s.io

# 3. ServiceAccount(服务账号)
- kind: ServiceAccount
name: my-sa
namespace: default

中级题

4. PolicyRule 的核心字段有哪些?分别说明含义。

参考答案:

1
2
3
4
5
6
rules:
- verbs: ["get", "list", "watch"] # 操作
apiGroups: ["", "apps"] # API 组("" 表示核心组)
resources: ["pods", "deployments"] # 资源类型
resourceNames: ["my-pod"] # 资源名称(可选)
nonResourceURLs: ["/healthz"] # 非资源 URL(可选)

说明

  • verbs:允许的操作(get/list/watch/create/update/delete/patch/*)
  • apiGroups:API 组(* 表示所有组)
  • resources:资源类型(* 表示所有资源)
  • resourceNames:限制特定资源名称
  • nonResourceURLs:非资源路径(如 /healthz、/metrics)

5. RoleBinding 如何引用 ClusterRole?有什么应用场景?

参考答案:

配置示例

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: development
subjects:
- kind: User
name: dev-user
roleRef:
kind: ClusterRole # 引用 ClusterRole
name: pod-reader
apiGroup: rbac.authorization.k8s.io

应用场景

  1. 复用权限定义:定义一次 ClusterRole,在多个命名空间复用
  2. 跨命名空间授权:给用户在特定命名空间的权限
  3. 权限降级:将集群级权限限制在命名空间内

注意:权限仍然只在该命名空间内生效!

6. 解释 RBAC 权限的聚合规则。

参考答案:

聚合规则:用户的多个 RoleBinding 的权限会累加

1
2
3
4
5
6
7
8
9
# RoleBinding 1: 允许读取 Pod
- verbs: ["get", "list"]
resources: ["pods"]

# RoleBinding 2: 允许读取 Service
- verbs: ["get", "list"]
resources: ["services"]

# 最终权限: 可以读取 Pod 和 Service

重要特性

  • 权限是累加的,没有”拒绝”规则
  • Deny 需要通过准入控制或其他机制实现

7. ClusterRole 的聚合(Aggregation)功能是什么?

参考答案:
ClusterRole 可以聚合其他 ClusterRole 的规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitoring
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.example.com/aggregate-to-monitoring: "true"
rules: [] # 规则会自动填充
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pods-reader
labels:
rbac.example.com/aggregate-to-monitoring: "true"
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]

应用场景:动态组合权限,系统自动聚合匹配的 ClusterRole。


高级题

8. RBAC 授权检查的完整流程是怎样的?

参考答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1. 提取请求属性
├── 用户信息 (User.Info)
├── 请求动词 (Verb)
├── 资源信息 (Resource, APIGroup, Subresource)
├── 命名空间 (Namespace)
└── 资源名称 (Name)

2. 遍历权限规则
├── 获取用户的所有 RoleBinding
├── 获取对应的 Role/ClusterRole
└── 遍历 PolicyRules

3. 规则匹配
├── 检查 Verb 匹配
├── 检查 APIGroup 匹配
├── 检查 Resource 匹配
└── 检查 ResourceName 匹配(如果指定)

4. 返回决策
└── DecisionAllow / DecisionNoOpinion

关键代码

  • plugin/pkg/auth/authorizer/rbac/rbac.go:75 - Authorize()
  • pkg/registry/rbac/rest/mapping.go - VisitRulesFor()

9. 如何实现权限的”拒绝”功能?

参考答案:

RBAC 本身不支持 Deny 规则,但可以通过以下方式实现:

1. 准入控制 Webhook

1
2
3
4
5
6
7
func validate(request *admission.AdmissionRequest) bool {
// 自定义拒绝逻辑
if isDenied(request) {
return false
}
return true
}

2. 准入控制插件

  • PodSecurity - 拒绝不安全的 Pod
  • ResourceQuota - 拒绝超配额请求

3. OPA/Gatekeeper

1
2
3
4
5
6
7
8
9
10
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
spec:
crd:
spec:
validation:
openAPIV3Schema:
properties:
deniedNamespaces:
type: array

10. ServiceAccount 的 RBAC 权限是如何工作的?

参考答案:

1. ServiceAccount 创建

1
2
3
4
5
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-sa
namespace: default

2. 自动创建 Secret(Token)

1
2
3
4
5
6
7
apiVersion: v1
kind: Secret
metadata:
name: my-sa-token
annotations:
kubernetes.io/service-account.name: my-sa
type: kubernetes.io/service-account-token

3. 绑定权限

1
2
3
4
5
6
7
8
9
10
11
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-sa-binding
subjects:
- kind: ServiceAccount
name: my-sa
namespace: default
roleRef:
kind: Role
name: pod-reader

4. Pod 使用

1
2
3
4
5
spec:
serviceAccountName: my-sa
containers:
- name: app
# Token 自动挂载到 /var/run/secrets/kubernetes.io/serviceaccount/token

11. 解释 system:authenticated 和 system:unauthenticated 组的作用。

参考答案:

说明 典型用途
system:authenticated 所有已认证用户 给登录用户基本权限
system:unauthenticated 所有未认证用户 限制匿名访问
system:serviceaccounts 所有 ServiceAccount 给 SA 基本权限
system:serviceaccounts:<ns> 指定命名空间的 SA 命名空间 SA 权限

示例

1
2
3
4
5
6
7
8
9
10
11
12
# 给所有认证用户基本发现权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: discovery
subjects:
- kind: Group
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: system:discovery

12. 如何调试 RBAC 权限问题?

参考答案:

1. 使用 auth can-i 命令

1
2
3
4
5
6
7
8
# 检查当前用户权限
kubectl auth can-i get pods -n default

# 模拟其他用户
kubectl auth can-i get pods --as=alice -n default

# 模拟 ServiceAccount
kubectl auth can-i get secrets --as=system:serviceaccount:default:my-sa

2. 查看绑定

1
2
3
4
5
# 列出所有 RoleBinding
kubectl get rolebinding,clusterrolebinding -A

# 查看详细信息
kubectl describe clusterrolebinding admin-binding

3. 检查 apiserver 日志

1
2
3
4
5
6
# 启用详细日志
kube-apiserver --v=5

# 日志示例
# RBAC: no rules authorize user "alice" with groups ["system:authenticated"]
# to "get" resource "pods" in namespace "default"

4. 使用 SubjectAccessReview API

1
2
3
4
5
6
7
8
apiVersion: authorization.k8s.io/v1
kind: SubjectAccessReview
spec:
resourceAttributes:
namespace: default
verb: get
resource: pods
user: alice

场景题

13. 如何设计一个多租户系统的 RBAC 方案?

参考答案:

1. 角色设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 命名空间管理员
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: tenant-admin
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
# 排除敏感资源
- apiGroups: [""]
resources: ["namespaces", "nodes"]
verbs: [] # 无权限
---
# 命名空间开发者
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: tenant-developer
rules:
- apiGroups: ["", "apps", "batch"]
resources: ["pods", "deployments", "jobs", "configmaps", "secrets"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"] # 只读

2. 自动化绑定

1
2
3
4
5
6
7
8
9
10
11
12
# 使用 Namespace Controller 自动创建 RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: tenant-admin-binding
namespace: tenant-a
subjects:
- kind: Group
name: tenant-a-admins
roleRef:
kind: ClusterRole
name: tenant-admin

3. 隔离策略

  • 每个租户独立命名空间
  • 使用 NetworkPolicy 隔离网络
  • 使用 ResourceQuota 限制资源

14. 如何实现跨命名空间的只读权限?

参考答案:

方案 1:使用 ClusterRole + 多个 RoleBinding

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# ClusterRole 定义只读权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cross-ns-reader
rules:
- apiGroups: ["", "apps"]
resources: ["pods", "deployments", "services"]
verbs: ["get", "list", "watch"]
---
# 在每个命名空间创建 RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: reader
namespace: ns-a
subjects:
- kind: User
name: alice
roleRef:
kind: ClusterRole
name: cross-ns-reader

方案 2:使用 ClusterRoleBinding(谨慎使用)

1
2
3
4
5
6
7
8
9
10
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: all-namespaces-reader
subjects:
- kind: User
name: alice
roleRef:
kind: ClusterRole
name: view # 内置只读角色

15. 如何限制用户只能访问特定名称的资源?

参考答案:
使用 resourceNames 字段:

1
2
3
4
5
6
7
8
9
10
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: config-reader
namespace: default
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["app-config", "db-config"] # 只能访问这两个
verbs: ["get", "list"]

注意事项

  • 只适用于 get、update、delete 等操作单个资源的动词
  • 不适用于 list、watch、create(无法预先知道名称)
  • 可以与通配符 * 组合使用

16. 如何防止权限提升(Privilege Escalation)?

参考答案:

1. Kubernetes 内置保护

  • 用户不能创建/更新比自己权限更高的 Role/RoleBinding
  • authorization.go 中的 allowPrivilegeEscalation 检查

2. 最佳实践

1
2
3
4
5
6
7
8
9
10
# 限制谁可以创建 RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: rolebinding-creator
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["rolebindings", "clusterrolebindings"]
verbs: ["create", "update", "delete"]
# 不能绑定到权限比自己高的 ClusterRole

3. 审计和监控

1
2
# 监控 RBAC 变更
kubectl audit --filter "rbac.authorization.k8s.io"

4. 最小权限原则

  • 使用 view、edit 等内置角色
  • 避免使用 cluster-admin
  • 定期审查权限