跳转至

修改kubeadm调整证书有效期

修改源码,调整CA证书和子证书有效期均为100年

默认,k8s的CA证书是有效期10年(k8s ca、etcd-ca、front-proxy-ca),其他基于CA证书签发的子证书有效期均是1年。

此处以k8s 1.27.4为例,具体步骤如下: - 下载源码,在github上下载kubernetes release为1.27.4的源码 下载 - 解压源码: 1>、修改 kubernetes-1.27.4/staging/src/k8s.io/client-go/util/cert/cert.go CA根证书默认是10年有效期

ca.png

2>、修改kubernetes-1.27.4/cmd/kubeadm/app/util/pkiutil/pki_helpers.go

生成自签证书的 CertificateValidity 是一个常量,值是 time.Hour * 24 * 365 即1年,所以改成再乘以100,建议改CertificateValidity这个常量的值

c.png

改了常量的值后,下面代码位置就【不需要】再乘以100了

cert.png

3>、编译(可以参考Mafile文件),只需要kubeadm即可,也可以直接用make all编译所有组件

go mod tidy
make all WHAT=cmd/kubeadm GOFLAGS=-v

make.png

4>、替换kubeadm文件

cp /usr/bin/kubeadm{,.bak}
scp _output/local/bin/linux/amd64/kubeadm  root@x.x.x.x:/usr/bin/

5>、更新集群证书,如果有多个master,需要在所有master节点上更新

## 备份所有节点/etc/kubernetes,以便在失败时能够被还原
cp -rp /etc/kubernetes{,.bak}
kubeadm certs renew all

6>、重启kube-apiserver, kube-controller-manager, kube-scheduler and etcd

## 使用以下方式重启
mv /etc/kubernetes/manifests /etc/kubernetes/manifests.bak
## 查看 kube-apiserver, kube-controller-manager, kube-scheduler and etcd 等容器是否均已停止
crictl ps 
## 如果已经停止,再将 manifests.bak 改回成 manifests
mv /etc/kubernetes/manifests.bak /etc/kubernetes/manifests
## 等待kube-apiserver, kube-controller-manager, kube-scheduler and etcd起动完成

最后,检查证书有效期

# kubeadm certs check-expiration
CERTIFICATE                EXPIRES                  RESIDUAL TIME   CERTIFICATE AUTHORITY   EXTERNALLY MANAGED
admin.conf                 Nov 26, 2123 03:32 UTC   99y             ca                      no      
apiserver                  Nov 26, 2123 03:18 UTC   99y             ca                      no      
apiserver-etcd-client      Nov 26, 2123 03:18 UTC   99y             etcd-ca                 no      
apiserver-kubelet-client   Nov 26, 2123 03:18 UTC   99y             ca                      no      
controller-manager.conf    Nov 26, 2123 03:32 UTC   99y             ca                      no      
etcd-healthcheck-client    Nov 26, 2123 03:18 UTC   99y             etcd-ca                 no      
etcd-peer                  Nov 26, 2123 03:18 UTC   99y             etcd-ca                 no      
etcd-server                Nov 26, 2123 03:18 UTC   99y             etcd-ca                 no      
front-proxy-client         Nov 26, 2123 03:18 UTC   99y             front-proxy-ca          no      
scheduler.conf             Nov 26, 2123 03:32 UTC   99y             ca                      no      

CERTIFICATE AUTHORITY   EXPIRES                  RESIDUAL TIME   EXTERNALLY MANAGED
ca                      Aug 06, 2033 06:02 UTC   9y              no      
etcd-ca                 Aug 06, 2033 06:02 UTC   9y              no      
front-proxy-ca          Aug 06, 2033 06:02 UTC   9y              no      

按照上面步骤更新后,根证书ca、etcd-ca、front-proxy-ca仍然是10年,因为CA根证书没有重新生成(也包括各worker节点上的/etc/kubernetes/pki/ca.crt)。 当CA证书过期时,由该CA签发的所有证书将不再被信任,即使它们的有效期尚未结束。因此,CA 证书的有效期也要设置为足够长的时间

