- 深入理解Kubernetes 4A - Authentication源码解析
- 深入理解Kubernetes 4A - Authorization源码解析
- 深入理解Kubernetes 4A - Admission Control源码解析
- 深入理解Kubernetes 4A - Audit源码解析
- TLS Everywhere - 解密kubernetes集群的安全认证
所有关于Kubernetes 4A部分代码上传至仓库 github.com/cylonchau/hello-k8s-4A
在 kubernetes 集群中,所有的通讯都是用 TLS 进行加密和认证,本文使用一次老集群(二进制部署集群)证书更换作为记录,通过这种方式深入对 kubernetes 的认证方式来了解更换证书的步骤,以及一次模拟老集群的更换步骤。
本文使用证书生成工具为 “kubernetes-generator” [1] 专用于 k8s 二进制部署生成证书和安装包的工具。
Kubernetes认证方式
为了了解证书更换需要做那些步骤,所以必须了解 k8s 的认证方式,这样才能更好的在更换证书时对集群上部署的业务系统的影响降低到最低。
X509 证书
kube-apiserver 的启动参数 --client-ca-file
,可以使用客户端办法机构,英文代号就是熟悉的 “CA” (Certificate authority),当这个证书传递后,可以验证 kube-apiserver 用于验证向 kube-apiserver 提供的客户端证书,这里包含 k8s 中提供的用户种类的两种:
- 用户名:对应证书的 CN (Common Name)
- 用户组:对应证书的O (organization),用于对一个用户组进行授权,例如 “system:masters” 表示一个组 [1],允许不受限制地访问 kube-apiserver
静态token
kube-apiserver 的启动参数 --token-auth-file
,是以文件提供给 kube-apiserver,该 Token 会长期有效,并且如果不重启服务 Token 是不会更新。
令牌文件的定义必须符合 [a-z0-9]{6}\.[a-z0-9]{16}
的格式,以 “.” 分割,第一部分是 “Token ID”; 第二部分是“令牌秘密(Token Secret” ;其后是这个用户的 Group,Group 可以包含多个,如果包含多个,则对应的列必须用双引号括起来。
|
|
例如
|
|
system:masters
除非有必要,否则,应避免向该组分发证书。该组用户无法通过 ClusterRole 和 clusterRoleBinding 来控制权限,即使删除了所有集群角色,或者从来就没有分配过集群角色。该组的用户,仍然可以直接请求 kube-apiserver 执行任何操作。使用时可以这样传入
|
|
Bootstrap Tokens
Bootstrap Tokens 和 “静态Token”是属于相同类型,并存在于kube-system
名称空间中 Secret, 他的类型是 bootstrap.kubernetes.io/token
,==这种设计是为了能够支持 kubeadm
==。 的情况下启动集群。[3]
Bootstrap Tokens 和 静态 token 是相同的格式类型,这里就不多做阐述。
这里我们看一下我们生成的 kubelet 相关证书与配置文件
$ cat kubelet
# kubernetes kubelet config
#
# You can add your configuration own!
KUBELET_ARGS="--v=0 \
--logtostderr=true \
--network-plugin=cni \
--config=/etc/kubernetes/kubelet-config.yaml \
--kubeconfig=/etc/kubernetes/auth/kubelet.conf \
--cgroup-driver=cgroupfs \
--bootstrap-kubeconfig=/etc/kubernetes/auth/bootstrap.conf"
再查看一下 /etc/kubernetes/auth/bootstrap.conf
的配置文件
|
|
可以用命令去求证 certificate-authority-data 是否与 CA 一致。
|
|
使用命令可以查询到这个 bootstrap token 可以操作的权限
|
|
因为我们在创建集群时,手动执行过这条命令
|
|
这是我们在证书生成脚本中的定义的用户与组
|
|
system:bootstrappers
组会被默认添加例如 kubeadm 是使用了 controller-manager 中的 CSRApprovingController 自动对 bootstrap token 进行的签发。当接收到 CSR 时,CSRApprovingController 会验证他的 CSR 的合法性。可以从代码中看出。
|
|
上述代码中表明了 CSR 的签发需满足的条件:
- SAN Email, IP, URI 必须不提供。
- 证书的 Organization 字段必须为
system:nodes
,例如: O = system:nodes - 证书的 commonName 字段必须为
sytem:node:
开头,通常格式定义为 sytem:node:hostname,例如: CN = system:node:debian-demo。 - 证书 Usage 必须配置 client auth 和 digital signature, 这部分在生成脚本中有配置。
这里做一个小实验,创建一个 匹配上述条件的 CSR,并使用 CertificateSigningRequest 去申请一个证书。
使用 cfssl 工具准备 CSR
|
|
使用 openssl 工具准备 CSR
|
|
查看 demo.csr 的详情
|
|
使用 bootstrap token吧 CSR 发送给 apiserver 去申请证书, 需要注意的是 csr 资源的版本 旧版本certificates.k8s.io/v1beta1
; certificates.k8s.io/v1
v1.19 。
|
|
在新版本中(v1.19)kube-controller-manager 中的它会自动审批 signerName
为 kubernetes.io/kube-apiserver-client-kubelet
的 CSR [4]。
而旧版本的 CertificateSigningRequest 资源不包含 spec.CertificateSigningRequest
|
|
查看
|
|
可以使用下面命令查看被签发的证书
|
|
kubelet 配置 bootstrap token
如果使用 bootstrap token 需要启用对应的配置,需要具备下列条件:
kube-apiserver 相关配置
- kube-apiserver 启用参数
--enable-bootstrap-token-auth=true
- kube-apiserver 启用参数
kubelet 相关配置
一个用来存储所生成的密钥和证书的路径
一个用来指向尚不存在的
kubeconfig
文件的路径;kubelet 会将 bootstrap token 配置文件放到这个位置。一个指向 bootstrap token 的
kubeconfig
文件的路径,用来提供 API 服务器的 URL 和启动 bootstrap token。
其他认证方式
其他认证方式指的是 serviceaccount, openid, webhook token等方式,因为这些不属于 kubernetes 集群中的基础认证方式,而是属于扩展认证方式,故这里不会在提及。
实验 - 证书更换
构建 kubernetes 1.16.10 实验环境
实验环境使用 kubernetes 1.16.10 来模拟常见的老旧集群(通过二进制方式进行部署)证书过期进行更换的问题。通过上面了解到的“基础认证”方式可以快速做到对集群进行证书更换的问题。
生成证书列表如下
|
|
etcd 证书更换
etcd 证书更换部分主要围绕 etcd 所使用的证书进行规划,例如:
- ca
- server
- peer
- client
这里使用脚本套件会根据 kubernetes 官方给的一个 kubernetes 集群所需要的一套证书的标准进行生成。手动更换即可。更换完成后检查集群状态。
|
|
遇到的问题
|
|
启动后立马停止,这里检查 etcd 证书是否正确。
kube-apiserver 证书更换
kube-apiserver 所使用的配置参数
|
|
注意需要替换的证书部分
|
|
遇到的问题
|
|
报错提示握手认证失败,手动使用 cert 和 key 访问是正常
|
|
原因:注意 etcd ca 是否正确。要确认下面的均为正确配置才可以
|
|
无法查看 pod 日志 You must be logged in to the server
|
|
这个就是上面提到的,要保证 kube-apiserver 和 kubelet 使用的证书是否一致
|
|
kube-controller-manager 证书更换
|
|
除了上面提到的,ca 外,只需要替换 serviceaccount 所需的 key 即可
|
|
kube-scheduler 证书更换
|
|
工作节点证书更换
如果节点使用 bootstrap 证书进行部署的,通常证书不正确 kubelet 会从新自动申请 csr 获取新证书,这部分根据 kubernetes 集群版本不同需要手动进行批准 (kubectl certificate approve)。
另外一种方式就是,手动重新给每一个节点的 kubelet 重新签发证书,并且替换每一个节点的 kube-proxy 的 kubeconfig 文件 (==这里使用的套件是 bootstrap token==)。生成证书的要求按照 bootstrap token 部分介绍的:
- SAN Email, IP, URI 必须不提供。
- 证书的 Organization 字段必须为
system:nodes
,例如: O = system:nodes - 证书的 commonName 字段必须为
sytem:node:
开头,通常格式定义为 sytem:node:hostname,例如: CN = system:node:debian-demo。 - 证书 Usage 必须配置 client auth 和 digital signature, 这部分在生成脚本中有配置。
更换cni使用证书
例如 calico 使用了etcd时,etcd为外部etcd时,这里的证书也要替换,否则 calico-controller 会无法连接etcd,下图是对应的日志。
更换serviceaccount
在 kubernetes 官方的 “手动轮换 CA 证书” [6] 一文中有提到,在更新了 CA 之后,集群内 Pod 需要重启以获得新的 Secret 数据。下图是当 Pod 没有重启时,在启动新 Pod 的报错
network: Unauthorized 原因如下:
- cni node 没有启动
- 旧的 default secret 还是旧的,没办法请求到 apiserver 去创建网络空间
当更换完成证书后,检查 node cni 服务全部没问题,但是新建的Pod无法创建网络,提示 network: Unauthorized;重建了所有的 secret后重启 Pod 就恢复了。这时 kubelet 出现日志如下:
|
|
|
|
遇到的问题
tls: bad certificate 问题原因,更新完成证书后,Pod 中 CA 会更新,但是 secret token 不会自动更新,容器内请求 API 使用 serviceaccount token,当更换 CA 后必须重启 Pod 才能重新在 Pod 内建立新的 token。
|
|
验证上述问题
使用 SA token 访问 API
|
|
未重启过的Pod
|
|
重启更换过 Token 的 Pod
|
|
总结
- 了解了 k8s 集群认证模式(TLS Everywhere)。
- 通过基础知识知道了换证书需要更换那些地方。
- 没有尝试官方提到的滚动更新CA的方式。