这个写得确实专业,node
转一下收藏。git
https://mritd.me/2018/01/07/kubernetes-tls-bootstrapping-note/github
阅读本文章前,请先阅读一下本文参考的相关文档:bootstrap
Kubernetes 在 1.4 版本(我记着是)推出了 TLS bootstrapping 功能;这个功能主要解决了如下问题:api
当集群开启了 TLS 认证后,每一个节点的 kubelet 组件都要使用由 apiserver 使用的 CA 签发的有效证书才能与 apiserver 通信;此时若是节点多起来,为每一个节点单独签署证书将是一件很是繁琐的事情;TLS bootstrapping 功能就是让 kubelet 先使用一个预约的低权限用户链接到 apiserver,而后向 apiserver 申请证书,kubelet 的证书由 apiserver 动态签署;在配合 RBAC 受权模型下的工做流程大体以下所示(不完整,下面细说)并发
在官方 TLS bootstrapping 文档中屡次提到过 kubelet server
这个东西;在通过翻阅大量文档以及 TLS bootstrapping 设计文档后得出,kubelet server
指的应该是 kubelet 的 10250 端口;app
kubelet 组件在工做时,采用主动的查询机制,即按期请求 apiserver 获取本身所应当处理的任务,如哪些 pod 分配到了本身身上,从而去处理这些任务;同时 kubelet 本身还会暴露出两个自己 api 的端口,用于将本身自己的私有 api 暴露出去,这两个端口分别是 10250 与 10255;对于 10250 端口,kubelet 会在其上采用 TLS 加密以提供适当的鉴权功能;对于 10255 端口,kubelet 会以只读形式暴露组件自己的私有 api,而且不作鉴权处理dom
总结一下,就是说 kubelet 上实际上有两个地方用到证书,一个是用于与 API server 通信所用到的证书,另外一个是 kubelet 的 10250 私有 api 端口须要用到的证书测试
kubelet 发起的 CSR 请求都是由 controller manager 来作实际签署的,对于 controller manager 来讲,TLS bootstrapping 下 kubelet 发起的 CSR 请求大体分为如下三种google
O=system:nodes
和 CN=system:node:(node name)
形式发起的 CSR 请求大白话加本身测试得出的结果: nodeclient 类型的 CSR 仅在第一次启动时会产生,selfnodeclient 类型的 CSR 请求实际上就是 kubelet renew 本身做为 client 跟 apiserver 通信时使用的证书产生的,selfnodeserver 类型的 CSR 请求则是 kubelet 首次申请或后续 renew 本身的 10250 api 端口证书时产生的
在说具体的引导过程以前先谈一下 TLS 和 RBAC,由于这两个事不整明白下面的都不用谈;
众所周知 TLS 的做用就是对通信加密,防止中间人窃听;同时若是证书不信任的话根本就没法与 apiserver 创建链接,更不用提有没有权限向 apiserver 请求指定内容
当 TLS 解决了通信问题后,那么权限问题就应由 RBAC 解决(可使用其余权限模型,如 ABAC);RBAC 中规定了一个用户或者用户组(subject)具备请求哪些 api 的权限;在配合 TLS 加密的时候,实际上 apiserver 读取客户端证书的 CN 字段做为用户名,读取 O 字段做为用户组
从以上两点上能够总结出两点: 第一,想要与 apiserver 通信就必须采用由 apiserver CA 签发的证书,这样才能造成信任关系,创建 TLS 链接;第二,能够经过证书的 CN、O 字段来提供 RBAC 所需的用户与用户组
看完上面的介绍,不知道有没有人想过,既然 TLS bootstrapping 功能是让 kubelet 组件去 apiserver 申请证书,而后用于链接 apiserver;那么第一次启动时没有证书如何链接 apiserver ?
这个问题实际上能够去查看一下 bootstrap.kubeconfig
和 token.csv
获得答案: 在 apiserver 配置中指定了一个 token.csv
文件,该文件中是一个预设的用户配置;同时该用户的 Token 和 apiserver 的 CA 证书被写入了 kubelet 所使用的 bootstrap.kubeconfig
配置文件中;这样在首次请求时,kubelet 使用 bootstrap.kubeconfig
中的 apiserver CA 证书来与 apiserver 创建 TLS 通信,使用 bootstrap.kubeconfig
中的用户 Token 来向 apiserver 声明本身的 RBAC 受权身份,以下图所示
在有些用户首次启动时,可能与遇到 kubelet 报 401 无权访问 apiserver 的错误;这是由于在默认状况下,kubelet 经过 bootstrap.kubeconfig
中的预设用户 Token 声明了本身的身份,而后建立 CSR 请求;可是不要忘记这个用户在咱们不处理的状况下他没任何权限的,包括建立 CSR 请求;因此须要以下命令建立一个 ClusterRoleBinding,将预设用户 kubelet-bootstrap
与内置的 ClusterRole system:node-bootstrapper
绑定到一块儿,使其可以发起 CSR 请求
kubectl create clusterrolebinding kubelet-bootstrap \ --clusterrole=system:node-bootstrapper \ --user=kubelet-bootstrap
在 kubelet 首次启动后,若是用户 Token 没问题,而且 RBAC 也作了相应的设置,那么此时在集群内应该能看到 kubelet 发起的 CSR 请求
出现 CSR 请求后,可使用 kubectl 手动签发(容许) kubelet 的证书
当成功签发证书后,目标节点的 kubelet 会将证书写入到 --cert-dir=
选项指定的目录中;注意此时若是不作其余设置应当生成四个文件
而 kubelet 与 apiserver 通信所使用的证书为 kubelet-client.crt
,剩下的 kubelet.crt
将会被用于 kubelet server
(10250) 作鉴权使用;注意,此时 kubelet.crt
这个证书是个独立于 apiserver CA 的自签 CA,而且删除后 kubelet 组件会从新生成它
单独把这部分拿出来写,是由于我的以为上面已经有点乱了;这部分实际上更复杂,只好单独写一下了,由于这部分涉及的东西比较多,因此也不想草率的几笔带过
首先…首先好几回了…嗯,就是说 kubelet 所发起的 CSR 请求是由 controller manager 签署的;若是想要是实现自动续期,就须要让 controller manager 可以在 kubelet 发起证书请求的时候自动帮助其签署证书;那么 controller manager 不可能对全部的 CSR 证书申请都自动签署,这时候就须要配置 RBAC 规则,保证 controller manager 只对 kubelet 发起的特定 CSR 请求自动批准便可;在 TLS bootstrapping 官方文档中,针对上面 2.2 章节提出的 3 种 CSR 请求分别给出了 3 种对应的 ClusterRole,以下所示
# A ClusterRole which instructs the CSR approver to approve a user requesting # node client credentials. kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: approve-node-client-csr rules: - apiGroups: ["certificates.k8s.io"] resources: ["certificatesigningrequests/nodeclient"] verbs: ["create"] --- # A ClusterRole which instructs the CSR approver to approve a node renewing its # own client credentials. kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: approve-node-client-renewal-csr rules: - apiGroups: ["certificates.k8s.io"] resources: ["certificatesigningrequests/selfnodeclient"] verbs: ["create"] --- # A ClusterRole which instructs the CSR approver to approve a node requesting a # serving cert matching its client cert. kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: approve-node-server-renewal-csr rules: - apiGroups: ["certificates.k8s.io"] resources: ["certificatesigningrequests/selfnodeserver"] verbs: ["create"]
RBAC 中 ClusterRole 只是描述或者说定义一种集群范围内的能力,这三个 ClusterRole 在 1.7 以前须要本身手动建立,在 1.8 后 apiserver 会自动建立前两个(1.8 之后名称有改变,本身查看文档);以上三个 ClusterRole 含义以下
因此,若是想要 kubelet 可以自动续期,那么就应当将适当的 ClusterRole 绑定到 kubelet 自动续期时所所采用的用户或者用户组身上
在自动续期下引导过程与单纯的手动批准 CSR 有点差别,具体的引导流程地址以下
从以上流程咱们能够看出,咱们若是要建立 RBAC 规则,则至少能知足四种状况:
基于以上四种状况,咱们须要建立 3 个 ClusterRoleBinding,建立以下
# 自动批准 kubelet 的首次 CSR 请求(用于与 apiserver 通信的证书) kubectl create clusterrolebinding node-client-auto-approve-csr --clusterrole=approve-node-client-csr --group=system:bootstrappers # 自动批准 kubelet 后续 renew 用于与 apiserver 通信证书的 CSR 请求 kubectl create clusterrolebinding node-client-auto-renew-crt --clusterrole=approve-node-client-renewal-csr --group=system:nodes # 自动批准 kubelet 发起的用于 10250 端口鉴权证书的 CSR 请求(包括后续 renew) kubectl create clusterrolebinding node-server-auto-renew-crt --clusterrole=approve-node-server-renewal-csr --group=system:nodes
在 1.7 后,kubelet 启动时增长 --feature-gates=RotateKubeletClientCertificate=true,RotateKubeletServerCertificate=true
选项,则 kubelet 在证书即将到期时会自动发起一个 renew 本身证书的 CSR 请求;同时 controller manager 须要在启动时增长 --feature-gates=RotateKubeletServerCertificate=true
参数,再配合上面建立好的 ClusterRoleBinding,kubelet client 和 kubelet server 证才书会被自动签署;
注意,1.7 版本设置自动续期参数后,新的 renew 请求不会当即开始,而是在证书总有效期的 70%~90%
的时间时发起;并且经测试 1.7 版本即便自动签发了证书,kubelet 在不重启的状况下不会从新应用新证书;在 1.8 后 kubelet 组件在增长一个 --rotate-certificates
参数后,kubelet 才会自动重载新证书
须要重复强调一个问题是: TLS bootstrapping 时的证书实际是由 kube-controller-manager 组件来签署的,也就是说证书有效期是 kube-controller-manager 组件控制的;因此在 1.7 版本之后(我查文档发现的从1.7开始有) kube-controller-manager 组件提供了一个 --experimental-cluster-signing-duration
参数来设置签署的证书有效时间;默认为 8760h0m0s
,将其改成 87600h0m0s
即 10 年后再进行 TLS bootstrapping 签署证书便可。
kubelet 首次启动经过加载 bootstrap.kubeconfig
中的用户 Token 和 apiserver CA 证书发起首次 CSR 请求,这个 Token 被预先内置在 apiserver 节点的 token.csv 中,其身份为 kubelet-bootstrap
用户和 system:bootstrappers
用户组;想要首次 CSR 请求能成功(成功指的是不会被 apiserver 401 拒绝),则须要先将 kubelet-bootstrap
用户和 system:node-bootstrapper
内置 ClusterRole 绑定;
对于首次 CSR 请求能够手动批准,也能够将 system:bootstrappers
用户组与 approve-node-client-csr
ClusterRole 绑定实现自动批准(1.8 以前这个 ClusterRole 须要手动建立,1.8 后 apiserver 自动建立,并改名为 system:certificates.k8s.io:certificatesigningrequests:nodeclient
)
默认签署的的证书只有 1 年有效期,若是想要调整证书有效期能够经过设置 kube-controller-manager 的 --experimental-cluster-signing-duration
参数实现,该参数默认值为 8760h0m0s
对于证书自动续签,须要经过协调两个方面实现;第一,想要 kubelet 在证书到期后自动发起续期请求,则须要在 kubelet 启动时增长 --feature-gates=RotateKubeletClientCertificate=true,RotateKubeletServerCertificate=true
来实现;第二,想要让 controller manager 自动批准续签的 CSR 请求须要在 controller manager 启动时增长 --feature-gates=RotateKubeletServerCertificate=true
参数,并绑定对应的 RBAC 规则;同时须要注意的是 1.7 版本的 kubelet 自动续签后须要手动重启 kubelet 以使其从新加载新证书,而 1.8 后只须要在 kublet 启动时附带 --rotate-certificates
选项就会自动从新加载新证书
该文件为一个用户的描述文件,基本格式为 Token,用户名,UID,用户组
;这个文件在 apiserver 启动时被 apiserver 加载,而后就至关于在集群内建立了一个这个用户;接下来就能够用 RBAC 给他受权;持有这个用户 Token 的组件访问 apiserver 的时候,apiserver 根据 RBAC 定义的该用户应当具备的权限来处理相应请求
该文件中内置了 token.csv 中用户的 Token,以及 apiserver CA 证书;kubelet 首次启动会加载此文件,使用 apiserver CA 证书创建与 apiserver 的 TLS 通信,使用其中的用户 Token 做为身份标识像 apiserver 发起 CSR 请求
该文件在 kubelet 完成 TLS bootstrapping 后生成,此证书是由 controller manager 签署的,此后 kubelet 将会加载该证书,用于与 apiserver 创建 TLS 通信,同时使用该证书的 CN 字段做为用户名,O 字段做为用户组向 apiserver 发起其余请求
该文件在 kubelet 完成 TLS bootstrapping 后而且没有配置 --feature-gates=RotateKubeletServerCertificate=true
时才会生成;这种状况下该文件为一个独立于 apiserver CA 的自签 CA 证书,有效期为 1 年;被用做 kubelet 10250 api 端口
该文件在 kubelet 完成 TLS bootstrapping 后而且配置了 --feature-gates=RotateKubeletServerCertificate=true
时才会生成;这种状况下该证书由 apiserver CA 签署,默认有效期一样是 1 年,被用做 kubelet 10250 api 端口鉴权
这是一个软链接文件,当 kubelet 配置了 --feature-gates=RotateKubeletClientCertificate=true
选项后,会在证书总有效期的 70%~90%
的时间内发起续期请求,请求被批准后会生成一个 kubelet-client-时间戳.pem
;kubelet-client-current.pem
文件则始终软链接到最新的真实证书文件,除首次启动外,kubelet 一直会使用这个证书同 apiserver 通信
一样是一个软链接文件,当 kubelet 配置了 --feature-gates=RotateKubeletServerCertificate=true
选项后,会在证书总有效期的 70%~90%
的时间内发起续期请求,请求被批准后会生成一个 kubelet-server-时间戳.pem
;kubelet-server-current.pem
文件则始终软链接到最新的真实证书文件,该文件将会一直被用于 kubelet 10250 api 端口鉴权
apiserver 预先放置 token.csv,内容样例以下
6df3c701f979cee17732c30958745947,kubelet-bootstrap,10001,"system:bootstrappers"
容许 kubelet-bootstrap 用户建立首次启动的 CSR 请求
kubectl create clusterrolebinding kubelet-bootstrap \ --clusterrole=system:node-bootstrapper \ --user=kubelet-bootstrap
配置 kubelet 自动续期,RotateKubeletClientCertificate 用于自动续期 kubelet 链接 apiserver 所用的证书(kubelet-client-xxxx.pem),RotateKubeletServerCertificate 用于自动续期 kubelet 10250 api 端口所使用的证书(kubelet-server-xxxx.pem)
KUBELET_ARGS="--cgroup-driver=cgroupfs \ --cluster-dns=10.254.0.2 \ --resolv-conf=/etc/resolv.conf \ --experimental-bootstrap-kubeconfig=/etc/kubernetes/bootstrap.kubeconfig \ --feature-gates=RotateKubeletClientCertificate=true,RotateKubeletServerCertificate=true \ --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \ --fail-swap-on=false \ --cert-dir=/etc/kubernetes/ssl \ --cluster-domain=cluster.local. \ --hairpin-mode=promiscuous-bridge \ --serialize-image-pulls=false \ --pod-infra-container-image=gcr.io/google_containers/pause-amd64:3.0"
配置 controller manager 自动批准相关 CSR 请求,若是不配置 --feature-gates=RotateKubeletServerCertificate=true
参数,则即便配置了相关的 RBAC 规则,也只会自动批准 kubelet client 的 renew 请求
KUBE_CONTROLLER_MANAGER_ARGS="--address=0.0.0.0 \ --service-cluster-ip-range=10.254.0.0/16 \ --feature-gates=RotateKubeletServerCertificate=true \ --cluster-name=kubernetes \ --cluster-signing-cert-file=/etc/kubernetes/ssl/k8s-root-ca.pem \ --cluster-signing-key-file=/etc/kubernetes/ssl/k8s-root-ca-key.pem \ --service-account-private-key-file=/etc/kubernetes/ssl/k8s-root-ca-key.pem \ --root-ca-file=/etc/kubernetes/ssl/k8s-root-ca.pem \ --leader-elect=true \ --node-monitor-grace-period=40s \ --node-monitor-period=5s \ --pod-eviction-timeout=5m0s"
建立自动批准相关 CSR 请求的 ClusterRole
# A ClusterRole which instructs the CSR approver to approve a user requesting # node client credentials. kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: approve-node-client-csr rules: - apiGroups: ["certificates.k8s.io"] resources: ["certificatesigningrequests/nodeclient"] verbs: ["create"] --- # A ClusterRole which instructs the CSR approver to approve a node renewing its # own client credentials. kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: approve-node-client-renewal-csr rules: - apiGroups: ["certificates.k8s.io"] resources: ["certificatesigningrequests/selfnodeclient"] verbs: ["create"] --- # A ClusterRole which instructs the CSR approver to approve a node requesting a # serving cert matching its client cert. kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: approve-node-server-renewal-csr rules: - apiGroups: ["certificates.k8s.io"] resources: ["certificatesigningrequests/selfnodeserver"] verbs: ["create"]
将 ClusterRole 绑定到适当的用户组,以完成自动批准相关 CSR 请求
# 自动批准 system:bootstrappers 组用户 TLS bootstrapping 首次申请证书的 CSR 请求 kubectl create clusterrolebinding node-client-auto-approve-csr --clusterrole=approve-node-client-csr --group=system:bootstrappers # 自动批准 system:nodes 组用户更新 kubelet 自身与 apiserver 通信证书的 CSR 请求 kubectl create clusterrolebinding node-client-auto-renew-crt --clusterrole=approve-node-client-renewal-csr --group=system:nodes # 自动批准 system:nodes 组用户更新 kubelet 10250 api 端口证书的 CSR 请求 kubectl create clusterrolebinding node-server-auto-renew-crt --clusterrole=approve-node-server-renewal-csr --group=system:nodes
一切就绪后启动 kubelet 组件便可,不过须要注意的是 1.7 版本 kubelet 不会自动重载 renew 的证书,须要本身手动重启
apiserver 预先放置 token.csv,内容样例以下
6df3c701f979cee17732c30958745947,kubelet-bootstrap,10001,"system:bootstrappers"
容许 kubelet-bootstrap 用户建立首次启动的 CSR 请求
kubectl create clusterrolebinding kubelet-bootstrap \ --clusterrole=system:node-bootstrapper \ --user=kubelet-bootstrap
配置 kubelet 自动续期,RotateKubeletClientCertificate 用于自动续期 kubelet 链接 apiserver 所用的证书(kubelet-client-xxxx.pem),RotateKubeletServerCertificate 用于自动续期 kubelet 10250 api 端口所使用的证书(kubelet-server-xxxx.pem),--rotate-certificates
选项使得 kubelet 可以自动重载新证书
KUBELET_ARGS="--cgroup-driver=cgroupfs \ --cluster-dns=10.254.0.2 \ --resolv-conf=/etc/resolv.conf \ --experimental-bootstrap-kubeconfig=/etc/kubernetes/bootstrap.kubeconfig \ --feature-gates=RotateKubeletClientCertificate=true,RotateKubeletServerCertificate=true \ --rotate-certificates \ --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \ --fail-swap-on=false \ --cert-dir=/etc/kubernetes/ssl \ --cluster-domain=cluster.local. \ --hairpin-mode=promiscuous-bridge \ --serialize-image-pulls=false \ --pod-infra-container-image=gcr.io/google_containers/pause-amd64:3.0"
配置 controller manager 自动批准相关 CSR 请求,若是不配置 --feature-gates=RotateKubeletServerCertificate=true
参数,则即便配置了相关的 RBAC 规则,也只会自动批准 kubelet client 的 renew 请求
KUBE_CONTROLLER_MANAGER_ARGS="--address=0.0.0.0 \ --service-cluster-ip-range=10.254.0.0/16 \ --cluster-name=kubernetes \ --cluster-signing-cert-file=/etc/kubernetes/ssl/k8s-root-ca.pem \ --cluster-signing-key-file=/etc/kubernetes/ssl/k8s-root-ca-key.pem \ --service-account-private-key-file=/etc/kubernetes/ssl/k8s-root-ca-key.pem \ --feature-gates=RotateKubeletServerCertificate=true \ --root-ca-file=/etc/kubernetes/ssl/k8s-root-ca.pem \ --leader-elect=true \ --experimental-cluster-signing-duration 10m0s \ --node-monitor-grace-period=40s \ --node-monitor-period=5s \ --pod-eviction-timeout=5m0s"
建立自动批准相关 CSR 请求的 ClusterRole,相对于 1.7 版本,1.8 的 apiserver 自动建立了前两条 ClusterRole,因此只须要建立一条就好了
# A ClusterRole which instructs the CSR approver to approve a node requesting a # serving cert matching its client cert. kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: system:certificates.k8s.io:certificatesigningrequests:selfnodeserver rules: - apiGroups: ["certificates.k8s.io"] resources: ["certificatesigningrequests/selfnodeserver"] verbs: ["create"]
将 ClusterRole 绑定到适当的用户组,以完成自动批准相关 CSR 请求
# 自动批准 system:bootstrappers 组用户 TLS bootstrapping 首次申请证书的 CSR 请求 kubectl create clusterrolebinding node-client-auto-approve-csr --clusterrole=system:certificates.k8s.io:certificatesigningrequests:nodeclient --group=system:bootstrappers # 自动批准 system:nodes 组用户更新 kubelet 自身与 apiserver 通信证书的 CSR 请求 kubectl create clusterrolebinding node-client-auto-renew-crt --clusterrole=system:certificates.k8s.io:certificatesigningrequests:selfnodeclient --group=system:nodes # 自动批准 system:nodes 组用户更新 kubelet 10250 api 端口证书的 CSR 请求 kubectl create clusterrolebinding node-server-auto-renew-crt --clusterrole=system:certificates.k8s.io:certificatesigningrequests:selfnodeserver --group=system:nodes
一切就绪后启动 kubelet 组件便可,1.8 版本 kubelet 会自动重载证书,如下为 1.8 版本在运行一段时间后的相关证书截图
转载请注明出处,本文采用 CC4.0 协议受权