乐于分享
好东西不私藏

Kubernetes 1.35.4 源码修改指南:证书有效期延长至 100 年

Kubernetes 1.35.4 源码修改指南:证书有效期延长至 100 年

Kubernetes 1.35.4 源码修改指南:证书有效期延长至 100 年

适用版本:Kubernetes v1.35.4
修改目标:将 kubeadm 生成的证书有效期从默认的 1 年(组件证书)/ 10 年(CA 证书)延长至 100 年
运行环境:Linux (amd64)、Go 1.25+、Docker(可选)


一、背景说明

kubeadm 初始化集群时,会自动生成一套 PKI 证书体系:

证书类型
默认有效期
影响的证书
CA 根证书
10 年 ca.crt

front-proxy-ca.crtetcd/ca.crt
组件证书
1 年 apiserver.crt

apiserver-kubelet-client.crtetcd/healthcheck-client.crt 等

虽然 kubeadm 提供了 kubeadm certs renew all 命令用于证书续期,但在生产环境中频繁续期仍然是一个运维负担。本文将基于 Kubernetes 1.35.4 源码,详细说明如何通过修改源码并重新编译的方式,从根本上将证书有效期延长至 100 年。


二、Kubernetes 1.35.4 源码关键位置分析

在 v1.35.4 版本中,证书有效期的控制分散在三个关键位置:

2.1 证书有效期常量定义

文件cmd/kubeadm/app/constants/constants.go

// 第 47-50 行
// CertificateValidityPeriod 定义 kubeadm 生成的所有签名证书的有效期(非 CA 证书)
CertificateValidityPeriod = time.Hour * 24 * 365// 默认 1 年

// CACertificateValidityPeriod 定义 kubeadm 生成的所有 CA 证书的有效期
CACertificateValidityPeriod = time.Hour * 24 * 365 * 10// 默认 10 年

2.2 kubeadm 签发证书时使用有效期

文件cmd/kubeadm/app/util/pkiutil/pki_helpers.go

// 第 624 行 - 签发非 CA 证书(apiserver、etcd 等组件证书)
notAfter := notBefore.Add(kubeadmconstants.CertificateValidityPeriod)

// 第 667 行 - 签发自签名 CA 证书(ca、front-proxy-ca、etcd-ca)
notAfter := notBefore.Add(kubeadmconstants.CACertificateValidityPeriod)

2.3 client-go 通用 CA 证书工具

文件staging/src/k8s.io/client-go/util/cert/cert.go

// 第 40 行
const duration365d = time.Hour * 24 * 365

// 第 79 行 - NewSelfSignedCACert 函数内
NotAfter: now.Add(duration365d * 10).UTC(),  // 默认 10 年

此文件位于 staging 目录中,是独立的 Go 模块(k8s.io/client-go),被 kubelet、controller-manager 等组件引用。修改此处影响范围更广。


三、修改步骤(可直接复制执行)

步骤 1:进入源码目录并确认当前配置

# 进入 kubernetes 源码根目录
cd /path/to/kubernetes

# 确认修改前的默认值
grep -n "CertificateValidityPeriod\|CACertificateValidityPeriod" cmd/kubeadm/app/constants/constants.go

步骤 2:修改证书有效期常量(核心修改)

修改 ①:kubeadm 常量 — 组件证书有效期 1 年 → 100 年

文件cmd/kubeadm/app/constants/constants.go 第 48 行

# macOS 使用以下命令(Linux 将 sed -i '' 改为 sed -i)
sed -i '''s/CertificateValidityPeriod = time.Hour \* 24 \* 365$/CertificateValidityPeriod = time.Hour * 24 * 365 * 100/' \
  cmd/kubeadm/app/constants/constants.go

修改后效果:

// 修改前
CertificateValidityPeriod = time.Hour * 24 * 365// 1 年

// 修改后
CertificateValidityPeriod = time.Hour * 24 * 365 * 100// 100 年

修改 ②:kubeadm 常量 — CA 证书有效期 10 年 → 100 年

文件cmd/kubeadm/app/constants/constants.go 第 50 行

# macOS 使用以下命令(Linux 将 sed -i '' 改为 sed -i)
sed -i '''s/CACertificateValidityPeriod = time.Hour \* 24 \* 365 \* 10$/CACertificateValidityPeriod = time.Hour * 24 * 365 * 100/' \
  cmd/kubeadm/app/constants/constants.go

