bigywater.tech
Kubernetes · 27

CSR 与证书:kubectl 用户证书怎么签发

“给新同事发一个 kubectl 账号”在 Kubernetes 里是怎么做的?集群里没有 User 对象,身份就写在证书里。这篇把用户证书从私钥、CSR、批准、签发到写进 kubeconfig、被 RBAC 拦下再放行的全过程真跑了一遍,并看了几种得不到证书的情形。

3900 秒
请求 expirationSeconds=3600 的证书实际的 notAfter - notBefore(notBefore 回拨了 300 秒)
jane + devs
用这张证书的 kubeconfig 执行 kubectl auth whoami 得到的用户与组(来自 CN 与 O)
SignerValidationFailure
kube-apiserver-client 的 CSR 申请了 server auth 用途、被批准后出现的 Failed 条件

提交 CSR

实测 · 本机执行输出
  kubectl create csr jane(openssl 生成的 RSA 2048 密钥,Subject CN=jane,O=devs;signerName=kubernetes.io/kube-apiserver-client,expirationSeconds=3600,usages=[client auth]):certificatesigningrequest.certificates.k8s.io/jane created
  status:conditions=None;certificate=(空);spec.username=kubernetes-admin;spec.groups=['kubeadm:cluster-admins', 'system:authenticated']
  kubectl get csr:NAME   AGE   SIGNERNAME                            REQUESTOR          REQUESTEDDURATION   CONDITION | jane   0s    kubernetes.io/kube-apiserver-client   kubernetes-admin   60m                 Pending
  等 3 秒之后 certificate 仍然是 (空)——没有批准就没有人签发

私钥留在用户手里,只有 CSR 交给集群:CertificateSigningRequest 里是 base64 的 CSR、signerName: kubernetes.io/kube-apiserver-client、usages: [client auth] 和 expirationSeconds: 3600。创建后它只是个对象,status 里什么都没有,kubectl get csr 显示 Pending;spec.username 记着是谁提交的。没人批准,等多久都没有证书。

批准与签发

实测 · 本机执行输出
  kubectl certificate approve jane:certificatesigningrequest.certificates.k8s.io/jane approved
  0.0 秒后 status.certificate 被填上;conditions=[('Approved', 'KubectlApprove')]
    subject=O=devs, CN=jane
    issuer=CN=kubernetes
    notBefore=Oct 10 09:15:20 2026 GMT
    notAfter=Oct 10 10:20:20 2026 GMT
    X509v3 Extended Key Usage:
    TLS Web Client Authentication
  notAfter - notBefore = 3900 秒(请求的 expirationSeconds=3600);notBefore 比签发时刻早 300 秒左右

kubectl certificate approve jane 之后,controller-manager 里的签名者用集群 CA 签出证书,几乎立刻出现在 status.certificate。证书里 subject=O=devs, CN=jane、issuer=CN=kubernetes、只有 TLS Web Client Authentication 用途。有效期是 3900 秒,不是请求的 3600:notBefore 比签发时刻早了约 300 秒,防止时钟不同步导致刚签的证书“还没生效”。

用证书当用户

实测 · 本机执行输出
  用 jane 的 kubeconfig:kubectl auth whoami → jane|["devs","system:authenticated"]
  kubectl get pods -n k21:Error from server (Forbidden): pods is forbidden: User "jane" cannot list resource "pods" in API group "" in the namespace "k21"
  给组 devs 绑定 view(RoleBinding 在 k21 命名空间)之后:No resources found in k21 namespace.
  同一个用户看 default 命名空间:Error from server (Forbidden): pods is forbidden: User "jane" cannot list resource "pods" in API group "" in the namespace "default"
  auth can-i delete pods -n k21:no
  集群里有 User 对象吗?kubectl get users:error: the server doesn't have a resource type "users"——用户只存在于证书里

把证书和私钥写进独立的 kubeconfig:whoami 得到 jane,组是 devs(证书的 O)和 system:authenticated。证书只证明身份,权限一点没有:get pods 是 Forbidden。给组 devs 在 k21 命名空间绑定 view 之后才能列出 Pod,到 default 命名空间仍然被拒,can-i delete pods 是 no。kubectl get users 报 the server doesn't have a resource type "users"——集群里没有 User 对象,所以要撤销一个用户只能等证书过期或撤销它的权限。

得不到证书的几种情形

实测 · 本机执行输出
  kubectl certificate deny bob:certificatesigningrequest.certificates.k8s.io/bob denied;conditions=[('Denied', 'KubectlDeny')];certificate=(空)
  signerName=example.com/my-signer(没有任何组件负责签)被 approve 之后 5 秒:conditions=['Approved'];certificate=(空)
  kubernetes.io/kube-apiserver-client 却申请 usages=[server auth]:创建时退出码 0;certificatesigningrequest.certificates.k8s.io/dave created
  approve 之后 4 秒:conditions=[('Approved', 'KubectlApprove', 'This CSR was approved by kubectl certificate approve.'), ('Failed', 'SignerValidationFailure', 'invalid usage for client certificate: server auth')];certificate=(空)
  kubectl get csr jane bob carol dave:NAME    AGE   SIGNERNAME                            REQUESTOR          REQUESTEDDURATION   CONDITION | jane    13s   kubernetes.io/kube-apiserver-client   kubernetes-admin   60m                 Approved,Issued | bob     10s   kubernetes.io/kube-apiserver-client   kubernetes-admin   60m                 Denied | carol   9s    example.com/my-signer                 kubernetes-admin   60m                 Approved | dave    4s    kubernetes.io/kube-apiserver-client   kubernetes-admin   60m                 Approved,Failed

deny 的 CSR 变成 Denied,没有证书;signerName 是 example.com/my-signer 的 CSR 即使被 approve 也没有人签(内置签名者只处理 kubernetes.io/*);kube-apiserver-client 却申请 server auth 用途,创建时能通过,approve 之后才出现 Failed: SignerValidationFailure — invalid usage for client certificate: server auth。排查“批准了却没有证书”先看 conditions。

分步演示

证书签发
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0,kubeadm 默认的签名设置);密钥与 CSR 由宿主机 openssl 生成,证书内容用 openssl x509 解析;用户的 kubeconfig 是单独写在实验目录里的文件,不碰 ~/.kube;RBAC 绑定的是内置 ClusterRole view(RoleBinding 在 k21 命名空间);实验后删除了所有 CSR、RoleBinding 和临时文件;每种情形各一次
    • 没有验证:CSR 的自动清理(已签发 1 小时后、Pending 24 小时后被清理);--cluster-signing-duration 对有效期上限的约束(只验证了请求 3600 秒的情形);kubernetes.io/kubelet-serving 与 kube-apiserver-client-kubelet 的自动批准;证书轮换与吊销(Kubernetes 没有 CRL 机制);ECDSA 密钥;O=system:masters 之类的高权限组被批准的后果
    京ICP备2026067502号-1京公网安备11010502063487号