各证书用途 - admin.conf:这是集群管理员用于与 API Server 进行通信的客户端证书,通常用于 kubectl 命令行工具或其他需要对集群进行管理操作的应用程序。 - apiserver:API Server 服务器证书,用于证明 API Server 的身份。当其他组件(如 kubelet、controller-manager、scheduler 或外部客户端)连接到 API Server 时,会验证此证书以确保与正确的服务进行通信。 - apiserver-etcd-client:API Server 用来连接 etcd 数据库的客户端证书,保证了数据层的安全访问。 - apiserver-kubelet-client:API Server 用于与 kubelet 进行安全通信的客户端证书。 - controller-manager.conf 和 scheduler.conf:这两个文件分别对应于控制器管理器(kube-controller-manager)和服务调度器(kube-scheduler)的客户端证书,它们用于与 API Server 进行安全认证。 - etcd-healthcheck-client:用于执行 etcd 健康检查的客户端证书。 - etcd-peer:etcd 节点之间相互通信的证书,用于保护 etcd 集群内部的数据传输安全。 - etcd-server:etcd 服务端证书,用于对外提供服务时的身份验证。 - front-proxy-client:kube-apiserver 的前端代理客户端证书,用于与请求头代理相关的身份验证。 对于证书颁发机构(CA)部分: - ca:Kubernetes 根证书颁发机构,签发上述除 etcd-ca 和 front-proxy-ca 外的所有证书。 - etcd-ca:专门用于签发 etcd 相关证书的证书颁发机构。 - front-proxy-ca:负责签发前端代理相关证书的证书颁发机构。

