这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

TLS

了解如何使用传输层安全性( TLS )保护集群中的流量。

1 - 使用 CertificateSigningRequest 为 Kubernetes API 客户端颁发证书

Kubernetes 允许你使用公钥基础设施 (PKI) 对你的集群进行身份认证,这类似于对客户端进行身份认证。

为了能够对普通用户进行身份认证并调用 API,需要执行几个步骤。首先,此用户必须拥有由你的 Kubernetes 集群所信任的权威机构颁发的 X.509 证书。之后客户端必须向 Kubernetes API 提交该证书。

在这个过程中,你需要使用 CertificateSigningRequest,并且你或其他主体必须批准此请求。

你将创建私钥,然后获取颁发的证书,最后为客户端配置该私钥。

准备开始

  • 你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:

  • 你需要 kubectlopensslbase64 等工具。

此页面假设你使用的是 Kubernetes 基于角色的访问控制 (RBAC)。 如果你在鉴权方面有替代的或额外的安全机制,也需要将其考虑在内。

创建私钥

在这一步中,你将创建一个私钥。你将此文件作为秘密保管起来,因为任何拥有该私钥的人都可以伪装成对应的用户。

# 创建一个私钥
openssl genrsa -out myuser.key 3072

创建 X.509 证书签名请求

说明:

这与类似名称的 CertificateSigningRequest API 不同; 你在此处生成的文件将被放入 CertificateSigningRequest 对象中。

设置 CSR 的 CN 和 O 属性非常重要。CN 是用户的名称,O 是此用户所属的群组。 你可以参阅 RBAC 了解标准的群组。

# 将通用名称 "myuser" 更改为你要使用的实际用户名
openssl req -new -key myuser.key -out myuser.csr -subj "/CN=myuser"

创建 Kubernetes CertificateSigningRequest

使用以下命令对 CSR 文档进行编码:

cat myuser.csr | base64 | tr -d "\n"

创建 CertificateSigningRequest 并通过 kubectl 将其提交到 Kubernetes 集群。以下是你可以用于生成 CertificateSigningRequest 的 Shell 片段。

cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: myuser # 示例
spec:
  # 这是已编码的 CSR。将此更改为 myuser.csr 的经 base64 编码的内容
  request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1ZqQ0NBVDRDQVFBd0VURVBNQTBHQTFVRUF3d0dZVzVuWld4aE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRgpBQU9DQVE4QU1JSUJDZ0tDQVFFQTByczhJTHRHdTYxakx2dHhWTTJSVlRWMDNHWlJTWWw0dWluVWo4RElaWjBOCnR2MUZtRVFSd3VoaUZsOFEzcWl0Qm0wMUFSMkNJVXBGd2ZzSjZ4MXF3ckJzVkhZbGlBNVhwRVpZM3ExcGswSDQKM3Z3aGJlK1o2MVNrVHF5SVBYUUwrTWM5T1Nsbm0xb0R2N0NtSkZNMUlMRVI3QTVGZnZKOEdFRjJ6dHBoaUlFMwpub1dtdHNZb3JuT2wzc2lHQ2ZGZzR4Zmd4eW8ybmlneFNVekl1bXNnVm9PM2ttT0x1RVF6cXpkakJ3TFJXbWlECklmMXBMWnoyalVnald4UkhCM1gyWnVVV1d1T09PZnpXM01LaE8ybHEvZi9DdS8wYk83c0x0MCt3U2ZMSU91TFcKcW90blZtRmxMMytqTy82WDNDKzBERHk5aUtwbXJjVDBnWGZLemE1dHJRSURBUUFCb0FBd0RRWUpLb1pJaHZjTgpBUUVMQlFBRGdnRUJBR05WdmVIOGR4ZzNvK21VeVRkbmFjVmQ1N24zSkExdnZEU1JWREkyQTZ1eXN3ZFp1L1BVCkkwZXpZWFV0RVNnSk1IRmQycVVNMjNuNVJsSXJ3R0xuUXFISUh5VStWWHhsdnZsRnpNOVpEWllSTmU3QlJvYXgKQVlEdUI5STZXT3FYbkFvczFqRmxNUG5NbFpqdU5kSGxpT1BjTU1oNndLaTZzZFhpVStHYTJ2RUVLY01jSVUyRgpvU2djUWdMYTk0aEpacGk3ZnNMdm1OQUxoT045UHdNMGM1dVJVejV4T0dGMUtCbWRSeEgvbUNOS2JKYjFRQm1HCkkwYitEUEdaTktXTU0xMzhIQXdoV0tkNjVoVHdYOWl4V3ZHMkh4TG1WQzg0L1BHT0tWQW9FNkpsYWFHdTlQVmkKdjlOSjVaZlZrcXdCd0hKbzZXdk9xVlA3SVFjZmg3d0drWm89Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=
  signerName: kubernetes.io/kube-apiserver-client
  expirationSeconds: 86400  # 一天
  usages:
  - client auth
