Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ products:
ProductsVersion:
- '4.x'
id: KB260800061
i18n:
disableAutoTranslation: true
---

# Recovering ACP Kubernetes Certificates with Kubernetes Certificates Rotator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,32 @@ kind:
products:
- Alauda Container Platform
ProductsVersion:
- 4.x
- '4.x'
id: KB260800061
sourceSHA: a2033d53d40cfea2cec2b03770770d6f1b648791f794b41a3f3b4d6158cb433c
sourceSHA: 261c8931ef707b68b60da93af1f5e6e1059ff45f9fa979ed4ca695dc4090d33f
---

# 使用 Kubernetes 证书轮换器恢复 ACP Kubernetes 证书
# 使用 Kubernetes Certificates Rotator 恢复 ACP Kubernetes 证书

## 问题

Kubernetes 证书轮换器发放短期证书后,卸载插件不会恢复之前的长期证书。已写入节点的证书保持不变,并且在移除插件后自动续订停止
Kubernetes Certificates Rotator 已经签发短有效期证书后,卸载插件不会自动恢复之前的长有效期证书。节点上已经写入的证书保持不变,插件移除后也不会再发生自动续期

此操作步骤用于经过批准的紧急恢复。它使用集群当前的 CA 证书和私钥重新签署现有证书。这不是标准的维护操作,也不会扩展 CA 本身
本文步骤只用于经过批准的紧急恢复。它使用集群当前的 CA 证书和私钥重新签发现有证书,不是日常维护操作,也不会延长 CA 自身的有效期

## 环境

此操作步骤适用于使用 kubeadm 风格文件的 ACP 集群,文件位于 `/etc/kubernetes` 下,并且具有由 Kubernetes 证书轮换器提供的 `cert-renew` 工具文件。插件命名空间通常为 `cpaas-system`;在使用不同版本的工具之前,请确认已安装的版本和镜像标签
本文适用于使用 kubeadm 风格 `/etc/kubernetes` 文件布局,并且已经由 Kubernetes Certificates Rotator 交付 `cert-renew` 工具文件的 ACP 集群。插件命名空间通常是 `cpaas-system`;执行前先确认已安装插件的版本和镜像标签,不要直接使用其他版本的工具

在集群中的每个节点上单独运行恢复,包括所有控制平面和工作节点。该脚本仅更改运行它的节点上的本地文件;在一个节点上运行不会更新其他节点。工作节点通常没有 CA 私钥由于脚本需要 CA 私钥,批准的恢复计划必须定义如何在每个工作节点上提供、保护和移除该密钥
恢复操作必须在集群中的每个节点上分别执行,包括所有控制平面节点和工作节点。该脚本只修改当前节点的本地文件,在一台节点上执行不会更新其他节点。工作节点通常没有 CA 私钥由于脚本需要 CA 私钥才能运行,获批的恢复方案必须明确规定如何临时提供、保护并清理工作节点上的 CA 私钥

## 解决方案

### 1. 验证交付的工具
### 1. 确认交付的工具

插件镜像提供 `cert-renew` 和 `renew-all.sh`。从前端 Pod 或匹配的 OCI 镜像中获取这两个文件,然后将它们复制到每个目标节点。不要在主机的 `/cluster-cert-rotator/download` 中查找它们
插件镜像提供 `cert-renew` 和 `renew-all.sh`。从 `frontend` Pod 或匹配的 OCI 镜像中获取这两个文件,再传到每个目标节点;不要在宿主机的 `/cluster-cert-rotator/download` 路径下查找

检查 ConfigMap,然后使用准备好的前端 Pod 导出工具文件:
先检查配置映射,然后从一个就绪的 `frontend` Pod 导出工具文件:

```bash
PLUGIN_NAMESPACE=${PLUGIN_NAMESPACE:-cpaas-system}
Expand All @@ -50,13 +50,13 @@ kubectl -n "${PLUGIN_NAMESPACE}" cp -c alauda-console \
chmod 755 ./cert-renew-files/cert-renew ./cert-renew-files/renew-all.sh
```

通过站点批准的文件传输路径将这两个文件传输到每个目标节点,例如传输到 `/var/tmp/cluster-cert-rotator/`。以 root 身份从主机运行这些文件。不要期望这些文件会自动出现在主机上。该镜像是无发行版的且非 root。它不是一个容器化的恢复作业,因为脚本需要主机的 Bash、证书路径和 `systemctl`。
将这两个文件通过站点批准的文件传输方式传到每个目标节点,例如 `/var/tmp/cluster-cert-rotator/`,再以 root 用户身份在宿主机执行。不能假设宿主机上会自动出现文件。该镜像是 distroless、非 root 镜像,不是可以直接运行的容器化恢复作业:脚本需要宿主机的 Bash、证书路径和 `systemctl`。