其中front-proxy-client 和 front-proxy-ca 证书在 Kubernetes 集群中主要用于实现请求头代理(Request Header Proxy)的功能, 这种机制允许集群外部的客户端通过一个中间代理服务器安全地访问集群内部的服务。具体使用场景和作用如下: front-proxy-ca.crt: 这是一个证书颁发机构(CA)证书,用于签发前端代理服务所使用的证书,如 front-proxy-client.crt。集群中的前端代理服务会信任由 front-proxy-ca.crt 签发的证书。 front-proxy-client.crt 及其对应的私钥文件:这是一个客户端证书,被前端代理服务(例如 kube-apiserver 的前置代理)使用,以验证它与集群内部组件通信时的身份。当集群外的客户端通过这个前端代理访问 API Server 时,API Server 会验证前端代理发送过来的请求是否携带有由 front-proxy-ca 签发的有效证书。这样可以确保只有经过身份验证的前端代理才能代表外部客户端与集群进行交互。 具体的工作流程是这样的: 外部客户端向前端代理发起 HTTPS 请求。 前端代理收到请求后,将请求头部进行修改(如添加或替换 Authorization 头),然后转发给集群内的 API Server。 API Server 收到请求后,首先验证前端代理提供的 front-proxy-client.crt 证书是否由受信的 front-proxy-ca 签发,并且有效。 验证通过后,API Server 根据请求头部信息执行相应的操作。 通过这种方式,Kubernetes 实现了对集群外部客户端的安全认证和授权控制,同时保持了内部网络结构的隔离性。 上述所有列出的证书均由 kubeadm 自动生成并维护的。

  • 查看已有的用kubeadm生成的CA证书(也可以用cfssl-certinfo -cert ca.crt)
    # openssl x509 -in /etc/kubernetes/pki/ca.crt -text -noout        
    Certificate:
        Data:
            Version: 3 (0x2)
            Serial Number: 4451033681560841821 (0x3dc53f8d00bbae5d)
            Signature Algorithm: sha256WithRSAEncryption
            Issuer: CN = kubernetes  # 通用名
            Validity
                Not Before: Aug 17 02:07:03 2023 GMT
                Not After : Aug 14 02:07:03 2033 GMT
            Subject: CN = kubernetes
            Subject Public Key Info:
                Public Key Algorithm: rsaEncryption
                    RSA Public-Key: (2048 bit) # 加密方式
                    Modulus:
                        00:cf:d1:e2:98:c6:5c:85:8f:05:d9:13:da:37:35:
                        65:24:e7:ad:b7:be:56:e2:46:1c:d6:e3:f3:d2:2e:
                        f5:58:ba:00:9b:4c:be:82:b3:1c:65:37:73:59:b7:
                        81:73:d1:6f:93:e8:55:d3:f5:44:85:1e:e8:f0:2a:
                        60:67:6d:57:a1:90:28:41:57:fa:a8:01:dd:e4:7d:
                        c8:40:b0:3a:84:8d:18:2f:0d:06:a9:61:1e:cb:24:
                        8a:36:fe:60:a6:b3:37:f7:73:18:94:21:64:6b:a7:
                        26:c9:9c:17:bf:59:4b:f5:a9:f2:b6:7b:b3:ad:76:
                        6a:8d:4f:fa:53:a1:03:3f:58:3a:b4:6a:9e:5b:e2:
                        3b:e4:43:bd:7c:06:11:1d:07:30:07:9f:7e:f3:02:
                        c2:82:48:39:6b:a9:6f:f4:ab:e1:83:a7:6c:4b:ae:
                        63:31:df:51:ff:7e:43:b5:d5:0b:3c:aa:8c:d9:8a:
                        ed:af:4b:41:9d:09:50:6b:6c:b3:4e:77:a5:bc:7a:
                        33:cc:fc:fa:8f:ca:5b:70:e9:af:f6:a8:3c:7f:19:
                        56:9e:dc:ae:a6:e9:0e:7e:4a:41:6d:c1:f2:2d:06:
                        58:2d:3d:1d:1f:4f:77:17:0c:bd:8d:55:99:75:a0:
                        dc:85:14:75:84:d0:85:24:b2:06:a8:c9:15:09:ba:
                        1a:bd
                    Exponent: 65537 (0x10001)
            X509v3 extensions:
                X509v3 Key Usage: critical
                    Digital Signature, Key Encipherment, Certificate Sign
                X509v3 Basic Constraints: critical
                    CA:TRUE
                X509v3 Subject Key Identifier: 
                    42:6D:2A:00:13:F0:42:97:EF:DA:E8:BA:5B:BE:FC:79:DE:CE:9F:E7
                X509v3 Subject Alternative Name: 
                    DNS:kubernetes
        Signature Algorithm: sha256WithRSAEncryption
             83:e2:a6:f8:51:ab:39:d0:3e:79:0e:86:23:bb:b7:20:02:37:
             bb:8f:16:88:5d:bf:8d:03:6d:31:2d:00:66:eb:56:3c:93:da:
             95:92:02:98:df:54:18:29:e0:d9:05:2e:f0:a9:0c:b9:b2:69:
             01:c2:89:d4:0c:90:3f:c1:68:5e:d3:3e:5a:e6:57:08:11:e8:
             e5:2f:b7:3b:d8:3d:bd:60:94:76:b7:59:08:85:3c:3a:8c:6a:
             25:5b:99:5e:3c:ad:a3:0b:7a:11:b0:ea:df:d5:66:ff:a3:d6:
             a4:14:2f:94:a1:08:81:01:a8:af:ad:f6:10:3a:b6:f6:5c:c9:
             87:a3:df:ae:fe:86:cf:86:0b:7d:5c:d1:a4:b8:11:75:3c:cd:
             fb:cc:7f:ad:95:f0:14:6c:7b:f0:ce:fc:be:43:8f:cd:12:1f:
             19:26:1e:32:91:79:eb:1b:ff:5c:a9:f0:f2:a7:8e:85:6f:22:
             b2:a8:5b:7b:42:90:08:57:d6:78:27:14:de:f8:0f:da:33:1a:
             b5:8a:d1:30:38:e5:ed:fe:0f:b3:53:1d:34:95:1d:8e:44:a6:
             ed:dd:ef:6f:0e:29:cf:db:83:26:65:2b:71:15:3c:c1:a6:54:
             73:95:f0:aa:1e:83:ca:93:95:f1:a9:d5:19:a5:c7:3e:b6:f8:
             48:64:82:44
    
    
    ## 查看 front-proxy-ca.crt 
    # cfssl-certinfo -cert front-proxy-ca.crt 
    {
      "subject": {
        "common_name": "front-proxy-ca",
        "names": [
          "front-proxy-ca"
        ]
      },
      "issuer": {
        "common_name": "front-proxy-ca",
        "names": [
          "front-proxy-ca"
        ]
      },
      "serial_number": "7320769407696814648",
      "sans": [
        "front-proxy-ca"
      ],
      "not_before": "2023-08-17T02:07:03Z",
      "not_after": "2033-08-14T02:07:03Z",
      "sigalg": "SHA256WithRSA",
      "authority_key_id": "",
      "subject_key_id": "E9:6D:4E:04:B0:53:A7:19:B4:7B:5F:1B:65:11:77:06:62:EC:2B:E0",
      "pem": "-----BEGIN CERTIFICATE-----\nMIIDETCCAfmgAwIBAgIIZZiY/TxQwjgwDQYJKoZIhvcNAQELBQAwGTEXMBUGA1UE\nAxMOZnJvbnQtcHJveHktY2EwHhcNMjMwODE3MDIwNzAzWhcNMzMwODE0MDIwNzAz\nWjAZMRcwFQYDVQQDEw5mcm9udC1wcm94eS1jYTCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBALmgR48rhHqSMb6NniEXftHgLZRi/HimksuuVDOPbbSSVp4d\nhH/eEoUg404pQxRfT+cd+IpwhcEgbDhPs0MiJrX987qar6b8Ccy72MfyAsrfkUkX\n02R1FwIimr9qC16zYcl5RT4HRBjE/tLjF15l9iGYYSuuaIV8+Irwsqu9Ct8vVTEe\nQCqVrrqsAXhu4wKnTGo+Q4RwrAurghXJ/D18/wfJRkgs+eMcc2ztnnUiiBRl2c0j\nKVVp7RbtD/Z+dIDGLQ5CIUUM/d19P4B3ahlaY4LI9aqpv37pxQZPAEv6N44bpAqx\nYGrqoljRrEkvjhYG93m3zfQmJD6sVjhuefIBF6ECAwEAAaNdMFswDgYDVR0PAQH/\nBAQDAgKkMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOltTgSwU6cZtHtfG2UR\ndwZi7CvgMBkGA1UdEQQSMBCCDmZyb250LXByb3h5LWNhMA0GCSqGSIb3DQEBCwUA\nA4IBAQAwLx5385fuq39PucPQwCafi3NdSxiAUSAvyIus6UQSYb+y7ca04S4HsQoQ\niUsdoCzOn0B8MTaDu4RmIjCo5JgzMkUdfzCnWY358dsfDlXEFhpSlJRXT8WhT2hb\nXyXKQsukXmWo/CI2biT34aTIOwGWGKYpGyJGjf6w4amad5P9j1vvwi7a9Cb9MR68\nMTekbZYBn0FxSPXzXtdK3Z0i+luFLOycjhoUtxlOCbzMI1bb0J3OmKlJpN9O2vGT\n7/S7ko4YzZvmCrhMeO4GnQvXIzNBVTaV2Jw3UodXmY7oRadSCOy5ocrbOy6Gsrsp\neS60vn2WY1Mb3zvrUmRTjZRzwnYM\n-----END CERTIFICATE-----\n"
    }
    
    ## 查看 etcd 的 ca.crt 
    # cfssl-certinfo -cert ca.crt 
    {
      "subject": {
        "common_name": "etcd-ca",
        "names": [
          "etcd-ca"
        ]
      },
      "issuer": {
        "common_name": "etcd-ca",
        "names": [
          "etcd-ca"
        ]
      },
      "serial_number": "5126283446287249703",
      "sans": [
        "etcd-ca"
      ],
      "not_before": "2023-08-17T02:07:04Z",
      "not_after": "2033-08-14T02:07:04Z",
      "sigalg": "SHA256WithRSA",
      "authority_key_id": "",
      "subject_key_id": "EB:70:DA:68:22:72:56:F8:CC:18:46:0B:62:F6:57:09:65:73:21:2F",
      "pem": "-----BEGIN CERTIFICATE-----\nMIIC/DCCAeSgAwIBAgIIRyQ3olnqsScwDQYJKoZIhvcNAQELBQAwEjEQMA4GA1UE\nAxMHZXRjZC1jYTAeFw0yMzA4MTcwMjA3MDRaFw0zMzA4MTQwMjA3MDRaMBIxEDAO\nBgNVBAMTB2V0Y2QtY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8\njv6bwcmPDU7CE9AA+E8lvOFEHjisDulY7Jj2bWoWFhgNkafR9qr5yOTJb12D4t7H\n3zzqWUpRVg98oU6XmfNK0IV6jXUqxlNKttn94czyBpqQLwTz5AJhHxxQz+RxHJE9\n6vtB+fQ1XWLy0bO4QZau7MUYUXnwVwKczeUnyNxpAOjZX7V9cgLTBe2qhUrwQ+f2\nw9z9LaTMAXTcyqH99mFgeQgamDGBi4MBUqR/oHYAx/X+197BEIRGKQApi3OW38OC\nk7A4zsKlOJD7yh9H2X7nj/BXHEAxBetVQo35NLlu2KPR2AkSEEzAMa08SyNAjzhl\nCzWWv8KD+Gena+A6fqJ9AgMBAAGjVjBUMA4GA1UdDwEB/wQEAwICpDAPBgNVHRMB\nAf8EBTADAQH/MB0GA1UdDgQWBBTrcNpoInJW+MwYRgti9lcJZXMhLzASBgNVHREE\nCzAJggdldGNkLWNhMA0GCSqGSIb3DQEBCwUAA4IBAQAUKZzn/cioQWhtiyQ+vshn\noVXouj4odYhaot4EOXMO3QlhqiXEJioOmhLscaG9JQtLsKs47YaY4yryXMHdekCm\nFuJAGPHFC8g0B7tTlmrm/eO+SVjehCbr/Q5rensY+CTWi7OUh8oexSiQ4+L/unxB\n3axI9WV1wGP9/kQLBFsfQYDS/W02XKwLKaDwYDA3dpM0WfRotQTM0tXSpp6WhOUt\nfkLQTUnrCkwcjaq6K0Qw8i0X5KPsnjQ1ZAkr6lVFrMhJsRaVBvlZO0T4gMwfofJk\n9xw35FGoZ4HTZc6qC+v1lpPM34JsMZ/h5tXuYOXIefqBBiYs0AcxVP4C2JyteICP\n-----END CERTIFICATE-----\n"
    }
    
  • 使用cfssl工具重新生成自签CA证书(只需要在master节点上执行生成,然后拷贝到其他节点)
    # wget https://github.com/cloudflare/cfssl/releases/download/v1.6.4/cfssl_1.6.4_linux_amd64
    # wget https://github.com/cloudflare/cfssl/releases/download/v1.6.4/cfssljson_1.6.4_linux_amd64
    # wget https://github.com/cloudflare/cfssl/releases/download/v1.6.4/cfssl-certinfo_1.6.4_linux_amd64
    
    # mv cfssl_1.6.4_linux_amd64 /usr/bin/cfssl
    # mv cfssljson_1.6.4_linux_amd64 /usr/bin/cfssljson
    # mv cfssl-certinfo_1.6.4_linux_amd64 /usr/bin/cfssl-certinfo
    # chmod +x /usr/bin/cfssl*
    
    
    
    # cfssl print-defaults config > config-ca.json
    # cfssl print-defaults csr > config-csr.json
    
    将 config-csr.json内容修改如下
    # cat config-csr.json 
    {
        "CN": "kubernetes",
        "key": {
            "algo": "rsa",
            "size": 2048
        },
        "ca": {
        "expiry": "876000h"
       }
    }
    

