简介
Kubernetes 身份认证用于确认请求方的身份;授权则决定该身份可以执行哪些操作。RBAC 将权限表示为针对 API 资源的操作动词,并将这些权限绑定到用户、用户组或 ServiceAccount。
你将创建一个限定在命名空间内的只读身份,将其与相应权限关联起来,然后通过身份模拟验证允许和拒绝的访问边界。
理解 RBAC 时,可以将其归纳为三个问题:谁?(ServiceAccount)、可以做什么?(Role)以及谁获得这些权限?(RoleBinding)。只创建其中一个或两个对象,并不能完成完整的授权链路。
创建 ServiceAccount 身份
在本步骤中,为应用组件创建一个限定在命名空间内的 ServiceAccount。
ServiceAccount 是 Kubernetes API 中供工作负载和自动化任务使用的身份。它并不是容器内的 Linux 用户。为本示例创建独立身份,可以避免继承命名空间中的 default ServiceAccount。
cd /home/labex/project/rbac-access
kubectl create serviceaccount inventory-reader -n practice-rbac
kubectl get serviceaccount inventory-reader -n practice-rbac -o yaml
它的完整身份名称是 system:serviceaccount:practice-rbac:inventory-reader。单独创建身份不会赋予任何应用权限。
在 YAML 输出中,元数据会确认命名空间和名称。不要期待系统自动生成一个长期有效的令牌 Secret;现代 Kubernetes 项目会在 Pod 需要时,将短期令牌挂载到 Pod 中。
返回的对象包含专用名称和命名空间,但没有自动生成的令牌 Secret:
kind: ServiceAccount
metadata:
name: inventory-reader
namespace: practice-rbac
定义命名空间级权限
在本步骤中,创建一个 Role,使其仅允许在 practice-rbac 中读取 Pod 和 ConfigMap。
每条规则由 API 组、资源和操作动词组成。对于 Pod 和 ConfigMap 等核心资源,apiGroups: [""] 使用空字符串表示核心 API 组。get、list 和 watch 分别表示读取单个对象、读取对象集合以及监听资源变化。
cd /home/labex/project/rbac-access
cat <<'EOF' > inventory-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata: {name: inventory-reader, namespace: practice-rbac}
rules:
- apiGroups: [""]
resources: [pods, configmaps]
verbs: [get, list, watch]
EOF
应用并查看 Role。与原始 YAML 相比,describe 会以更便于审查的表格形式展示策略规则:
kubectl apply -f inventory-role.yaml
kubectl describe role inventory-reader -n practice-rbac
空 API 组用于选择核心资源。Role 永远不会授予命名空间之外的访问权限。
同时注意其中缺少的权限:没有 create、update、patch 或 delete。最小权限原则不仅体现在授予了哪些权限,也体现在明确省略了哪些权限。
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
configmaps [] [] [get list watch]
pods [] [] [get list watch]
该表将 YAML 中合并定义的规则展开为每个资源一行。两行都具有相同的三个只读操作动词。
将 Role 绑定到身份
在本步骤中,使用 RoleBinding 将 Role 关联到 ServiceAccount。
由于两个对象都已经存在,因此命令式操作命令非常简洁。--role 指定权限来源,--serviceaccount 使用 namespace:name 格式标识主体。
cd /home/labex/project/rbac-access
kubectl create rolebinding inventory-reader -n practice-rbac --role=inventory-reader --serviceaccount=practice-rbac:inventory-reader
kubectl get rolebinding inventory-reader -n practice-rbac -o yaml
roleRef 指定权限,subjects 指定获得这些权限的身份。在这里,两者都限定在命名空间范围内。
即使 Role 和 ServiceAccount 使用相同名称,在创建此绑定之前,它们仍然互不相关。名称只是方便人类识别;RoleBinding 才是真正建立授权关系的对象。
在 YAML 中,沿着 roleRef.name: inventory-reader 追踪这条关联:主体的类型是 ServiceAccount,名称是 inventory-reader,命名空间是 practice-rbac。
测试允许和拒绝的操作
在本步骤中,使用带有 --as 参数的 kubectl auth can-i 来模拟该 ServiceAccount。
授权测试既需要验证允许的操作,也需要验证拒绝的操作。返回 yes 说明所需工作可以执行;返回 no 则说明系统没有意外授予破坏性操作或跨命名空间访问权限。
cd /home/labex/project/rbac-access
IDENTITY=system:serviceaccount:practice-rbac:inventory-reader
kubectl auth can-i list pods -n practice-rbac --as="$IDENTITY"
kubectl auth can-i get configmaps -n practice-rbac --as="$IDENTITY"
kubectl auth can-i delete pods -n practice-rbac --as="$IDENTITY" || true
kubectl auth can-i list pods -n default --as="$IDENTITY" || true
前两个结果应为 yes;删除 Pod 和跨命名空间列出 Pod 的结果应为 no。身份模拟可以在不暴露或创建令牌的情况下测试授权。
kubectl auth can-i 在返回 no 的同时,也会返回非零的 Shell 状态码。末尾的两个 || true 用于让这两个预期的拒绝测试继续执行;它们不会改变授权决策。
yes
yes
no
no
将这些结果理解为:前两个表示所需的能力,后两个表示受到保护的边界。只有 yes 结果的测试,无法证明系统遵循了最小权限原则。
当前实验用户被允许模拟此 ServiceAccount,以便进行测试。--as 只会改变 API 服务器针对当前命令评估的身份;它不会改变你的 Shell 用户,也不会永久切换 kubectl 凭据。
总结
你创建了一个 ServiceAccount,使用 Role 表达了命名空间级的只读权限,通过 RoleBinding 分配这些权限,并使用身份模拟验证了允许和拒绝的操作。