EOF

一些注意点:

  • usages 必须是 client auth
  • expirationSeconds 可以设置得更长(例如 864000 表示十天)或更短(例如 3600 表示一小时)。 你所请求的时长不能短于 10 分钟。
  • request 值是 CSR 文件内容的 base64 编码值。

批准 CertificateSigningRequest

使用 kubectl 找到你创建的 CSR,并手动批准它。

获取 CSR 列表:

kubectl get csr

批准 CSR:

kubectl certificate approve myuser

获取证书

从 CSR 中检索证书,以检查其是否正常。

kubectl get csr/myuser -o yaml

证书值以 Base64 编码格式显示在 .status.certificate 下。

从 CertificateSigningRequest 导出已颁发的证书。

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

将证书配置到 kubeconfig 中

下一步是将此用户添加到 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

对其执行测试:

kubectl --context myuser auth whoami

你应该看到确认你是 “myuser” 的输出。

创建 Role 和 RoleBinding

说明:

如果你不使用 Kubernetes RBAC,请跳过这一步,并对集群实际使用的鉴权机制进行适当更改。

创建证书之后,就可以为此用户定义 Role 和 RoleBinding,以访问 Kubernetes 集群资源。

这是为新用户创建 Role 的示例命令:

kubectl create role developer --verb=create --verb=get --verb=list --verb=update --verb=delete --resource=pods

这是为新用户创建 RoleBinding 的示例命令:

kubectl create rolebinding developer-binding-myuser --role=developer --user=myuser

接下来

2 - 管理集群中的 TLS 认证

Kubernetes 提供 certificates.k8s.io API,可让你配置由你控制的证书颁发机构(CA) 签名的 TLS 证书。 你的工作负载可以使用这些 CA 和证书来建立信任。

certificates.k8s.io API使用的协议类似于 ACME 草案

说明:

使用 certificates.k8s.io API 创建的证书由指定 CA 颁发。 将集群配置为使用集群根目录 CA 可以达到这个目的,但是你永远不要依赖这一假定。 不要以为这些证书将针对群根目录 CA 进行验证。

准备开始

你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:

你需要 cfssl 工具。 你可以从 https://github.com/cloudflare/cfssl/releases 下载 cfssl

本文中某些步骤使用 jq 工具。如果你没有 jq,你可以通过操作系统的软件源安装, 或者从 https://jqlang.github.io/jq/ 获取。

集群中的 TLS 信任

信任 Pod 中运行的应用程序所提供的自定义 CA 通常需要一些额外的应用程序配置。 你需要将 CA 证书包添加到 TLS 客户端或服务器信任的 CA 证书列表中。 例如,你可以使用 Golang TLS 配置通过解析证书链并将解析的证书添加到 tls.Config 结构中的 RootCAs 字段中。

说明:

即使自定义 CA 证书可能包含在文件系统中(在 ConfigMap kube-root-ca.crt 中), 除了验证内部 Kubernetes 端点之外,你不应将该证书颁发机构用于任何目的。 内部 Kubernetes 端点的一个示例是默认命名空间中名为 kubernetes 的服务。

