本文采用TLS bootstrap证书:在安装 k8s worker node 时,基本上 worker 的初始状态仅仅是安装了 docker 和 kubelet,worker 需要一种机制跟 master 通信。但网络通信的基本假设是通信双方谁也不信任谁。所以,kubelet bootstrap要以自动化的方式解决如下几个问题:
- 在只知道 api server IP 地址的情况下,工作节点如何获取 api server 的 CA 证书?
- 如何让 api server 信任 worker?因为在 api server 信任 worker 之前,worker 没有途径拿到自己的证书
Bootstrap有两种形式:bootstrap令牌以及bootstrap认证文件,相对于认证文件 令牌形式更加的灵活,所以后续演示都是通过令牌形式部署
要让api server信任工作节点,工作节点必须让master认证鉴权:
- apiserver 开启 bootstrap token 认证,支持 kubelet TLS bootstrapping,所以apiserver启动的时候需要加入以下参数
--authorization-mode=Node,RBAC \
--enable-bootstrap-token-auth=true \
--apiserver-count=3 \
--kubelet-https \
--kubelet-client-certificate=/etc/kubernetes/pki/cs_client.crt \
--kubelet-client-key=/etc/kubernetes/pki/cs_client.key \
--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname \
bootstrap令牌功能 可以为每个工作节点发送一个令牌授权工作节点,这个过程主要两方面:
- 使用令牌ID,密钥和范围创建Kubernetes密钥。
- 将令牌发送到kubelet
KUBE-API服务器将其识别为一个特殊的记号,并授予任何与该令牌特殊的启动权认证,特别是对待他们的成员system:bootstrappers
组。这满足了TLS引导的基本要求。
主要步骤:
建立TLS bootstrap secret来提供自动签证使用:
TOKEN_PUB=$(openssl rand -hex 3)
TOKEN_SECRET=$(openssl rand -hex 8)
BOOTSTRAP_TOKEN="${TOKEN_PUB}.${TOKEN_SECRET}"
kubectl -n kube-system create secret generic bootstrap-token-${TOKEN_PUB} \
--type 'bootstrap.kubernetes.io/token' \
--from-literal description="cluster bootstrap token" \
--from-literal token-id=${TOKEN_PUB} \
--from-literal token-secret=${TOKEN_SECRET} \
--from-literal usage-bootstrap-authentication=true \
--from-literal usage-bootstrap-signing=true
建立bootstrap
的kubeconfig文件:
CLUSTER_NAME="kubernetes"
KUBE_USER="kubelet-bootstrap"
KUBE_CONFIG="bootstrap.kubeconfig"
# 设置集群参数
kubectl config set-cluster ${CLUSTER_NAME} \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=/etc/kubernetes/${KUBE_CONFIG}
# 设置上下文参数
kubectl config set-context ${KUBE_USER}@${CLUSTER_NAME} \
--cluster=${CLUSTER_NAME} \
--user=${KUBE_USER} \
--kubeconfig=/etc/kubernetes/${KUBE_CONFIG}
# 设置客户端认证参数
kubectl config set-credentials ${KUBE_USER} \
--token=${BOOTSTRAP_TOKEN} \
--kubeconfig=/etc/kubernetes/${KUBE_CONFIG}
# 设置当前使用的上下文
kubectl config use-context ${KUBE_USER}@${CLUSTER_NAME} --kubeconfig=/etc/kubernetes/${KUBE_CONFIG}
# 查看生成的配置文件
kubectl config view --kubeconfig=/etc/kubernetes/${KUBE_CONFIG}
之后会在/etc/kubernetes目录生成bootstrap.kubeconfig,后续在工作节点在启动kubelet里通过参数--bootstrap-kubeconfig=/etc/kubernetes/bootstrap.kubeconfig 引入文件
授权 kubelet 可以创建 csr:
kubectl create clusterrolebinding kubeadm:kubelet-bootstrap --clusterrole system:node-bootstrapper --group system:bootstrappers
批准 csr 请求:
- 允许 system:bootstrappers 组的所有 csr
cat <<EOF | kubectl apply -f -
# Approve all CSRs for the group "system:bootstrappers"
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: auto-approve-csrs-for-group
subjects:
- kind: Group
name: system:bootstrappers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: system:certificates.k8s.io:certificatesigningrequests:nodeclient
apiGroup: rbac.authorization.k8s.io
EOF
允许 kubelet 能够更新自己的证书
cat <<EOF | kubectl apply -f -
# Approve renewal CSRs for the group "system:nodes"
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: auto-approve-renewals-for-nodes
subjects:
- kind: Group
name: system:nodes
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
apiGroup: rbac.authorization.k8s.io
EOF
配置完成之后kubelet会向apiserver申请csr证书,申请完成之后会生成自己对应的证书 例如:
在master节点通过kubectl get csr 查看申请的证书 可以看淡Approved代表申请成功:
开启自动续签:
在 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 签署证书即可。