Tanzu Kubernetes Grid 2.1の証明書自動更新機能の裏側を確認する

 TKG2.1のRelease Notesに以下の文面があった。

> Clusters can automatically renew control plane node VM certificates; see [Control Plane Node Certificate Auto-Renewal]((https://docs.vmware.com/en/VMware-Tanzu-Kubernetes-Grid/2.1/using-tkg-21/workload-clusters-secret.html#auto-renew)).

ドキュメントのパラメタの記載が非常に読みづらいのだが、要は以下の値でControlPlaneノード内の証明書が自動的に更新される。（値の設定は変更可。以下はデフォルト値）
```
    variables:
    - name: controlPlaneCertificateRotation
      value:
        activate: true
        daysBefore: 90
```
この値が実際にどこに効いているのかを調べた時のメモ。
ClusterAPIにある程度精通していることが前提で書いているので、説明不足な点はご了承を。

## 調査
ドキュメントの設定値(cluster.spec.topology.variables)について`kubectl explain`で調べてみる。
```
$ kubectl explain cluster.spec.topology.variables
：（省略）
DESCRIPTION:
     Variables can be used to customize the Cluster through patches. They must
     comply to the corresponding VariableClasses defined in the ClusterClass.

     ClusterVariable can be used to customize the Cluster through patches. It
     must comply to the corresponding ClusterClassVariable defined in the
     ClusterClass.
```
ClusterClassの中に定義されてるようなことが書かれている。
ClusterClassはデフォルトで1つだけ存在するので、これを見てみる。
```
kubectl get clusterclass -o yaml tkg-vsphere-default-v1.0.0
```
中を見ると、`controlPlaneCertificateRotation`に関する記述は2箇所見つかる。
1つ目は以下のパッチを当てている箇所だ。
```yaml
  - definitions:
    - jsonPatches:
      - op: add
        path: /spec/template/spec/rolloutBefore
        valueFrom:
          template: |
            certificatesExpiryDays: {{ .controlPlaneCertificateRotation.daysBefore }}
      selector:
        apiVersion: controlplane.cluster.x-k8s.io/v1beta1
        kind: KubeadmControlPlaneTemplate
        matchResources:
          controlPlane: true
    enabledIf: '{{ .controlPlaneCertificateRotation.activate }}'
    name: kcptCertificateRotation
```
2つ目は以下のパラメタの定義をしている箇所になる。
```yaml
  - name: controlPlaneCertificateRotation
    required: false
    schema:
      openAPIV3Schema:
        default:
          activate: true
          daysBefore: 90
        properties:
          activate:
            default: true
            type: boolean
          daysBefore:
            default: 90
            format: int32
            minimum: 7
            type: integer
        type: object
```

2つ目の定義は置いておいて、1つ目のselectorで`KubeadmControlPlaneTemplate`を指定していることから、KCP(KubeadmControlPlane)にパッチを当てていることが想像できる。
ここでkcpのリソースを見てみる。
```
$ kubectl explain kcp.spec --recursive
：(省略)
   rolloutBefore	<Object>
      certificatesExpiryDays	<integer>
```
パッチの内容と同じようなパラメタが見つかった。おそらくこれを書き換えているものと想像出来る。
念の為、実際のkcpに設定されているかも確認しておく。
```json
$ kubectl get kcp -o yaml tkg21wc-b9qzg -o jsonpath={.spec.rolloutBefore}
{"certificatesExpiryDays":90}
```
指定した値が入っているようだ。
これの仕様をClusterAPIのドキュメントから確認する。
[Automatically rotating certificates using Kubeadm Control Plane provider](
https://cluster-api.sigs.k8s.io/tasks/certs/auto-rotate-certificates-in-kcp.html)
ドキュメントから`kubeadm certs renew` 相当のことをやってくれると推察出来る。
また、kcpは`Machine`リソースに設定される証明書の有効期限を見て、ロールアウトしてくれる模様。
```
$ kubectl get machine -o yaml tkg21wc-b9qzg-tg26s -ojsonpath={.status.certificatesExpiryDate}
2024-04-02T09:17:28
```
ここまで分かれば動作検証が可能である。

## 検証

ノードにログインし、現時点の`kubeadm certs`で管理されている証明書を取得する。。
```
# kubeadm certs check-expiration
[check-expiration] Reading configuration from the cluster...
[check-expiration] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'

CERTIFICATE                EXPIRES                  RESIDUAL TIME   CERTIFICATE AUTHORITY   EXTERNALLY MANAGED
admin.conf                 Apr 03, 2024 02:24 UTC   364d            ca                      no
apiserver                  Apr 03, 2024 02:24 UTC   364d            ca                      no
apiserver-etcd-client      Apr 03, 2024 02:24 UTC   364d            etcd-ca                 no
apiserver-kubelet-client   Apr 03, 2024 02:24 UTC   364d            ca                      no
controller-manager.conf    Apr 03, 2024 02:24 UTC   364d            ca                      no
etcd-healthcheck-client    Apr 03, 2024 02:24 UTC   364d            etcd-ca                 no
etcd-peer                  Apr 03, 2024 02:24 UTC   364d            etcd-ca                 no
etcd-server                Apr 03, 2024 02:24 UTC   364d            etcd-ca                 no
front-proxy-client         Apr 03, 2024 02:24 UTC   364d            front-proxy-ca          no
scheduler.conf             Apr 03, 2024 02:24 UTC   364d            ca                      no

CERTIFICATE AUTHORITY   EXPIRES                  RESIDUAL TIME   EXTERNALLY MANAGED
ca                      Mar 31, 2033 09:16 UTC   9y              no
etcd-ca                 Mar 31, 2033 09:16 UTC   9y              no
front-proxy-ca          Mar 31, 2033 09:16 UTC   9y              no
```

次に証明書の期限切れを擬似的に起こす。`Machine`リソースに設定される証明書の有効期限は`Machine`リソースのannotationに`machine.cluster.x-k8s.io/certificates-expiry: "2021-04-03T09:16:36Z"`
のように書くことで更新できる。
更新後、`status`が書き換わっていることを確認する。
```
$ kubectl get machine -o yaml tkg21wc-b9qzg-tg26s -ojsonpath={.status.certificatesExpiryDate}
2021-04-03T09:16:36Z
```
しばらくすると、Machineがロールアウトされるのが確認できる。
```
$ kubectl get machine
NAME                                  CLUSTER   NODENAME                              PROVIDERID                                       PHASE          AGE     VERSION
tkg21wc-b9qzg-ngsp6                   tkg21wc   tkg21wc-b9qzg-ngsp6                   vsphere://422bbbc5-4435-2307-241b-44688a34a9f2   Running        3h41m   v1.24.9+vmware.1
tkg21wc-b9qzg-pb4kb                   tkg21wc   tkg21wc-b9qzg-pb4kb                   vsphere://422b1ebe-e355-da61-bb61-4041898c2b6c   Running        20h     v1.24.9+vmware.1
tkg21wc-b9qzg-tg26s                   tkg21wc   tkg21wc-b9qzg-tg26s                   vsphere://422b016b-1f0a-4329-4b5d-bee5dc9e732a   Running        20h     v1.24.9+vmware.1
tkg21wc-b9qzg-vnkln                   tkg21wc                                                                                          Provisioning   34s     v1.24.9+vmware.1
tkg21wc-md-0-8jpw5-5cc9bc9c94-562wm   tkg21wc   tkg21wc-md-0-8jpw5-5cc9bc9c94-562wm   vsphere://422b1243-f39d-832a-d567-1f504b2dec05   Running        20h     v1.24.9+vmware.1
tkg21wc-md-0-8jpw5-5cc9bc9c94-7q89v   tkg21wc   tkg21wc-md-0-8jpw5-5cc9bc9c94-7q89v   vsphere://422b22f2-c284-9f6b-9ab7-bbd51ba9f54d   Running        20h     v1.24.9+vmware.1
tkg21wc-md-0-8jpw5-5cc9bc9c94-wxs7s   tkg21wc   tkg21wc-md-0-8jpw5-5cc9bc9c94-wxs7s   vsphere://422b7b65-6dd0-7000-e19b-9d7c16fbc96a   Running        20h     v1.24.9+vmware.1
```
再作成されたノードにログインすると、証明書が更新されていることが確認できる。
```
# kubeadm certs check-expiration
[check-expiration] Reading configuration from the cluster...
[check-expiration] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'

CERTIFICATE                EXPIRES                  RESIDUAL TIME   CERTIFICATE AUTHORITY   EXTERNALLY MANAGED
admin.conf                 Apr 03, 2024 06:05 UTC   364d            ca                      no
apiserver                  Apr 03, 2024 06:05 UTC   364d            ca                      no
apiserver-etcd-client      Apr 03, 2024 06:05 UTC   364d            etcd-ca                 no
apiserver-kubelet-client   Apr 03, 2024 06:05 UTC   364d            ca                      no
controller-manager.conf    Apr 03, 2024 06:05 UTC   364d            ca                      no
etcd-healthcheck-client    Apr 03, 2024 06:05 UTC   364d            etcd-ca                 no
etcd-peer                  Apr 03, 2024 06:05 UTC   364d            etcd-ca                 no
etcd-server                Apr 03, 2024 06:05 UTC   364d            etcd-ca                 no
front-proxy-client         Apr 03, 2024 06:05 UTC   364d            front-proxy-ca          no
scheduler.conf             Apr 03, 2024 06:05 UTC   364d            ca                      no

CERTIFICATE AUTHORITY   EXPIRES                  RESIDUAL TIME   EXTERNALLY MANAGED
ca                      Mar 31, 2033 09:16 UTC   9y              no
etcd-ca                 Mar 31, 2033 09:16 UTC   9y              no
front-proxy-ca          Mar 31, 2033 09:16 UTC   9y              no
```

## まとめ
TKG2.1から追加された証明書の自動更新機能について、以下のことが分かった。
- クラスタ構築時の設定ファイルに設定値を記載することで設定できる
- 設定値は`KubeadmControlPlane`(kcp)に最終的に効く
- kcpは`Machine`リソースの期限を見てロールアウトする

今回、実機検証では`Machine`リソースの期限のみ更新して確認したが、以下を追加で試してみてもよいと思う（今回はやらない）。
- インストール時の設定ファイルを変更してkcpの値が変わるか
- kcp内の値を大きくした場合、すぐにロールアウトが走るか