必须用自建ca而非默认证书,因其存在三大硬伤:ca私钥暴露、无分级信任域、证书1年过期且无自动轮换;自建ca通过cfssl实现可控的证书生命周期、权限隔离与用途约束,是生产集群强制准入门槛。

自建证书链不是“可选优化”,而是生产集群的准入门槛。用 kubeadm 默认生成的证书或 RKE 自签名 CA,等同于把集群大门钥匙埋在门口花盆底下。
为什么必须用自建 CA 而非默认证书
默认证书(如 kubeadm init 生成的)存在三个硬伤:
- CA 证书和私钥直接暴露在
/etc/kubernetes/pki/ca.crt和/etc/kubernetes/pki/ca.key—— 一旦节点失陷,攻击者可签发任意组件证书 - 所有证书共用同一 CA,缺乏分级控制能力;无法为 etcd、API Server、kubelet 分配不同信任域
- 证书有效期普遍为 1 年,且无自动轮换机制,到期后集群会静默中断(
Unable to connect to the server: x509: certificate has expired or is not yet valid)
自建 CA 的核心价值是:把证书生命周期、签发权限、用途约束全部收归可控体系。推荐用 cfssl 搭建,它比 openssl 更适合多角色、多用途的 Kubernetes PKI 场景。
cfssl 自建 CA 的最小可行配置
只需 3 个文件就能跑通整个链路:
ca-config.json 定义使用策略:
{
"signing": {
"default": {"expiry": "8760h"},
"profiles": {
"kubernetes": {
"usages": ["signing", "key encipherment", "server auth", "client auth"],
"expiry": "8760h"
}
}
}
}
ca-csr.json 定义 CA 根证书身份:
针对 Kubernetes 仪表板和 Web UI 的浏览器自动化。适用于与 Kubernetes Dashboard、Grafana、ArgoCD UI 或其他 Web 界面交互。需要设置 MCP_BROWSER_ENABLED=true。
{
"CN": "MyK8sRootCA",
"key": {"algo": "rsa", "size": 2048},
"names": [{"C": "CN", "ST": "Beijing", "L": "Haidian", "O": "k8s", "OU": "CA"}]
}
执行生成命令:cfssl gencert -initca ca-csr.json | cfssljson -bare ca,得到 ca.pem 和 ca-key.pem。
注意:这两个文件必须离线保管,绝不能放入任何集群节点或 Git 仓库。
为各组件签发证书时的关键约束
每个组件证书的 CN 和 O 必须严格匹配 Kubernetes 内置授权器的要求,否则会触发拒绝访问:
-
apiserver:CN 可任意,但必须包含所有可能访问它的 IP/DNS —— 包括 VIP、LB 地址、所有 control-plane 节点 IP,漏一个就导致connection refused -
kubelet:CN 必须为system:node:<nodename></nodename>,O 必须为system:nodes,否则 NodeAuthorizer 拒绝授权 -
etcd:CSR 中需显式设置"usages": ["server auth", "client auth"],且服务端证书必须含 SAN(Subject Alternative Name)字段,否则etcdctl连接失败 -
admin用户证书:CN 设为admin,O 设为system:masters,这是唯一能绕过 RBAC 的群组
错误示例:openssl req -new -key admin.key -subj "/CN=admin" 缺少 O 字段 → 登录后提示 error: You must be logged in to the server (Unauthorized)。
证书分发与 APIServer 启动参数绑定
证书签发完成后,不能直接丢进 /etc/kubernetes/pki/ 就完事。APIServer 启动参数必须精确指向新证书路径,并禁用旧证书残留:
- 确认
--tls-cert-file指向新签发的apiserver.pem(不是apiserver.crt),--tls-private-key-file指向对应私钥 - 必须显式指定
--client-ca-file=ca.pem,否则客户端证书认证失效 - 若启用 OIDC 或 webhook 认证,还需同步更新
--oidc-ca-file或--authentication-token-webhook-config-file中引用的 CA 路径 - 检查 kubelet 配置中
--bootstrap-kubeconfig是否仍指向旧 admin kubeconfig —— 若未清理,它会持续用高权证书申请 CSR,绕过 NodeRestriction
最容易被忽略的一点:所有节点上的 kubeconfig 文件(尤其是 /etc/kubernetes/kubelet.conf)必须用新 CA 签发的 client 证书重建,否则重启 kubelet 会报 x509: certificate signed by unknown authority。