如果你想为你的工作负载使用自定义证书颁发机构,你应该单独生成该 CA, 并使用你的 Pod 有读权限的 ConfigMap 分发该 CA 证书。

请求证书

以下部分演示如何为通过 DNS 访问的 Kubernetes 服务创建 TLS 证书。

说明:

本教程使用 CFSSL:Cloudflare's PKI 和 TLS 工具包 点击此处了解更多信息。

创建证书签名请求

通过运行以下命令生成私钥和证书签名请求(或 CSR):

cat <<EOF | cfssl genkey - | cfssljson -bare server
{
  "hosts": [
    "my-svc.my-namespace.svc.cluster.local",
    "my-pod.my-namespace.pod.cluster.local",
    "192.0.2.24",
    "10.0.34.2"
  ],
  "CN": "my-pod.my-namespace.pod.cluster.local",
  "key": {
    "algo": "ecdsa",
    "size": 256
  }
}
EOF

其中 192.0.2.24 是服务的集群 IP,my-svc.my-namespace.svc.cluster.local 是服务的 DNS 名称,10.0.34.2 是 Pod 的 IP,而 my-pod.my-namespace.pod.cluster.local 是 Pod 的 DNS 名称。 你能看到的输出类似于:

2022/02/01 11:45:32 [INFO] generate received request
2022/02/01 11:45:32 [INFO] received CSR
2022/02/01 11:45:32 [INFO] generating key: ecdsa-256
2022/02/01 11:45:32 [INFO] encoded CSR

此命令生成两个文件;它生成包含 PEM 编码 PKCS#10 证书请求的 server.csr, 以及 PEM 编码密钥的 server-key.pem,用于待生成的证书。

创建证书签名请求(CSR)对象发送到 Kubernetes API

你可以使用以下命令创建 CSR 清单(YAML 格式),并发送到 API 服务器:

cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: my-svc.my-namespace
spec:
  request: $(cat server.csr | base64 | tr -d '\n')
  signerName: example.com/serving
  usages:
  - digital signature
  - key encipherment
  - server auth
EOF

请注意,在步骤 1 中创建的 server.csr 文件是 base64 编码并存储在 .spec.request 字段中的。你还要求提供 “digital signature(数字签名)”, “密钥加密(key encipherment)” 和 “服务器身份验证(server auth)” 密钥用途, 由 example.com/serving 示例签名程序签名的证书。 你也可以要求使用特定的 signerName。更多信息可参阅 支持的签署者名称

在 API server 中可以看到这些 CSR 处于 Pending 状态。执行下面的命令你将可以看到:

kubectl describe csr my-svc.my-namespace
Name:                   my-svc.my-namespace
Labels:                 <none>
Annotations:            <none>
CreationTimestamp:      Tue, 01 Feb 2022 11:49:15 -0500
Requesting User:        yourname@example.com
Signer:                 example.com/serving
Status:                 Pending
Subject:
        Common Name:    my-pod.my-namespace.pod.cluster.local
        Serial Number:
Subject Alternative Names:
        DNS Names:      my-pod.my-namespace.pod.cluster.local
                        my-svc.my-namespace.svc.cluster.local
        IP Addresses:   192.0.2.24
                        10.0.34.2
Events: <none>

批准证书签名请求(CSR)

证书签名请求 的批准或者是通过自动批准过程完成的,或由集群管理员一次性完成。 如果你被授权批准证书请求,你可以使用 kubectl 来手动完成此操作;例如:

kubectl certificate approve my-svc.my-namespace
certificatesigningrequest.certificates.k8s.io/my-svc.my-namespace approved

你现在应该能看到如下输出:

kubectl get csr
NAME                  AGE   SIGNERNAME            REQUESTOR              REQUESTEDDURATION   CONDITION
my-svc.my-namespace   10m   example.com/serving   yourname@example.com   <none>              Approved

这意味着证书请求已被批准,并正在等待请求的签名者对其签名。