修改后效果:

// 修改前
CACertificateValidityPeriod = time.Hour * 24 * 365 * 10// 10 年

// 修改后
CACertificateValidityPeriod = time.Hour * 24 * 365 * 100// 100 年

修改 ③:client-go CA 证书有效期 10 年 → 100 年

文件staging/src/k8s.io/client-go/util/cert/cert.go 第 79 行

# macOS 使用以下命令(Linux 将 sed -i '' 改为 sed -i)
sed -i '''s/NotAfter:              now.Add(duration365d \* 10).UTC(),/NotAfter:              now.Add(duration365d * 100).UTC(),/' \
  staging/src/k8s.io/client-go/util/cert/cert.go

修改后效果:

// 修改前
NotAfter:              now.Add(duration365d * 10).UTC(),   // 10 年

// 修改后
NotAfter:              now.Add(duration365d * 100).UTC(),  // 100 年

步骤 3:验证修改结果

# 验证所有修改是否生效
echo"=== constants.go 修改结果 ==="
grep -n "CertificateValidityPeriod\|CACertificateValidityPeriod" cmd/kubeadm/app/constants/constants.go

echo""
echo"=== cert.go 修改结果 ==="
grep -n "NotAfter.*now.Add" staging/src/k8s.io/client-go/util/cert/cert.go

预期输出:

=== constants.go 修改结果 ===
48:    CertificateValidityPeriod = time.Hour * 24 * 365 * 100
50:    CACertificateValidityPeriod = time.Hour * 24 * 365 * 100

=== cert.go 修改结果 ===
79:        NotAfter:              now.Add(duration365d * 100).UTC(),

四、编译 kubeadm(支持 amd64 和 arm64)

macOS 前置依赖

macOS 默认的 tar 是 BSD 版本,Kubernetes 构建系统要求 GNU tar。编译前先安装:

# 安装 GNU 工具链
brew install gnu-tar

# 确认 GNU tar 可用(若安装在 /opt/homebrew/opt/gnu-tar/libexec/gnubin 则需加入 PATH)
which gtar || echo'export PATH="/opt/homebrew/opt/gnu-tar/libexec/gnubin:$PATH"' >> ~/.zshrc

Kubernetes 1.35.4 的 kubeadm 属于 Server 类组件,官方支持的编译目标平台为:

架构
平台标识
典型部署环境
x86_64
linux/amd64
Intel/AMD 服务器、主流云主机
ARM64
linux/arm64
树莓派、鲲鹏、Graviton、M 系列 Mac 虚拟机

方法一:本地 Go 环境编译(推荐)

macOS 注意:确保 GNU tar 已安装(brew install gnu-tar),否则构建脚本校验阶段会报错 Cannot find GNU tar

1.1 仅编译当前架构

# 确保 Go 版本 >= 1.25.0
go version

# 编译 kubeadm(自动识别当前 CPU 架构,产物位于 _output/bin/kubeadm)
make WHAT=cmd/kubeadm GOFLAGS=-v

# 查看编译后的版本和架构信息
_output/bin/kubeadm version
file _output/bin/kubeadm

1.2 同时编译 amd64 和 arm64(交叉编译)

# 设置目标平台列表,用空格分隔
export KUBE_BUILD_PLATFORMS="linux/amd64 linux/arm64"

# 编译 kubeadm,同时输出两个架构的二进制文件
make WHAT=cmd/kubeadm GOFLAGS=-v

编译产物输出路径:

# 编译完成后,产物按平台分别存放
_output/bin/linux/amd64/kubeadm    # x86_64 二进制
_output/bin/linux/arm64/kubeadm    # ARM64 二进制

# 查看各架构文件信息
file _output/bin/linux/amd64/kubeadm
# 输出:kubeadm: ELF 64-bit LSB executable, x86-64 ...

file _output/bin/linux/arm64/kubeadm
# 输出:kubeadm: ELF 64-bit LSB executable, ARM aarch64 ...

提示:macOS (darwin) 交叉编译 Linux 目标需要 Go 交叉编译工具链支持,Go 1.25 已内置,无需额外配置。

1.3 单独编译某个架构

# 仅编译 amd64
KUBE_BUILD_PLATFORMS="linux/amd64" make WHAT=cmd/kubeadm GOFLAGS=-v

# 仅编译 arm64
KUBE_BUILD_PLATFORMS="linux/arm64" make WHAT=cmd/kubeadm GOFLAGS=-v

1.4 编译其他组件

# 编译单个组件(当前架构)
make WHAT=cmd/kubelet GOFLAGS=-v        # kubelet
make WHAT=cmd/kube-apiserver GOFLAGS=-v # kube-apiserver
make WHAT=cmd/kubectl GOFLAGS=-v        # kubectl

# 同时编译多个组件 + 多架构
KUBE_BUILD_PLATFORMS="linux/amd64 linux/arm64" \
  make WHAT="cmd/kubeadm cmd/kubelet cmd/kubectl" GOFLAGS=-v

# 编译所有组件(耗时较长)
make all

方法二:容器化编译(无需本地 Go 环境,天然支持多架构)

如果不希望配置本地 Go 开发环境,可以使用 Kubernetes 官方编译镜像(内置所有交叉编译工具链):

# 在源码根目录执行,启动编译容器
cd build/

# 编译当前架构的 kubeadm
./run.sh make kubeadm

# 同时编译 amd64 和 arm64
KUBE_BUILD_PLATFORMS="linux/amd64 linux/arm64" ./run.sh make kubeadm

# 产物与本地编译路径一致
ls -lh ../_output/bin/linux/amd64/kubeadm
ls -lh ../_output/bin/linux/arm64/kubeadm

build/run.sh 会自动拉取匹配当前源码版本的 registry.k8s.io/build-image/kube-cross 镜像,该镜像已预置所有目标平台的交叉编译工具链,在容器内完成编译。


方法三:Docker 手动指定平台编译

# 拉取编译镜像(以 go.work 中指定的 Go 1.25 为准)
docker pull registry.k8s.io/build-image/kube-cross:v1.35.0-go1.25.0-bullseye.0

# 编译 amd64 和 arm64
docker run --rm \
  -v $(pwd):/go/src/k8s.io/kubernetes \
  -w /go/src/k8s.io/kubernetes \
  -e KUBE_BUILD_PLATFORMS="linux/amd64 linux/arm64" \
  registry.k8s.io/build-image/kube-cross:v1.35.0-go1.25.0-bullseye.0 \
  make WHAT=cmd/kubeadm GOFLAGS=-v

编译产物汇总

编译完成后,产物目录结构如下:

_output/bin/
├── linux/
│   ├── amd64/
│   │   └── kubeadm          # x86_64 可执行文件(≈ 45 MB)
│   └── arm64/
│       └── kubeadm          # ARM64 可执行文件(≈ 42 MB)

部署时根据目标节点架构选择对应的二进制文件即可:

# amd64 节点部署
scp _output/bin/linux/amd64/kubeadm root@<amd64-node>:/usr/bin/kubeadm

# arm64 节点部署
scp _output/bin/linux/arm64/kubeadm root@<arm64-node>:/usr/bin/kubeadm

五、部署与验证

5.1 备份现有环境(重要!)

# 备份原始 kubeadm 二进制
cp /usr/bin/kubeadm /usr/bin/kubeadm.bak.$(date +%Y%m%d)

# 备份当前证书目录
cp -r /etc/kubernetes/pki /etc/kubernetes/pki.bak.$(date +%Y%m%d)

5.2 替换 kubeadm 二进制

# 将编译好的 kubeadm 复制到系统路径
cp _output/bin/kubeadm /usr/bin/kubeadm
chmod +x /usr/bin/kubeadm

# 确认版本
kubeadm version

5.3 场景一:初始化新集群(自动使用 100 年有效期)

直接使用修改后的 kubeadm 初始化集群,生成的证书自动为 100 年有效期:

kubeadm init \
  --kubernetes-version=v1.35.4 \
  --pod-network-cidr=10.244.0.0/16 \
  --apiserver-advertise-address=<your-api-server-ip>

初始化完成后验证证书有效期:

# 查看所有证书到期时间
kubeadm certs check-expiration

# 查看单个证书详情(验证是否为 100 年)
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -noout | grep -A2 "Validity"
openssl x509 -in /etc/kubernetes/pki/ca.crt -text -noout | grep -A2 "Validity"
openssl x509 -in /etc/kubernetes/pki/front-proxy-ca.crt -text -noout | grep -A2 "Validity"

预期输出示例(100 年有效期):

Validity
    Not Before: May  6 08:00:00 2026 GMT
    Not After : May  3 08:00:00 2126 GMT

5.4 场景二:已有集群更新证书

如果集群已经存在,使用修改后的 kubeadm 续期所有证书:

# 第一步:续期所有证书(将使用新的 100 年有效期)
kubeadm certs renew all

# 第二步:验证续期结果
kubeadm certs check-expiration

# 第三步:重启控制平面组件(静态 Pod 管理方式)
# 方法 A:移走 manifest 再移回(推荐、安全)
mkdir -p /root/k8s-manifest-backup
mv /etc/kubernetes/manifests/*.yaml /root/k8s-manifest-backup/
sleep 10  # 等待旧 Pod 停止
mv /root/k8s-manifest-backup/*.yaml /etc/kubernetes/manifests/

# 方法 B:直接重启 kubelet
systemctl restart kubelet

# 第四步:更新本地 kubectl 配置
cp /etc/kubernetes/admin.conf ~/.kube/config

# 第五步:验证集群状态
kubectl get nodes
kubectl get pods -A

5.5 场景三:更新 kubeconfig 文件中的客户端证书

# kubeadm 生成的 kubeconfig 文件内嵌了客户端证书
# 需要重新生成以确保客户端证书也使用 100 年有效期

# 重新生成 admin.conf(100 年 = 876600 小时)
kubeadm kubeconfig user --client-name=kubernetes-admin --validity-period=876600h

# 或者重新生成所有 kubeconfig 文件
kubeadm init phase kubeconfig all --config=kubeadm-config.yaml

提示:kubeadm v1.35.4 已支持通过 --validity-period 参数指定 kubeconfig 证书有效期,但由于已修改常量,默认值即为 100 年,无需额外指定。


六、编译容器镜像(可选,替换控制平面组件)

如果需要替换控制平面组件的容器镜像(使 kube-apiserver、kube-controller-manager、kube-scheduler 也使用修改后的代码):

# 编译所有组件
make all

# 使用官方脚本构建镜像
KUBE_DOCKER_REGISTRY=your-registry.example.com \
KUBE_BUILD_CONFORMANCE=n \
  build/release-images.sh

# 生成的镜像包括:
# - your-registry.example.com/kube-apiserver:v1.35.4-dirty
# - your-registry.example.com/kube-controller-manager:v1.35.4-dirty
# - your-registry.example.com/kube-scheduler:v1.35.4-dirty
# - your-registry.example.com/kube-proxy:v1.35.4-dirty

使用自定义镜像部署集群:

cat > kubeadm-config.yaml <<EOF
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
imageRepository: your-registry.example.com
kubernetesVersion: v1.35.4
# 以下两个字段可选,因为修改源码后默认值已是 100 年
certificateValidityPeriod: 876600h     # 100 年 = 365 * 24 * 100
caCertificateValidityPeriod: 876600h   # 100 年
EOF


kubeadm init --config=kubeadm-config.yaml

七、常见问题与排查

7.1 编译报错:Go 版本不匹配

# 查看 go.work 要求的 Go 版本
head -5 go.work

# 确保本地 Go 版本匹配
go version

# 版本不匹配时切换到容器化编译方式(方法二或方法三)

7.2 编译产物找不到

# 确认编译产物位置(默认在 _output/bin/ 下)
ls -lh _output/bin/

# 自定义输出路径示例
make WHAT=cmd/kubeadm OUT_DIR=_custom_output

7.3 证书续期后 apiserver 无法启动

# 验证证书链是否完整
openssl verify -CAfile /etc/kubernetes/pki/ca.crt /etc/kubernetes/pki/apiserver.crt

# 查看 apiserver 容器日志
crictl logs $(crictl ps --name kube-apiserver -q)

# 确保证书目录权限正确
ls -la /etc/kubernetes/pki/

7.4 恢复原始 kubeadm(回滚操作)

# 恢复备份的 kubeadm 二进制
cp /usr/bin/kubeadm.bak.20260506 /usr/bin/kubeadm

# 恢复备份的证书
rm -rf /etc/kubernetes/pki
cp -r /etc/kubernetes/pki.bak.20260506 /etc/kubernetes/pki

# 重启 kubelet 使静态 Pod 生效
systemctl restart kubelet

八、修改文件总览

序号
文件路径
行号
修改内容
影响范围
1
cmd/kubeadm/app/constants/constants.go
48
* 365

 → * 365 * 100
kubeadm 生成的组件证书(apiserver, etcd 等)
2
cmd/kubeadm/app/constants/constants.go
50
* 365 * 10

 → * 365 * 100
kubeadm 生成的 CA 证书(ca, front-proxy-ca, etcd-ca)
3
staging/src/k8s.io/client-go/util/cert/cert.go
79
duration365d * 10

 → duration365d * 100
client-go 工具生成的 CA 证书(kubelet 等组件调用)

九、Kubernetes 1.35.4 完整调用链说明

理解调用链有助于判断修改是否完整覆盖所有证书生成路径:

kubeadm init / kubeadm certs renew
    │
    ├── phases/certs/certlist.go (GetConfig 方法)
    │   ├── 读取 CertificateValidityPeriod → 设置非 CA 证书 NotAfter
    │   └── 读取 CACertificateValidityPeriod → 设置 CA 证书 NotAfter
    │
    ├── util/pkiutil/pki_helpers.go
    │   ├── NewSignedCert() 函数 第 624 行
    │   │   └── notAfter = notBefore.Add(CertificateValidityPeriod)  ← 常量
    │   └── NewSelfSignedCACert() 函数 第 667 行
    │       └── notAfter = notBefore.Add(CACertificateValidityPeriod) ← 常量
    │
    └── phases/kubeconfig/kubeconfig.go 第 476 行
        └── notAfter = startTime.Add(CertificateValidityPeriod)  ← 生成 kubeconfig 证书

client-go(staging 模块,被 kubelet 等组件引用)
    └── util/cert/cert.go → NewSelfSignedCACert() 第 79 行
        └── NotAfter: now.Add(duration365d * 10)  ← 硬编码,需单独修改

十、其他可自定义参数说明

在 kubeadm v1.35.4 中,除了证书有效期常量外,还可以通过以下参数影响证书生成:

参数
配置位置
说明
CertificateBackdate constants.go:46
证书签发回溯时间,默认 5 分钟(time.Minute * 5),用于应对节点间时间偏移
EncryptionAlgorithm v1beta4/defaults.go:61
证书加密算法,默认 RSA-2048(可改为 RSA-4096)
certificateValidityPeriod
kubeadm 配置文件
运行时覆盖组件证书有效期,需 ≥ 修改后的常量值
caCertificateValidityPeriod
kubeadm 配置文件
运行时覆盖 CA 证书有效期,需 ≥ 修改后的常量值

如需进一步自定义,可修改对应的常量或配置文件字段。


十一、总结

通过修改 3 个文件中的 3 处关键代码,即可将 Kubernetes 1.35.4 集群的证书有效期从默认的 1~10 年延长至 100 年。核心操作流程:

  1. 1. 修改常量 — constants.go 中的 CertificateValidityPeriod 和 CACertificateValidityPeriod 各乘以 100
  2. 2. 修改底层工具 — cert.go 中的 CA 证书默认有效期乘以 100
  3. 3. 重新编译 — make WHAT=cmd/kubeadm 编译新二进制
  4. 4. 替换部署 — 用新编译的 kubeadm 初始化集群或续期已有证书

所有 sed 命令可直接复制执行,无需手动编辑文件,确保修改的一致性和可重复性。

免责声明:本文档仅供技术研究和学习参考。修改 Kubernetes 源码可能影响集群的合规性和安全性,请在生产环境操作前充分测试。