TT Lab
开始
学习 学习路径 课程

CKA — Kubernetes 管理员

认证和授权是两层

在 TT Lab 中继续学习

一句话总结

进入 apiserver 的请求依次经过认证(你是谁)→ 授权(这个人能否这样做)→ 准入(内容是否符合规则)。RBAC 只是第二层,第一层属于证书与 token。混淆两者会让诊断纠缠不清。

为什么需要它

Kubernetes 没有 user 对象,也没有 kubectl get users,因为 apiserver 不是身份签发者,而是验证者。身份来自外部。

所以“请删除那个用户”并不是一个成立的请求。能做的只有吊销证书或删除 binding。

授权侧只有四种对象。

namespace scope cluster scope
定义权限 Role ClusterRole
授予权限 RoleBinding ClusterRoleBinding

唯一容易混淆的组合是:允许 RoleBinding 引用 ClusterRole,此时 ClusterRole 的规则只在该 RoleBinding 所在 namespace 内生效。这是按 namespace 复用 view、edit 等内置 ClusterRole 的标准方法。反之,使用 ClusterRoleBinding 会扩散到整个 cluster,试图守住 namespace 边界时经常在此出错。

RBAC 只会累加,没有 deny 规则。任一 binding 一旦允许,结果就是允许。因此追查“这个账号为什么能做这件事”时,必须检查全部 binding,而 kubectl auth can-i --as= 是捷径。它只是创建 SubjectAccessReview 向 apiserver 询问,并不会真的发送目标请求,所以可以无副作用地安全确认。

它如何运作

Aggregated ClusterRole 是不直接写规则的 ClusterRole。在 aggregationRule 中写 label selector 后,控制器会寻找带该 label 的其他 ClusterRole,并填充 rules。通过 CRD 添加新资源时,只需一个 label 就能纳入现有 view/edit role。手动在其中写 rules 会被控制器覆盖。

automountServiceAccountToken 决定是否向 Pod 注入 API token,默认会注入。这样即使完全不使用 API 的 nginx Pod 也会得到 token,container 被攻破后,该 token 就是 cluster 访问权。在 ServiceAccount 或 Pod spec 中设为 false,kube-api-access-* projected volume 本身就不会注入。

在实际工作中会遇到的情况

案例 1——把 CA private key 暴露窗口缩短到 2 小时。家庭实验室从 3 节点扩展到 7 节点时,worker join 与 control plane join 的差异完整展示了认证结构。worker 只需要一个 token。

kubeadm token create --print-join-command

control plane 不同。新节点也必须成为签发证书的主体,因此需要 CA private key。kubeadm 不让人通过 scp 传输敏感文件,而用 kubeadm init phase upload-certs --upload-certs 把 CA key bundle 加密后上传为集群内 Secret。join command 中的 64 位 certificate-key 是解密该密文的 symmetric key。

而且这个 Secret 会在 2 小时后自动删除。即使已经加密,里面仍包含 cluster root of trust,因此设计目标是最小化暴露窗口。过期后重新执行 upload-certs 即可,不影响现有集群。认证的核心正是“让信任根暴露得多短”。

案例 2——证书 SAN 就是访问权限。同一集群即使把 control plane 扩到三台,第一台死亡后仍无人能连接,因为 apiserver 证书 SAN 中没有另外两台的 IP。RBAC 再完善,无法通过 TLS 验证就根本到不了授权层。反过来利用这一性质,把死亡节点的 IP 加到存活节点 interface 上,无需重新签发证书或修改 kubeconfig,所有 client 都会重新连接。client 验证的不是节点本身,而是连接地址是否位于 SAN 中。

案例 3——有时问题不是权限,而是配置。安装 GPU Operator 时,所有 Pod 都卡在 Init。kubectl get runtimeclass 中正常存在 nvidia,节点 containerd 配置里却完全没有 nvidia。名称存在于 Kubernetes 对象中,实体必须存在于节点,而后者缺失。对象存在与实际可用是两个不同命题。诊断授权问题也需要相同习惯:can-i 返回 yes 后,应继续按证书、网络、admission webhook 的顺序向下检查。

后续实验要做什么

创建 ServiceAccount,用 Role/RoleBinding 只授予读取权限,并用 kubectl auth can-i --as= 同时确认允许和拒绝的行为。随后通过 ClusterRole/ClusterRoleBinding 开放 cluster scope 资源,配置 Aggregated ClusterRole,最后创建一个完全不注入 token 的 Pod。