将 front-proxy-ca-config-csr.json 内容修改如下

# cat front-proxy-ca-config-csr.json
{
    "CN": "front-proxy-ca",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "ca": {
    "expiry": "876000h"
   }
}

将 etcd-ca-config-csr.json 内容修改如下

# cat etcd-ca-config-csr.json
{
    "CN": "etcd-ca",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "ca": {
    "expiry": "876000h"
   }
}

重新生成ca证书 手动轮换 CA 证书

## 生成k8s根证书
# cfssl gencert -initca config-csr.json |cfssljson -bare ca -
## 命令会生成 ca.pem、ca.csr、ca-key.pem,其中ca.pem等于ca.crt,ca-key.pem等于ca.key

## 生成 front-proxy 根证书
# cfssl gencert -initca front-proxy-ca-config-csr.json |cfssljson -bare front-proxy-ca -


## 生成 etcd 根证书
# cfssl gencert -initca etcd-ca-config-csr.json |cfssljson -bare etcd-ca -

如果是多个master,还需要将上面生成的ca证书更新到其他master节点上

## 在所有master节点上执行
# cp -rp ca.pem ca-key.pem /etc/kubernetes/pki/
# cp -rp front-proxy-ca-key.pem  front-proxy-ca.pem /etc/kubernetes/pki/
# cp -rp etcd-ca.pem etcd-ca-key.pem /etc/kubernetes/pki/etcd/

