证书与证书签名请求


kubernetes 证书和 trust bundle API 可以通过为 kube-apiserver 的客户端提供编程接口,实现X.509证书的请求并获取证书颁发机构的自动化制备。

证书签名

etcd 不会保存签名请求,相应的会有以下几种状态:

  1. 已签发的请求:会在 1 个小时后自动被垃圾回收器删除
  2. 拒绝的请求:会在 1 个小时后自动被垃圾回收器删除
  3. 失败的请求:会在 1 个小时后自动被垃圾回收器删除
  4. 所有的请求:已签发证书会在失效以后自动被垃圾回收器删除

Signer

任何要在特定集群以外提供的签名者都应该提供关于签名者工作方式的信息。

  1. 信任分发:信任锚点(CA 证书或证书包)
  2. 许可的主体
  3. 许可的 x509 扩展:包括 IP subjectAltNames,DNS subjectAltNames, Email subjectAltNames, URL subjectAltNames 等
  4. 许可的/扩展的密钥用途
  5. 过期时间/证书有效期:可以由签名者确定、管理员配置,或者 CSR 请求中spec.expirationSeconds字段指定
  6. 允许/不允许 CA 位:若 CSR 包含一个签名者并不允许的 CA 证书时,相应的应对手段

内置的 Signer

  1. kubernetes.io/kube-apiserver-client 签名的证书将被 kube-apiserver 视为客户端证书,不会被 kube-controller-manager 自动批准
  2. kubernetes.io/kube-apiserver-client-kubelet 签名的证书将被 kube-apiserver 视为 kubelet 的客户端证书,可以被 kube-controller-manager 自动批准
  3. kubernetes.io/kubelet-serving 签名的证书将被视为有效的 kubelet 服务端证书,不会被 kube-controller-manager 自动批准
  4. kubernetes.io/legacy-unknown 不保证信任,kubernetes 的第三方组件发行版可能会使用它签署的客户端证书,稳定版的 CSR API(certificates.k8s.io/v1以及之后的版本)不允许将signerName设置为kubernetes.io/legacy-unknown,不会被 kube-controller-manager 自动批准

kube-controlelr-manager 为每个内置签名者实现了 control-plane 签名,所有这些故障仅在 kube-controller-manager 日志中报告。

除了上述信任的签名者前发的证书之外,kubernetes 集群不保证其他任何信任关系的建立。虽然某些发行版使用kubernetes.io/legacy-unknown作为客户端证书供 kube-apiserver 使用,但者并不是一个标准的做法(即某些发行版可能会有特定的配置,这跟 kubernetes 官方无关)。这些用法与 ServiceAccount 令牌密钥的.data[ca.crt]没有任何关。使用 CA bundles 的做法只能确保验证到 kube-apiserver 的连接,而且仅限于使用默认服务kubernetes.default.svc(即这些证书斤用于验证与默认服务 kube-apiserver 的连接,而不适用于其他服务或场景)。

自定义签名者

也可以使用自定义签名集成外部的第三方组件,如issuer.open-fictional.example/service-mesh

签名

Control Plane 签名者

Control plane 实现了内置的所有签名者,作为 kube-controller-manager 的一部分。

NOTES: v1.18 之前,kube-controller-manager 签名所有标记为 approved 的 CSR。 spec.expirationSeconds是在 v1.22 中加入的,v1.22 的版本会忽略该字段。

API-based 签名者

签名完成之后,会将已签发的一个或多个 base64 编码的 pem 证书包含在 CRS 的status.certificate字段中,所有的 pem 块必须要有"CERTIFICATE"标签,编码数据必须符合RFC5280 第 4 节

ClusterTrustBundles

可是使用 2 种模式:signer-linked,signer-unlinked

如何签发证书

创建私钥

# 生成证书私钥
openssl genrsa -out myuser.key 2048
# 用私钥生成一个证书请求文件
openssl req -new -key myuser.key -out myuser.csr -subj "/CN=myuser"

创建 CSR

cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: myuser
spec:
  request: <cat myuser.csr | base64 | tr -d "\n">
  signerName: kubernetes.io/kube-apiserver-client
  expirationSeconds: 86400  # 一天,单位是秒
  usages:
  - client auth # 必须是如此
EOF

批准 CSR

# kubectl get csr
kubectl certificate approve myuser

获取证书

# kubectl get csr/myuser -o yaml
kubectl get csr myuser -o jsonpath='{.status.certificate}' | base64 -d > myuser.crt

创建角色和绑定角色

kubectl create role developer --verb=create --verb=get --resource=pods
kubectl create rolebinding developer-binding-myuser --role=developer --user=myuser

添加到 kubeconfig

kubectl config set-credentials myuser --client-key=myuser.key --client-certificate=myuser.crt --embed-certs=true
kubectl config set-context myuser --cluster=kubernetes --user=myuser

至此用户可以使用该 kubeconfig 完成对集群的访问了