签名证书签名请求(CSR)

接下来,你将扮演证书签署者的角色,颁发证书并将其上传到 API 服务器。

签名者通常会使用其 signerName 查看对象的 CertificateSigningRequest API, 检查它们是否已被批准,为这些请求签署证书,并使用已颁发的证书更新 API 对象状态。

创建证书颁发机构

你需要授权在新证书上提供数字签名。

首先,通过运行以下命令创建签名证书:

cat <<EOF | cfssl gencert -initca - | cfssljson -bare ca
{
  "CN": "My Example Signer",
  "key": {
    "algo": "rsa",
    "size": 2048
  }
}
EOF

你应该看到类似于以下的输出:

2022/02/01 11:50:39 [INFO] generating a new CA key and certificate from CSR
2022/02/01 11:50:39 [INFO] generate received request
2022/02/01 11:50:39 [INFO] received CSR
2022/02/01 11:50:39 [INFO] generating key: rsa-2048
2022/02/01 11:50:39 [INFO] encoded CSR
2022/02/01 11:50:39 [INFO] signed certificate with serial number 263983151013686720899716354349605500797834580472

这会产生一个证书颁发机构密钥文件(ca-key.pem)和证书(ca.pem)。

颁发证书

{
    "signing": {
        "default": {
            "usages": [
                "digital signature",
                "key encipherment",
                "server auth"
            ],
            "expiry": "876000h",
            "ca_constraint": {
                "is_ca": false
            }
        }
    }
}

使用 server-signing-config.json 签名配置、证书颁发机构密钥文件和证书来签署证书请求:

kubectl get csr my-svc.my-namespace -o jsonpath='{.spec.request}' | \
  base64 --decode | \
  cfssl sign -ca ca.pem -ca-key ca-key.pem -config server-signing-config.json - | \
  cfssljson -bare ca-signed-server

你应该看到类似于以下的输出:

2022/02/01 11:52:26 [INFO] signed certificate with serial number 576048928624926584381415936700914530534472870337

这会生成一个签名的服务证书文件,ca-signed-server.pem

上传签名证书

最后,在 API 对象的状态中填充签名证书:

kubectl get csr my-svc.my-namespace -o json | \
  jq '.status.certificate = "'$(base64 ca-signed-server.pem | tr -d '\n')'"' | \
  kubectl replace --raw /apis/certificates.k8s.io/v1/certificatesigningrequests/my-svc.my-namespace/status -f -

说明:

这使用命令行工具 jq.status.certificate 字段中填充 base64 编码的内容。 如果你没有 jq 工具,你还可以将 JSON 输出保存到文件中,手动填充此字段,然后上传结果文件。

批准 CSR 并上传签名证书后,运行:

kubectl get csr

输入类似于:

NAME                  AGE   SIGNERNAME            REQUESTOR              REQUESTEDDURATION   CONDITION
my-svc.my-namespace   20m   example.com/serving   yourname@example.com   <none>              Approved,Issued

下载证书并使用它

现在,作为请求用户,你可以通过运行以下命令下载颁发的证书并将其保存到 server.crt 文件中:

CSR 被签署并获得批准后,你应该看到以下内容:

kubectl get csr my-svc.my-namespace -o jsonpath='{.status.certificate}' \
    | base64 --decode > server.crt

现在你可以将 server.crtserver-key.pem 填充到 Secret 中, 稍后你可以将其挂载到 Pod 中(例如,用于提供 HTTPS 的网络服务器)。

kubectl create secret tls server --cert server.crt --key server-key.pem
secret/server created

最后,你可以将 ca.pem 填充到 ConfigMap 并将其用作信任根来验证服务证书:

kubectl create configmap example-serving-ca --from-file ca.crt=ca.pem
configmap/example-serving-ca created

批准证书签名请求(CSR)

Kubernetes 管理员(具有适当权限)可以使用 kubectl certificate approvekubectl certificate deny 命令手动批准(或拒绝)证书签名请求(CSR)。 但是,如果你打算大量使用此 API,则可以考虑编写自动化的证书控制器。