cd /etc/kubernetes/pki/
mv ca.crt ca.crt.bak
mv ca.key ca.key.bak
mv ca.pem ca.crt
mv ca-key.pem ca.key

mv front-proxy-ca.crt front-proxy-ca.crt.bak
mv front-proxy-ca.key front-proxy-ca.key.bak
mv front-proxy-ca.pem front-proxy-ca.crt
mv front-proxy-ca-key.pem front-proxy-ca.key

cd etcd
mv ca.crt ca.crt.bak
mv ca.key ca.key.bak
mv etcd-ca.pem ca.crt
mv etcd-ca-key.pem ca.key

基于新的CA证书重新renew集群相关子证书,在所有master节点上执行

# kubeadm certs renew all
# cp -rp /etc/kubernetes/admin.conf /root/.kube/config 
# kubectl delete pods -n kube-system kube-apiserver-k8s01 kube-controller-manager-k8s01 kube-scheduler-k8s01 etcd-k8s01 --force
此时会因为kubelet证书未更新,导致apiserver、controller-manager等pod在删除后无法创建出来 因为kubeadm certs renew all 并不会更新kubelet.conf以及kubelet的证书文件,还需要在worker节点上做如下操作: 0. 更新各worker节点上的ca证书
## 从master节点上拷贝ca.crt到各个node节点上
scp -rp /etc/kubernetes/pki/ca.crt k8s02:/etc/kubernetes/pki/
scp -rp /etc/kubernetes/pki/ca.crt k8s03:/etc/kubernetes/pki/
重启kubelet,在此过程中,可能会出现kubelet客户端证书轮换失败的情况,因此需要在master节点上执行如下命令,生成各worker节点的kubelet.conf文件

