k3s 2023证书轮转方案

不知不觉已经使用k3s几年了,虽然从使用上来说跟k8s并无区别,而且更加轻量,安装非常方便,但是也存在一些痛点。

今天就讨论下其中的证书轮转问题。

本文使用的 k3s 版本 为 v1.25.4+k3s1 ,相关操作应该在后续版本也适用,最好使用前先测试一下。

在这个版本, k3s 早已经实现了自动轮转,但是需要满足"证书过期或者距离过期时间小于等于90天(证书中 Validity 的 Not After 字段)"的条件并且重启时才会轮转。为什么官方不在安装脚本里面提供一个可以设置定时重启的选项,例如可以使用 systemd timer 或者 crontab。

除了定时任务重启,我们还可以通过延长证书有效期的方式,当然这会有一些安全风险。

k3s 使用的 CA 证书只有10年有效期,如果你对于该时间不满意,例如想可以在安装 k3s 前创建所需的 CA 证书,具体位置由用户设置决定,下面使用默认位置:
```bash

mkdir -p /var/lib/rancher/k3s/server/tls
cd /var/lib/rancher/k3s/server/tls
openssl genrsa -out client-ca.key 2048
openssl genrsa -out server-ca.key 2048
openssl genrsa -out request-header-ca.key 2048
openssl req -x509 -new -nodes -key client-ca.key -sha256 -days 3650 -out client-ca.crt -addext keyUsage=critical,digitalSignature,keyEncipherment,keyCertSign -subj '/CN=k3s-client-ca'
openssl req -x509 -new -nodes -key server-ca.key -sha256 -days 3650 -out server-ca.crt -addext keyUsage=critical,digitalSignature,keyEncipherment,keyCertSign -subj '/CN=k3s-server-ca'
openssl req -x509 -new -nodes -key request-header-ca.key -sha256 -days 3650 -out request-header-ca.crt -addext keyUsage=critical,digitalSignature,keyEncipherment,keyCertSign -subj '/CN=k3s-request-header-ca'
```

 接着安装 k3s。安装完成后会在 /var/lib/rancher/k3s/server/tls/ 中出现很多文件,其中 client-admin.crt 就是我们 kubectl 使用的客户端证书。

我们使用openssl查看其内容:

➜  tls openssl x509 -text -in  client-admin.crt
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 3805033951105087658 (0x34ce3237f5eb78aa)
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: CN = k3s-client-ca@1642582069
        Validity
            Not Before: Jan 19 08:47:49 2022 GMT
            Not After : Nov  2 08:56:54 2023 GMT
        Subject: O = system:masters, CN = system:admin
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:0b:85:a1:57:ac:9c:04:e3:c3:21:63:84:7a:85:
                    35:ac:65:d5:c0:7d:ca:24:cf:06:81:e3:31:ff:e3:
                    91:30:ef:17:aa:ad:cf:82:a9:f0:da:9b:40:c7:33:
                    32:39:ac:f4:5c:88:16:a9:a2:7f:91:22:ab:31:6e:
                    a4:9f:57:9c:9c
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication
            X509v3 Authority Key Identifier: 
                keyid:2D:59:5F:73:0E:EB:4A:AC:3C:63:A6:2E:F5:83:C2:F9:91:F7:EA:34

    Signature Algorithm: ecdsa-with-SHA256
         30:45:02:20:0e:56:1b:12:23:f5:b0:e6:59:85:b5:ad:d8:5b:
         e2:cc:cc:17:95:77:70:0c:c5:56:4a:d8:c2:99:be:38:d3:bd:
         02:21:00:e9:02:4e:d7:c4:43:4e:46:cc:de:93:0c:42:de:e6:
         e2:cf:1e:94:8b:c8:9c:d7:de:21:bf:da:58:e3:e6:46:ea
-----BEGIN CERTIFICATE-----
MIIB..................jj5kbq
-----END CERTIFICATE-----

然后查看 kubectl 使用的 kubeconfig 文件中的 client-certificate-data 对应的证书:

➜  tls k config view --flatten --minify    
apiVersion: v1
clusters:
...
users:
- name: default
  user:
    client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrVENDQVRlZ0F3SU......zJCRnRrL1R3b0dXWnJMdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
  