注意:

批准证书 CSR 的能力决定了在你的环境中谁信任谁。 不应广泛或轻率地授予批准 CSR 的能力。

在授予 approve 权限之前,你应该确保自己充分了解批准人的验证要求颁发特定证书的后果。

无论上述机器或人使用 kubectl,“批准者”的作用是验证 CSR 满足如下两个要求:

  1. CSR 的 subject 控制用于签署 CSR 的私钥。这解决了伪装成授权主体的第三方的威胁。 在上述示例中,此步骤将验证该 Pod 控制了用于生成 CSR 的私钥。
  2. CSR 的 subject 被授权在请求的上下文中执行。 这点用于处理不期望的主体被加入集群的威胁。 在上述示例中,此步骤将是验证该 Pod 是否被允许加入到所请求的服务中。

当且仅当满足这两个要求时,审批者应该批准 CSR,否则拒绝 CSR。

有关证书批准和访问控制的更多信息, 请阅读证书签名请求参考页。

给集群管理员的一个建议

本页面假设已经为 certificates API 配置了签名者。 Kubernetes 控制器管理器提供了一个签名者的默认实现。要启用它,请为控制器管理器设置 --cluster-signing-cert-file--cluster-signing-key-file 参数, 使之取值为你的证书机构的密钥对的路径。

3 - 手动轮换 CA 证书

本页展示如何手动轮换证书机构(CA)证书。

准备开始

你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:

  • 要了解 Kubernetes 中用户认证的更多信息,参阅 认证
  • 要了解与 CA 证书最佳实践有关的更多信息, 参阅单根 CA

手动轮换 CA 证书

注意:

确保备份你的证书目录、配置文件以及其他必要文件。

这里的方法假定 Kubernetes 的控制面通过运行多个 API 服务器以高可用配置模式运行。 另一假定是 API 服务器可体面地终止,因而客户端可以彻底地与一个 API 服务器断开 连接并连接到另一个 API 服务器。

