CKA考试时可能会遇到一个大题: 大致题意是: 在已经存在的一个Kubernetes Cluster中新增一个Node, 使其加入集群及相关证书可自动续签.
我们一般搭建k8s集群,都使用了一些开源工具来做,这类工具都自动帮我们做了很多事情,因此我们只需要简单执行一条命令后,一个集群就完成搭建了, 非常方便,同时也隐藏了一些k8s的知识点, 比如Bootstarp Token就是上面这道题的考察内容.
要了解Bootstrap Token前,我们要知道Kubernetes集群的认证(Kubernetes)及鉴权(Kubernetes)机制.
Kubernetes中的存在非常多的证书, 原于Kubernetes的有些组件同时充当服务端及客户端, 比如apiserver, 其它组件访问它时,它是服务端, 同时,它也会访问etcd或者kubelet,这时它是客户端. 这种访问是需要通过认证的,kubernetes的认证也支持多种方式, 证书为其中最常用的, Kubernetes的证书可以存在多套,每套的证书可以由不同的**根证书(CA)**签发, apiserver访问kubelet跟访问etcd可以通过使用由不同根证书签发的证书来访问, 但是一般情况下,一个Kuberntes集群中我们习惯使用一个CA来签署所有的证书, 这也是几乎所有的部署工具采用的方式.
**Bootstrap Token主要涉及认证阶段(TLS)**,至于鉴权机制(RBAC),不是本文重点.
集群启用RBAC后各组件之间的通信是基于TLS加密的,client和server需要通过证书中的CN,O来确定用户的user和group,因此client和server都需要持有有效证书, Bootstrap Token只用于kubelet tls 到apiserver的认证, 如果k8s集群本身都未开启tls,那自然就不需要了
Node在Kubelet的启动参数中指定事先在集群中配置好的Bootstrap Token,这个Bootstrap Token只具有引导Node加入集群的权限限定,除此之外,没有其它权限, 这样通过限定权限可以保障集群安全
Kubelet申请证书大致流程
- 集群产生一个低权账号用户组,通过TOKEN进行认证创建ClusterRole使其具有创建证书申请CSR的权限
- 给这个组添加ClusterRoleBinding,使得具有这个组的账号的kubelet具有上述权限
- 给添加ClusterRoleBinding,使得controller-manager自动同意上述两个证书的下发
- 调整 Controller Manager确保启动tokencleaner和bootstrapsigner(4中自动证书下发的功能)
- 基于上述TOKEN生成bootstrap.kubeconfig文件,并下发给node节点
- node节点的kubelet拿着这个bootstrap.kubeconfig向master的apiserver发起CSR(certificate signing request)
- master自动同意并下发第一个证书
- node节点的kubelet自动拿着第一个证书与master的apiserver通信申请第二个证书
- master自动同意并下发第二个证书
- node节点加入集群
上述过程要求,kubelet跟apiserver具有相同的CA证书
假设现阶段已经存在一个k8s集群, 然后存在一台需要加入改集群的node.
先对Node做一些准备工作:
Node系统初始化
1 | swapoff -a |
Node安装docker/kubelet
1 | apt-get update |
此时我们查看kubelet会发现它启动失败,因为目前还未配置bootstrap相关配置,它无法连接上apiserver
调整kube-apiserver
要使用bootstrap token引导Node加入集群, kube-apiserver 需要开启参数 --enable-bootstrap-token-auth=true
Bootstrap
生成一个token
1 | echo "$(head -c 6 /dev/urandom | md5sum | head -c 6)"."$(head -c 16 /dev/urandom | md5sum | head -c 16)" |
Kubernetes的官方有详细说明, 点击查看Bootstrap Token
既然token只需要符合格式就行,CKA考试的时候可以直接使用页面上的Token来做,毕竟上面这一大串的命令不是谁都能记得住.
创建 Bootstrap Token Secret
1 | apiVersion: v1 |
secret的格式有要求,如下:
- namespace必须是kube-system
- name的后半部分token-id必须是token的前部分
- Expiration必须是未来的某个时刻, 不然的话一新建就会被删除
- token必须属于system:bootstrappers开头的组.
更多信息可看这里kubelet-tls-bootstrapping
上述操作只是创建出了这个token, 下面需要给这个token绑定合适的权限, 用于引导Node.
创建 ClusterRole 和 ClusterRoleBinding
查看集群必须存在3个clusterrole及3个clusterrolebinding,如下:
3个clusterrole:
- system:certificates.k8s.io:certificatesigningrequests:nodeclient 用于第一次证书认证
- system:certificates.k8s.io:certificatesigningrequests:selfnodeclient 用于证书续签
- system:certificates.k8s.io:certificatesigningrequests:selfnodeserver
nodeclient 类型的 CSR 仅在第一次启动时会产生,selfnodeclient 类型的 CSR 请求实际上就是 kubelet renew 自己作为 client 跟 apiserver 通讯时使用的证书产生的,selfnodeserver 类型的 CSR 请求则是 kubelet 首次申请或后续 renew 自己的 10250 api 端口证书时产生的
重点关注前两个,后面那个k8s新版本下会自动新建
1 | # A ClusterRole which instructs the CSR approver to approve a user requesting |
同时,需要有以下3个clusterrolebinding 到 clusterrole
- system:node-bootstrapper
- system:certificates.k8s.io:certificatesigningrequests:nodeclient
- system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
1 | # enable bootstrapping nodes to create CSR |
1 | # Approve all CSRs for the group "system:bootstrappers" |
1 | # Approve renewal CSRs for the group "system:nodes" |
自动批准组system:bootstrappers
所有CSR 请求(nodeclient)
自动批准组system:nodes
的证书重签CSR请求.
所以这就是为何token需要属于system:bootstrappers
组
更多信息可看这里bootstrap-tokens
调整kube-controllermanager启动参数
kube-controllermanager需要开启支持自动签署证书的参数 --controllers=*,bootstrapsigner,tokencleaner
这样,每当有Node通过Bootstrap token来请求CSR(certificate signing request)
对于 controller manager 来说,TLS bootstrapping 下 kubelet 发起的 CSR 请求大致分为以下三种
- nodeclient: kubelet 以
O=system:nodes
和CN=system:node:(node name)
形式发起的 CSR 请求- selfnodeclient: kubelet client renew 自己的证书发起的 CSR 请求(与上一个证书就有相同的 O 和 CN)
- selfnodeserver: kubelet server renew 自己的证书发起的 CSR 请求
对应上面的3个clusterrole
生成kubeconfig文件
1 | 设置集群参数 |
通过上面的命令最终会在/var/lib/kubelet目录下生bootstrap-kubeconfig文件, 将该文件放到node节点上, kubelet指定改文件路径,启动时从改文件中获取apiserver及Bootstrap Token
1 | apiVersion: v1 |
调整Node上kubelet启动参数
node上需要有ca.crt(或者ca.pem)
vim /lib/systemd/system/kubelet.service
1 | [Unit] |
其中, 在启动时,如果在–kubeconfig指定的路径下存在kubeconfig文件,则使用该文件做认证,如果不存在,则认证为第一次认证,则使用参数bootstrap-kubeconfig指定的文件, 正是包含bootstrap token的引导文件
**通过kube-controller自动签署之后会把最终的kubeconfig写到–kubeconfig参数指定的路径,后续–bootstrap-kubeconfig则没有作用了. **
config.yaml是kubelet的其它参数配置文件
1 | #cat /var/lib/kubelet/config.yaml |
流程总结
- kubelet 读取 bootstrap.kubeconfig,使用其 CA 与 Token 向 apiserver 发起第一次 CSR 请求(nodeclient),使用组
system:bootstrappers
- apiserver 根据 RBAC 规则自动批准首次 CSR 请求(approve-node-client-csr),并下发证书(kubelet-client.crt)
- kubelet **使用刚刚签发的证书(O=system:nodes, CN=system:node:NODE_NAME)**与 apiserver 通讯,并发起申请 10250 server 所使用证书的 CSR 请求
- apiserver 根据 RBAC 规则自动批准 kubelet 为其 10250 端口申请的证书(kubelet-server-current.crt)
- 证书即将到期时,kubelet 自动向 apiserver 发起用于与 apiserver 通讯所用证书的 renew CSR 请求和 renew 本身 10250 端口所用证书的 CSR 请求
- apiserver 根据 RBAC 规则自动批准两个证书
- kubelet 拿到新证书后关闭所有连接,reload 新证书,以后便一直如此
建议大家都全手动搭建一次kubernetes,这样对Bootstrap Token机制会了解更深入.