➜  tls echo LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrVENDQVRlZ0F3SU......zJCRnRrL1R3b0dXWnJMdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K|base64 -d|openssl x509 -text 

 Certificate:

    Data:
        Version: 3 (0x2)
        Serial Number: 3805033951105087658 (0x34ce3237f5eb78aa)
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: CN = k3s-client-ca@1642582069
        Validity
            Not Before: Jan 19 08:47:49 2022 GMT
            Not After : Nov  2 08:56:54 2023 GMT
        Subject: O = system:masters, CN = system:admin
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:0b:85:a1:57:ac:9c:04:e3:c3:21:63:84:7a:85:
                    35:ac:65:d5:c0:7d:ca:24:cf:06:81:e3:31:ff:e3:
                    91:30:ef:17:aa:ad:cf:82:a9:f0:da:9b:40:c7:33:
                    32:39:ac:f4:5c:88:16:a9:a2:7f:91:22:ab:31:6e:
                    a4:9f:57:9c:9c
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication
            X509v3 Authority Key Identifier: 
                keyid:2D:59:5F:73:0E:EB:4A:AC:3C:63:A6:2E:F5:83:C2:F9:91:F7:EA:34

    Signature Algorithm: ecdsa-with-SHA256
         30:45:02:20:0e:56:1b:12:23:f5:b0:e6:59:85:b5:ad:d8:5b:
         e2:cc:cc:17:95:77:70:0c:c5:56:4a:d8:c2:99:be:38:d3:bd:
         02:21:00:e9:02:4e:d7:c4:43:4e:46:cc:de:93:0c:42:de:e6:
         e2:cf:1e:94:8b:c8:9c:d7:de:21:bf:da:58:e3:e6:46:ea
-----BEGIN CERTIFICATE-----
MIIB..................jj5kbq
-----END CERTIFICATE-----

 两者完全一致。

 这里 client-certificate-data 证书要与 api-server 使用的证书区分开。

有了证书之后我们就可以从证书中提取出 CSR(Certificate Signing Request): 

 

➜  tls openssl x509 -x509toreq -in client-admin.crt -signkey client-admin.key -out client-admin.csr
Getting request Private Key
Generating certificate request

➜  tls openssl req -in client-admin.csr -text
Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: O = system:masters, CN = system:admin
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
...

 

 然后使用 CSR 文件 获取新的客户端证书 new-client-admin.crt :

➜  tls openssl x509 -req -days 3650 -in client-admin.csr -signkey client-admin.key -CA client-ca.crt -CAkey -CAcreateserial client-ca.key -out new-client-admin.crt 
➜  tls openssl x509 -in new-client-admin.crt -text -noout
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            42:80:25:5f:6e:39:54:bf:30:e6:0e:ff:ff:45:71:56:b9:53:a3:3c
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: CN = k3s-client-ca@1642582069
        Validity
            Not Before: Feb 12 11:50:59 2023 GMT
            Not After : Feb  9 11:50:59 2033 GMT
        Subject: O = system:masters, CN = system:admin
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:0b:85:a1:57:ac:9c:04:e3:c3:21:63:84:7a:85:
                    35:ac:65:d5:c0:7d:ca:24:cf:06:81:e3:31:ff:e3:
                    91:30:ef:17:aa:ad:cf:82:a9:f0:da:9b:40:c7:33:
                    32:39:ac:f4:5c:88:16:a9:a2:7f:91:22:ab:31:6e:
                    a4:9f:57:9c:9c
                ASN1 OID: prime256v1
                NIST CURVE: P-256
    Signature Algorithm: ecdsa-with-SHA256
         30:46:02:21:00:fc:05:b7:50:aa:ab:37:eb:f9:7a:a7:11:da:
         ce:c8:88:8a:ea:96:a6:7c:5e:d5:38:43:f7:48:15:ec:fd:86:
         98:02:21:00:cb:9a:b1:43:bd:49:76:fb:28:79:e1:74:2e:85:
         43:b2:1b:98:ea:89:0d:f9:d8:4f:0c:db:ed:6d:45:64:df:9a

  

然后我们将获得证书内容的base64 编码字符串:

➜  tls base64 new-client-admin.crt 
LS0tLS1CRUdJTiB......RS0tLS0tCg==

 最后将上诉base64编码字符串替换上面 kubeconfig 的 client-certificate-data 字段即可。

 

除了上述方法,其实还有一个更简洁的方式,通过设置环境变量 CATTLE_NEW_SIGNED_CERT_EXPIRATION_DAYS来指定证书的过期天数,这部分代码详见 https://github.com/rancher/dynamiclistener/blob/master/cert/cert.go#L118。如果是用官方安装脚本安装运行需要注意,直接设置的环境变量并不能被systemd(这里只说systemd,openrc应该类似)使用,我们需要在/etcdefault/k3s或者/etc/sysconfig/k3s中添加该环境变量:

echo CATTLE_NEW_SIGNED_CERT_EXPIRATION_DAYS=3650 > /etc/default/k3s
//或者
echo CATTLE_NEW_SIGNED_CERT_EXPIRATION_DAYS=3650 > /etc/sysconfig/k3s

如果还未安装k3s,设置上面的环境变量后即可使用官方脚本安装。如果已经安装了k3s,则可以删除目录/var/lib/rancher/k3s/server/tls,然后systemctl restart k3s即可。

 

posted on 2023-02-12 20:32  xzysaber  阅读(299)  评论(0编辑  收藏  举报

导航