kubeadm 修改默认证书有效期
前言
出于安全考虑,k8s 团队推荐定期更新版本,因此kubeadm生成的证书,有效期默认在代码中写死为1年,一旦证书过期,k8s集群将会崩溃,因此,续期 or 升级,成了一个一年一度必选题。但在生产环境中,每一次版本更新可能存在未知的风险,给已经稳定运行的集群带来诸多不确定性,而每年续期一次证书,对管理不太友好,频繁手动操作也可能会带来额外的风险。去年部署的1.14的集群,证书快要到期了,现在决定修改kubeadm的源码重新编译,将续期证书的有效期进行延长。本篇记载分析源码中证书更新的过程。
修改源码
准备
首先拉取代码,切换到指定k8s版本的tag,过程参考之前源码分析的第一篇文章:
[k8s源码阅读笔记-准备工作
](https://github.com/yinwenqin/kubeSourceCodeNote/blob/master/README.md)
也可直接下载相应版本的源码压缩包:
wget https://codeload.github.com/kubernetes/kubernetes/tar.gz/v1.14.3
代码结构
kubeadm代码结构如下,我们根据cmd命令入手,来找相应的生成证书的逻辑具体在哪。
证书生成方式分为两种,一种是执行kubeadm init
命令初始化生成的证书,一种是执行kubeadm alpha certs renew
,分别来看下。
Init证书
根据cmd的语义,可以很方便的找到相应的逻辑在哪个文件内,例如kubeadm init
命令的逻辑,在cmd/kubeadm/app/cmd/init.go
文件内。
通过函数名称,可以很容易辨认哪个是证书操作的函数,一级一级地查找:
cmd/kubeadm/app/cmd/init.go:176
initRunner.AppendPhase(phases.NewCertsPhase())
==> cmd/kubeadm/app/cmd/phases/init/certs.go:62
Phases: newCertSubPhases()
==> cmd/kubeadm/app/cmd/phases/init/certs.go:96
return certsphase.CreateCertAndKeyFilesWithCA(cert, caCert, cfg)
==> cmd/kubeadm/app/phases/certs/certs.go:161
1 | // 这里分两步,第一步生成证书 ,第二步,证书写入磁盘 |
CreateFromCA函数分为两步,第一步生成证书 ,第二步,证书写入磁盘。生成证书这里使用的是单独的封装pkiutil.NewCertAndKey()方法,猜测多个地方会使用到它。
生成证书
cmd/kubeadm/app/util/pkiutil/pki_helpers.go:76
==> cmd/kubeadm/app/util/pkiutil/pki_helpers.go:82
==> cmd/kubeadm/app/util/pkiutil/pki_helpers.go:557
1 | // NewSignedCert creates a signed certificate using the given CA certificate and key |
这里是init证书默认定义有效期的位置,renew证书应该也是调用的这里,是不是呢?还是再来确认一下。
Renew证书
根据cmd的语义,可以很方便的找到相应的逻辑在哪个文件内,例如kubeadm alpha certs renew
命令的逻辑,在cmd/kubeadm/app/cmd/alpha/certs.go
文件内。
通过函数名称,可以很容易初步锁定在newCmdCertsRenewal()
函数,再开始一级一级地查找:
cmd/kubeadm/app/cmd/alpha/certs.go:60
==> cmd/kubeadm/app/cmd/alpha/certs.go:68
==> cmd/kubeadm/app/cmd/alpha/certs.go:99
1 | // get the implementation of renewing this certificate |
==> cmd/kubeadm/app/cmd/alpha/certs.go:151
1 | // 更新已存在的证书 |
==> cmd/kubeadm/app/phases/certs/renewal/renewal.go:42
1 | newCert, newKey, err := impl.Renew(cfg) |
这里发现impl.Renew()是个接口方法,倒回上一级去查看impl
==> cmd/kubeadm/app/cmd/alpha/certs.go:148
1 | renewer, err := getRenewer(cfg, caCert.BaseName) |
==> cmd/kubeadm/app/cmd/alpha/certs.go:166
1 | func getRenewer(cfg *renewConfig, caCertBaseName string) (renewal.Interface, error) { |
这里的证书刷新方式分为两种,一种是k8s自管理式的证书,一种是本地文件证书(默认/etc/kubernetes/pki/
),两种方式有何差别,参考官方文档:
Certificate Management with kubeadm
自管理的证书有效期默认3个月。而一般使用的都是本地证书文件,所以直接看第二种
cmd/kubeadm/app/phases/certs/renewal/filerenewal.go:34
1 | // NewFileRenewal takes a certificate pair to construct the Interface. |
Renew方法在下面,果然,也是调用的 pkiutil.NewCertAndKey()
方法,也即是说,在上面修改那一行代码,init和renew的时候生成证书都会调用,都会生效。
修改完成,开始重新编译!
编译
go环境问题这里不赘述了,网上文章很多,跳过。
如果是linux,直接执行:
1 | make WHAT=cmd/kubeadm GOFLAGS=-v |
如果是mac,执行:
1 | make cross WHAT=cmd/kubeadm GOFLAGS=-v |
报错:
1 | ./hack/run-in-gopath.sh:行33: _output/bin/deepcopy-gen: 权限不够 |
解决办法:
1 | chmod +x _output/bin/deepcopy-gen |
重新编译,执行完成后,编译好的二进制文件路径为:
1 | ./_output/local/bin/linux/amd64/kubeadm |
使用此文件,覆盖原来的kubeadm文件:
1 | mv /usr/bin/kubeadm /usr/bin/kubeadm-bak |
验证
init
先看看kubeadm init时创建的证书
1 | [root@vm254011 ~]# kubeadm init --config kubeadmin-config.yaml |
可以看到,证书有效期为10年(默认时间为UTC时间,实际本地时区为UTC+8)
renew
过了一个晚上,再来对上面init创建的证书进行renew:
1 | # 因为我的环境里etcd不是static pod托管,而是外部二进制部署的,所以这里不需要更新etcd的证书 |
可以看到,renew的证书,有效期也是长达10年的。