为 kubelet 配置证书轮换 ,kubelet的 --rotate-certificates 参数已经废弃(默认就启用了客户端证书轮换),在先前版本,该参数决定kubelet在当前使用的证书即将到期时,是否会自动申请新的证书。

Kubelet客户端证书轮换失败 1. 在轮换失败的worker节点上,备份并删除 /etc/kubernetes/kubelet.conf 和 /var/lib/kubelet/pki/kubelet-client*

mv /etc/kubernetes/kubelet.conf /tmp
mv /var/lib/kubelet/pki/kubelet-client* /tmp
2. 在工作正常的控制平面节点上执行 kubeadm kubeconfig user --org system:nodes --client-name system:node:$NODE > kubelet.conf,$NODE 必须设置为集群中现有故障节点的名称
kubeadm kubeconfig user --org system:nodes --client-name system:node:k8s01 > /etc/kubernetes/kubelet.conf
kubeadm kubeconfig user --org system:nodes --client-name system:node:k8s02 >kubelet-k8s02.conf
kubeadm kubeconfig user --org system:nodes --client-name system:node:k8s03 >kubelet-k8s03.conf
3. 将得到的 kubelet-xx.conf 文件复制到故障节点上
scp -rp kubelet-k8s02.conf k8s02:/etc/kubernetes/kubelet.conf 
scp -rp kubelet-k8s03.conf k8s03:/etc/kubernetes/kubelet.conf 
4. 重启故障节点上的kubelet,等待 /var/lib/kubelet/pki/kubelet-client-current.pem 重新创建出来
systemctl restart kubelet 
5. 手动编辑 kubelet.conf 指向轮换的 kubelet 客户端证书,方法是将 client-certificate-data 和 client-key-data 替换为
client-certificate: /var/lib/kubelet/pki/kubelet-client-current.pem
client-key: /var/lib/kubelet/pki/kubelet-client-current.pem
6. 再次重启故障节点上的kubelet
systemctl restart kubelet
7. 确保故障节点变为Ready状态
kubectl get node 

  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
    

    这段脚本的作用是在k8s集群中为所有命名空间下的 Deployment 和 Daemonset 中的所有 Pod 添加一个名为 ca-rotation 的注解,其值为 "1"。添加这个注解的主要目的是触发这些工作负载的滚动更新(Rolling Update),即使它们的镜像版本没有变化。

    在CA证书轮换更新时,可能需要确保集群中的每个 Pod 使用最新的信任锚点或证书配置。通过给 Pod Spec 的模板添加注解并更改 PodTemplateSpec,Kubernetes 会认为这是一种配置变更,并按照滚动更新策略替换现有的 Pods。 这样可以确保新的安全配置被及时应用到所有的 Pod 上。

    当然,statefulset 也可能需要使用最新的CA证书,但statefulset的pod具有稳定且唯一标识符,同时要做到有序的启动和终止,重启更为复杂,不能直接用上面的命令去重启,但可以手工去控制重启。 是否要滚动更新Daemonset、Deployment、statefulset等工作负载,需要看这些工作负载内的应用程序或容器是否依赖了集群提供的信任锚点(例如通过服务账号挂载的 TLS 证书和私钥), 如果有,这时就需要确保这些应用能够正确地识别并使用新的 CA 证书。比如,有些pod挂载了/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

  2. 更新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 -
    