#### 在未安装插件时获取工具
#### 插件未安装时获取工具

如果未安装插件,请在具有注册表访问权限的管理工作站上获取匹配的 `ait/cert-renew:<tag>` OCI 镜像,然后提取 `cert-renew` 和 `renew-all.sh`:
如果插件未安装,应在有镜像仓库访问权限的管理工作站获取匹配的 `ait/cert-renew:<tag>` OCI 镜像,并从中提取 `cert-renew` 和 `renew-all.sh`:

例如,使用 `skopeo` 将镜像复制到临时目录,然后从镜像层中提取工具文件
例如,使用 `skopeo` 将镜像保存到临时目录,再从镜像层中提取工具文件

```bash
IMAGE=build-harbor.alauda.cn/ait/cert-renew:<installed-tag>
Expand All @@ -74,7 +74,7 @@ extract_from_image() {
return 0
fi
done
echo "${name} ${IMAGE} 中未找到" >&2
echo "${name} was not found in ${IMAGE}" >&2
return 1
}

Expand All @@ -83,11 +83,11 @@ extract_from_image renew-all.sh ./cert-renew-files/renew-all.sh
chmod 755 ./cert-renew-files/cert-renew ./cert-renew-files/renew-all.sh
```

对于 arm64 目标,将 `--override-arch amd64` 更改为 `--override-arch arm64`。验证镜像标签与已安装的插件版本,然后通过批准的路径将提取的文件传输到每个目标节点
目标节点为 arm64 时将 `--override-arch amd64` 改为 `--override-arch arm64`。核对镜像标签与已安装插件版本一致,再通过批准的路径将提取出的文件传到每个目标节点

### 2. 检查 CA 有效性
### 2. 检查 CA 有效期

由 CA 签署的证书在该 CA 过期后不能保持有效。在选择持续时间之前检查所有三个 CA 证书:
由 CA 签发的证书不能在 CA 过期后继续使用。选择有效期前检查三套 CA 证书:

```bash
for ca in \
Expand All @@ -99,11 +99,11 @@ for ca in \
done
```

将 `SAFE_DAYS` 设置为从当前时间到最早 CA `notAfter` 的完整天数,减去操作安全边际。仅在每个相关 CA 至少还有十年时使用固定值 `3650`;这在 kubeadm 集群中并不常见。如果 CA 已过期或其私钥不可用,请停止。此操作步骤无法修复 CA。请使用单独的 CA 轮换或集群恢复计划
将 `SAFE_DAYS` 设为从当前时间到最早 CA `notAfter` 的完整天数,再减去一个运维安全余量。只有所有相关 CA 都至少剩余十年时,固定使用 `3650` 才成立;对于 kubeadm 集群通常不能这样假设。如果 CA 已经过期,或 CA 私钥不可用,应停止操作:该流程不能修复 CA,需要单独的 CA 轮换或集群恢复方案

### 3. 备份节点文件
### 3. 备份节点资源

该工具会就地重写文件。在每个节点上,在进行更改之前创建受保护的备份。直到该节点通过恢复后检查之前,请保留备份
工具会原地改写文件。必须在每个节点修改前创建受保护的备份,并在该节点恢复验证通过前保留

```bash
BACKUP_DIR=/var/backups/cluster-cert-rotator/$(date +%Y%m%d%H%M%S)
Expand All @@ -115,43 +115,43 @@ if [ -f /root/.kube/config ]; then
fi
```

备份包含 CA 私钥。限制对备份的访问。仅根据站点批准的敏感备份保留程序删除它
备份中包含 CA 私钥。必须按站点对敏感备份的保留规则限制访问,并在允许的清理时点处理

### 4. 在每个节点上运行恢复
### 4. 在每个节点执行恢复

首先列出集群节点并创建逐节点执行检查表
先列出集群节点,建立逐节点执行清单

```bash
kubectl get nodes -o wide
```

然后,在检查表中的每个节点上,使用显式持续时间和交付工具的绝对路径运行脚本
然后在清单中的每个节点上显式传入有效期和工具文件的绝对路径

```bash
SAFE_DAYS=<CA-限制的天数>
SAFE_DAYS=<CA-bounded-days>
TOOL_DIR=/cluster-cert-rotator/download

env CERT_DAYS="${SAFE_DAYS}" \
CERT_RENEW_TOOL="${TOOL_DIR}/cert-renew" \
bash "${TOOL_DIR}/renew-all.sh"
```

该脚本使用主 CA 更新 API 服务器和 kubelet 文件,使用 etcd CA 更新 etcd 文件,使用前端代理 CA 更新 `front-proxy-client.crt`。当存在时,它会更新以下文件
脚本使用主 CA 处理 API 服务器和 kubelet 文件,使用 etcd CA 处理 etcd 文件,使用 front-proxy CA 处理 `front-proxy-client.crt`。以下文件存在时会尝试更新

