Kubernetes API Server和SSL Certificate
最近在重新录制
《Certified Kubernetes Administrator (CKA) 考试完全指南》的课程,没太有时间搞公众号。这周正好搞到Security这一章,关于用户的认证和授权这一部分,其中涉及到了PKI公钥私钥数字签名认证相关的内容,和我之前录制的一起学加密系列视频版有关联,所以就顺便写一篇。
如果有打算购买《Certified Kubernetes Administrator (CKA) 考试完全指南》课程的朋友,可以使用这个链接 (或者点击阅读原文) https://www.udemy.com/course/k8s-chinese/?couponCode=F74B2C1A1B1485788862
注:我们的实验是以kubeadm搭建的集群为例
Kubernetes API Server
Kubernetes的API Server对外是通过HTTPs提供服务的,服务器的地址和端口可以通过很多方式获取到,比如:
$ kubectl cluster-info
Kubernetes control plane is running at https://192.168.56.10:6443或者:
$ kubectl config view -o jsonpath='{.clusters[0].cluster.server}'
https://192.168.56.10:6443CA根证书
客户端通过如kubectl 要访问API Server,要信任HTTPs服务器提供的证书,则必须有这个签名这个证书的CA根证书。
这个CA根证书在集群初始化的时候生成,放到了control plane节点的 /etc/kubernetes/pki/ 目录里,名为 ca.crt. api server的服务器证书和私钥也在这个目录里,分别是 apiserver.crt 和 apiserver.key.
如果是kubeadm搭建的集群,这个根证书也会放到control plane节点的 ~/.kube/config 文件里,然后字符串是经过base64编码后的,要获取原始证书,要么直接查看/etc/kubernetes/pki/ca.crt文件,要么查看kubeconfig文件。
$ kubectl config view --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 --decode通过curl测试一下:
$ curl https://192.168.56.10:6443
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.htmlcurl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
curl默认无法验证证书的有效性,返回错误,这时候要么我们忽略掉证书验证:(--insecure 或者直接 -k)
$ curl https://192.168.56.10:6443 --insecure
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
"reason": "Forbidden",
"details": {},
"code": 403要么提供CA根证书文件:(--cacert /etc/kubernetes/pki/ca.crt)
$ curl https://192.168.56.10:6443 --cacert /etc/kubernetes/pki/ca.crt
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
"reason": "Forbidden",
"details": {},
"code": 403这样HTTPS这关过了,但是我们还是无法正在访问API,forbidden: User \"system:anonymous\" cannot get path 这是因为Kubernetes使用SSL双向认证的过程,要通过验证客户端(也就是kubectl)的SSL证书才验证用户的合法性。
SSL客户端证书
API Server如何判定访问它的客户端具有合法的“用户名和密码”呢,它是通过SSL的客户端验证实现的,而不是通过真正的用户名密码。
这就要说到客户端用户是如何产生的了。客户端用户实际上是拥有一个服务器api server的CA根证书签名过的证书,这个证书里包括客户端的用户名信息。过程如下:
• 客户端生成一对RSA公钥私钥
• 客户端通过自己的公钥,生成一个CSR(证书签名请求Certificate Signing Request),注意这个CSR中的CN的值是自己的用户名
• 客户端把CSR发给API Server,请求对其签名,通过CA根证书对其签名,获取到证书,发给客户端
• 客户端拿到证书后,就可以通过这个证书和API server通信了。
kubeadm搭建集群的初始,会生成的一个kubernetes-admin的用户,过程就是如上所示,然后把收到的签名证书和自己的私钥放到了 ~/.kube/config 文件里。
$ kubectl config view -o jsonpath='{.users[0]}' | python3 -m json.tool
{
"name": "kubernetes-admin",
"user": {
"client-certificate-data": "REDACTED",
"client-key-data": "REDACTED"
}
}client-certificate-data 证书数据,base64编码
client-key-data 私钥,base64加密
通过下面的命令可以把证书和私钥还原并存为文件:
$ kubectl config view -o jsonpath='{.users[0].user.client-certificate-data}' --raw | base64 --decode > client.crt
$ kubectl config view -o jsonpath='{.users[0].user.client-key-data}' --raw | base64 --decode > client.key然后就可以提供证书和私钥去访问API Server了:
curl https://192.168.56.10:6443 \
--cacert /etc/kubernetes/pki/ca.crt \
--cert client.crt \
--key client.key