此时,kubelet的客户端证书有效期还是1年轮换一次,这在k8s官档 有描述。

当签署的证书即将到期时,kubelet 会使用 Kubernetes API,自动发起新的证书签名请求。 该请求会发生在证书的有效时间剩下 30% 到 10% 之间的任意时间点。

需要调整kube-controller-manager 配置。尽管 API 服务器从 kubelet 收到证书请求并对这些请求执行身份认证, 但真正负责发放签名证书的是controller-manager。

controller-manager

- --cluster-signing-duration=876000h0m0s

在/var/lib/kubelet/pki目录下有2个证书文件,分别是kubelet kubelet-client-current.pem 和 kubelet.crt

kubelet-client-current.pem 通常指的是 kubelet 用于与 API Server 进行通信时所使用的客户端证书。这个证书的生命周期取决于集群配置中关于客户端证书自动签发和续期的策略设置。

kubelet.crt 则是 kubelet 的服务端证书,用于与其他组件(例如 API Server)进行 TLS 通信验证时使用。

最后,检查确保kube-controller-manager日志中没有 TLS 相关的错误信息

kubectl logs -n kube-system kube-controller-manager-k8s01 -f --tail 10
创建deployment、statefulset等正常

检查证书有效期

# kubeadm certs check-expiration
# openssl x509 -in kubelet-client-current.pem -text -noout
result.png

如果kube-controller-manager-k8s01中有如下未认证的日志,可能是因为CA证书轮换后,kube-controller-manager容器未正常重启

...
1 leaderelection.go:327] error retrieving resource lock kube-system/kube-controller-manager: Unauthorized
解决办法就是在所有master节点使用crictl stop命令停止kube-controller-manager容器

# kubectl get csr
NAME        AGE   SIGNERNAME                                    REQUESTOR                 REQUESTEDDURATION   CONDITION
csr-dblfk   91m   kubernetes.io/kube-apiserver-client-kubelet   system:node:k8s01         <none>              Approved,Issued
csr-g4rbp   90m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
csr-zx59n   90m   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef   <none>              Approved,Issued
csr-rtc2l   91m   kubernetes.io/kube-apiserver-client-kubelet   system:node:k8s02         <none>              Pending

# kubectl certificate approve  csr-rtc2l

初始何集群命令

kubeadm init --config kubeadm.yaml --node-name=k8s01 --upload-certs

kubeadm join 192.168.59.241:6443 --token abcdef.0123456789abcdef \
        --discovery-token-ca-cert-hash sha256:959ca546fb6ac87475fbb26649508fdaf0373c3c4a0307611cd0ba7cbfb96cc9   --node-name=k8s02