如果集群中只有一个 API 服务器,则在 API 服务器重启期间会经历服务中断期。

  1. 将新的 CA 证书和私钥(例如:ca.crtca.keyfront-proxy-ca.crtfront-proxy-client.key)分发到所有控制面节点,放在其 Kubernetes 证书目录下。
  1. 更新 kube-controller-manager--root-ca-file 标志,使之同时包含老的和新的 CA,之后重启 kube-controller-manager。

    自此刻起,所创建的所有ServiceAccount 都会获得同时包含老的 CA 和新的 CA 的 Secret。

    说明:

    kube-controller-manager 标志 --client-ca-file--cluster-signing-cert-file 所引用的文件不能是 CA 证书包。如果这些标志和 --root-ca-file 指向同一个 ca.crt 包文件 (包含老的和新的 CA 证书),你将会收到出错信息。 要解决这个问题,可以将新的 CA 证书复制到单独的文件中,并将 --client-ca-file--cluster-signing-cert-file 标志指向该副本。一旦 ca.crt 不再是证书包文件, 就可以恢复有问题的标志指向 ca.crt 并删除该副本。

    kubeadm 的 Issue 1350 在跟踪一个导致 kube-controller-manager 无法接收 CA 证书包的问题。

  1. 等待该控制器管理器更新服务账号 Secret 中的 ca.crt,使之同时包含老的和新的 CA 证书。

    如果在 API 服务器使用新的 CA 之前启动了新的 Pod,这些新的 Pod 也会获得此更新并且同时信任老的和新的 CA 证书。

  1. 重启所有使用集群内配置的 Pod(例如:kube-proxy、CoreDNS 等),以便这些 Pod 能够使用与 ServiceAccount 相关联的 Secret 中的、已更新的证书机构数据。

    • 确保 CoreDNS、kube-proxy 和其他使用集群内配置的 Pod 都正按预期方式工作。
  2. 将老的和新的 CA 都追加到 kube-apiserver 配置的 --client-ca-file--kubelet-certificate-authority 标志所指的文件。

  3. 将老的和新的 CA 都追加到 kube-scheduler 配置的 --client-ca-file 标志所指的文件。

  1. 通过替换 client-certificate-dataclient-key-data 中的内容,更新用户账号的证书。

    有关为独立用户账号创建证书的更多信息,可参阅 为用户帐号配置证书

    另外,还要更新 kubeconfig 文件中的 certificate-authority-data 节, 使之包含 Base64 编码的老的和新的证书机构数据。

  1. 更新 云控制器管理器(Cloud Controller Manager)--root-ca-file 标志值,使之同时包含老的和新的 CA,之后重新启动 cloud-controller-manager。

    说明:

    如果你的集群中不包含 cloud-controller-manager,你可以略过这一步。

  1. 遵循下列步骤执行滚动更新

    1. 重新启动所有其他被聚合的 API 服务器 或者 Webhook 处理程序,使之信任新的 CA 证书。

    2. 在所有节点上更新 kubelet 配置中的 clientCAFile 所指文件以及 kubelet.conf 中的 certificate-authority-data 并重启 kubelet 以同时使用老的和新的 CA 证书。

      如果你的 kubelet 并未使用客户端证书轮换,则在所有节点上更新 kubelet.confclient-certificate-dataclient-key-data 以及 kubelet 客户端证书文件(通常位于 /var/lib/kubelet/pki 目录下)

    1. 使用用新的 CA 签名的证书 (apiserver.crtapiserver-kubelet-client.crtfront-proxy-client.crt) 来重启 API 服务器。 你可以使用现有的私钥,也可以使用新的私钥。 如果你改变了私钥,则要将更新的私钥也放到 Kubernetes 证书目录下。
      由于集群中的 Pod 既信任老的 CA 也信任新的 CA,Pod 中的客户端会经历短暂的连接断开状态,
    

    之后再使用新的 CA 所签名的证书连接到新的 API 服务器。

      * 重启 kube-scheduler 以使用并信任新的
     CA 证书。
    
    • 确保控制面组件的日志中没有 TLS 相关的错误信息。

    说明:

      <!--
      To generate certificates and private keys for your cluster using the `openssl` command line tool,
      see [Certificates (`openssl`)](/docs/tasks/administer-cluster/certificates/#openssl).
      You can also use [`cfssl`](/docs/tasks/administer-cluster/certificates/#cfssl).
      -->
      要使用 `openssl` 命令行为集群生成新的证书和私钥,可参阅
      [证书(`openssl`)](/zh-cn/docs/tasks/administer-cluster/certificates/#openssl)。
      你也可以使用[`cfssl`](/zh-cn/docs/tasks/administer-cluster/certificates/#cfssl).
    
    1. 为 Daemonset 和 Deployment 添加注解,从而触发较安全的滚动更新,替换 Pod。
    for namespace in $(kubectl get namespace -o jsonpath='{.items[*].metadata.name}'); do
        for name in $(kubectl get deployments -n $namespace -o jsonpath='{.items[*].metadata.name}'); do
            kubectl patch deployment -n ${namespace} ${name} -p '{"spec":{"template":{"metadata":{"annotations":{"ca-rotation": "1"}}}}}';
        done
        for name in $(kubectl get daemonset -n $namespace -o jsonpath='{.items[*].metadata.name}'); do
            kubectl patch daemonset -n ${namespace} ${name} -p '{"spec":{"template":{"metadata":{"annotations":{"ca-rotation": "1"}}}}}';
        done
    done
    

    说明:

      <!--
      To limit the number of concurrent disruptions that your application experiences,
      see [configure pod disruption budget](/docs/tasks/run-application/configure-pdb/).
      -->
      要限制应用可能受到的并发干扰数量,
      可以参阅[配置 Pod 干扰预算](/zh-cn/docs/tasks/run-application/configure-pdb/)。
    
      取决于你在如何使用 StatefulSet,你可能需要对其执行类似的滚动替换操作。
    
  1. 如果你的集群使用启动引导令牌来添加节点,则需要更新 kube-public 名字空间下的 ConfigMap cluster-info,使之包含新的 CA 证书。

    base64_encoded_ca="$(base64 -w0 /etc/kubernetes/pki/ca.crt)"
    
    kubectl get cm/cluster-info --namespace kube-public -o yaml | \
       /bin/sed "s/\(certificate-authority-data:\).*/\1 ${base64_encoded_ca}/" | \
       kubectl apply -f -
    
  1. 验证集群的功能正常。

    1. 检查控制面组件以及 kubeletkube-proxy 的日志,确保其中没有抛出 TLS 错误, 参阅查看日志

    2. 验证被聚合的 API 服务器的日志,以及所有使用集群内配置的 Pod 的日志。

  1. 完成集群功能的检查之后:

    1. 更新所有的服务账号令牌,使之仅包含新的 CA 证书。

      • 使用集群内 kubeconfig 的 Pod 最终也需要被重启,以获得新的服务账号 Secret 数据,这样就不会有 Pod 再依赖老的集群 CA。
    2. 从 kubeconfig 文件和 --client-ca-file 以及 --root-ca-file 标志所指向的文件 中去除老的 CA 数据,之后重启控制面组件。

    3. 在每个节点上,移除 clientCAFile 标志所指向的文件,以删除老的 CA 数据,并从 kubelet kubeconfig 文件中去掉老的 CA,重启 kubelet。 你应该用滚动更新的方式来执行这一步骤的操作。

      如果你的集群允许你执行这一变更,你也可以通过替换节点而不是重新配置节点的方式来将其上线。

4 - 为 kubelet 配置证书轮换

本文展示如何在 kubelet 中启用并配置证书轮换。

特性状态: Kubernetes v1.19 [stable]

准备开始

  • 要求 Kubernetes 1.8.0 或更高的版本

概述

Kubelet 使用证书进行 Kubernetes API 的认证。 默认情况下,这些证书的签发期限为一年,所以不需要太频繁地进行更新。

Kubernetes 包含特性 kubelet 证书轮换, 在当前证书即将过期时, 将自动生成新的秘钥,并从 Kubernetes API 申请新的证书。 一旦新的证书可用,它将被用于与 Kubernetes API 间的连接认证。

启用客户端证书轮换

kubelet 进程接收 --rotate-certificates 参数,该参数决定 kubelet 在当前使用的 证书即将到期时,是否会自动申请新的证书。

kube-controller-manager 进程接收 --cluster-signing-duration 参数 (在 1.19 版本之前为 --experimental-cluster-signing-duration),用来 控制签发证书的有效期限。

理解证书轮换配置

当 kubelet 启动时,如被配置为自举(使用--bootstrap-kubeconfig 参数),kubelet 会使用其初始证书连接到 Kubernetes API ,并发送证书签名的请求。 可以通过以下方式查看证书签名请求的状态:

kubectl get csr

最初,来自节点上 kubelet 的证书签名请求处于 Pending 状态。 如果证书签名请求满足特定条件, 控制器管理器会自动批准,此时请求会处于 Approved 状态。 接下来,控制器管理器会签署证书, 证书的有效期限由 --cluster-signing-duration 参数指定,签署的证书会被附加到证书签名请求中。

Kubelet 会从 Kubernetes API 取回签署的证书,并将其写入磁盘,存储位置通过 --cert-dir 参数指定。 然后 kubelet 会使用新的证书连接到 Kubernetes API。

当签署的证书即将到期时,kubelet 会使用 Kubernetes API,自动发起新的证书签名请求。 该请求会发生在证书的有效时间剩下 30% 到 10% 之间的任意时间点。 同样地,控制器管理器会自动批准证书请求,并将签署的证书附加到证书签名请求中。 Kubelet 会从 Kubernetes API 取回签署的证书,并将其写入磁盘。 然后它会更新与 Kubernetes API 的连接,使用新的证书重新连接到 Kubernetes API。