- `apiserver.crt`、`apiserver-kubelet-client.crt`、`kubelet.crt``kubelet-client-current.pem`
- `admin.conf`、`super-admin.conf`、`controller-manager.conf`、`scheduler.conf``/root/.kube/config`
- `etcd/server.crt`、`etcd/peer.crt``apiserver-etcd-client.crt`
- `apiserver.crt`、`apiserver-kubelet-client.crt`、`kubelet.crt``kubelet-client-current.pem`
- `admin.conf`、`super-admin.conf`、`controller-manager.conf`、`scheduler.conf``/root/.kube/config`
- `etcd/server.crt`、`etcd/peer.crt``apiserver-etcd-client.crt`
- `front-proxy-client.crt`

对于嵌入客户端证书的 kubeconfig,该工具会替换证书数据并保留现有私钥。对于引用证书文件的 kubeconfig,该工具会更新引用的文件
对于内嵌客户端证书的 kubeconfig,工具只替换证书数据,保留原有私钥。对于引用外部证书文件的 kubeconfig,工具会更新被引用的证书文件

该脚本会触及 `kube-apiserver`、`kube-controller-manager``kube-scheduler` 静态 Pod 清单,然后重启 kubelet。它不会显式触及 `etcd.yaml`。验证 etcd 健康状况,并单独确定是否需要重启 etcd 或重新加载证书。
脚本会更新 `kube-apiserver`、`kube-controller-manager``kube-scheduler` 三个静态 Pod 清单,然后重启 kubelet。它不会显式更新 `etcd.yaml`;必须单独验证 etcd 健康状态,并确认是否需要重启 etcd 或重新加载证书。

当单个文件更新失败时,脚本不会立即停止。不要将最终的 `完成` 消息视为成功的证明。检查命令输出并完成以下验证步骤
脚本不会在每个文件出错时立即停止。不能把最后的 `Done` 消息当作成功证据,必须检查命令输出并完成下面的验证

### 5. 验证结果

检查每个更改的 PEM 证书和每个 kubeconfig 客户端证书的新有效期。每个新的 `notAfter` 值必须在所选 CA 边界日期之前或等于该日期
检查所有被修改的 PEM 证书和 kubeconfig 客户端证书的新有效期。每个新的 `notAfter` 都必须不晚于选定的 CA 截止日期

```bash
for cert in \
Expand All @@ -170,20 +170,20 @@ for cert in \
done
```

在恢复每个节点后,验证节点和控制平面的健康状况
每个节点完成恢复后,确认节点和控制平面健康状态

```bash
systemctl is-active kubelet
kubectl get nodes
kubectl get pods -n kube-system -o wide
```

检查 kubelet 和控制平面日志以查找重启失败。单独确认 etcd 端点健康。对每个节点重复步骤 3 5。在多控制平面集群中,逐个处理经过批准的控制平面节点,并在继续之前等待控制平面变为健康。根据站点批准的维护顺序逐个处理工作节点
检查 kubelet 和控制平面日志中是否有重启失败,并单独确认 etcd 端点健康状态。对所有节点重复步骤 3 至步骤 5。在多控制平面集群中,按获批顺序逐个控制平面节点执行,每个节点完成后等待控制平面恢复健康再处理下一个节点;工作节点按站点批准的维护顺序逐个处理

## 根本原因

Kubernetes 证书轮换器通过其控制器配置更改请求的持续时间,但移除插件不会重写它已发放的证书。独立的 `cert-renew` 工具使用现有 CA 签署替换证书,并将 `NotAfter` 设置为 `now + days`;它不会检查或限制该值到 CA 过期。有效的生命周期由请求的持续时间或 CA 过期中最早的一个限制
Kubernetes Certificates Rotator 通过控制器配置改变签发有效期,但卸载插件不会改写它已经签发的证书。独立的 `cert-renew` 工具使用现有 CA 重新签发证书,并将 `NotAfter` 设置为 `now + days`;它不会检查或截断为 CA 到期时间。因此实际有效期同时受请求天数和 CA 剩余有效期约束,不能只看请求参数

## 回滚

如果任何节点的恢复后检查失败,请停止更改其他节点并保留命令输出。从受保护的备份中恢复该节点的文件。恢复文件后,重复静态 Pod 和 kubelet 重启操作,然后在继续到另一个节点之前验证 API 服务器、kubelet 和 etcd 的健康状况
如果某个节点恢复后的检查失败,应停止修改其他节点并保留命令输出,从该节点的受保护备份恢复文件。恢复后重新执行相同的静态 Pod 和 kubelet 重启操作,再确认 API 服务器、kubelet 和 etcd 健康状态后,才能继续处理其他节点
Loading