一.基于CA签名的双向数字证书认证方式
在一个安全的内网环境中, Kubernetes的各个组件与Master之间可以通过apiserver的非安全端口http://apiserver:8080进行访问。但如果apiserver需要对外提供服务,或者集群中的某些容器也需要访问apiserver以获取集群中的某些信息,则更安全的做法是启用HTTPS安全机制。Kubernetes提供了基于CA签名的双向数字证书认证方式和简单的基于HTTP BASE或TOKEN的认证方式,其中CA证书方式的安全性最高。本节先介绍以CA证书的方式配置Kubernetes集群,要求Master上的kube-apiserver.kube-controller-manager. kube-scheduler进程及各Node上的kubelet, kube-proxy进程进行CA签名双向数字证书安全设置
k8s中哪些组件需要进行tls证书认证,哪些不需要?
kube-scheduler、kube-controller-manager 一般和 kube-apiserver 部署在同一台机器上,它们使用非安全端口和 kube-apiserver通信,非安全端口默认为http的8080,可以使用--insecure-port指定,监听非安全端口的地址默认为127.0.0.1,可以使用--insecure-bind-address指定;
kubelet、kube-proxy、kubectl 部署在其它 Node 节点上,如果通过安全端口访问 kube-apiserver,则必须先通过 TLS 证书认证,再通过 RBAC 授权。安全端口默认为https的6443,可以使用--secure-port指定,监听安全端口的地址默认为0.0.0.0(监听所有接口),可以使用--bind-address指定。
1、基于CA签名的双向数字证书的生成过程如下:
(1)为kube-apiserver生成一个数字证书,并用CA证书进行签名。
(2)为kube-apiserver进程配置证书相关的启动参数,包括CA证书(用于验证客户端证书的签名真伪)、自己的经过CA签名后的证书及私钥,
(3)为每个访问Kubernetes API Server的客户端(如kube-controller-manager.kube-scheduler,kubelet, kube-proxy及调用API Server的客户端程序kubectl等)进程生成自己的数字证书,也都用CA证书进行签名,在相关程序的启动参数里增加CA证书、自己的证书等相关参数。1)设置kube-apiserver的CA证书相关的文件和启动参数
生成如下证书:
根证书公钥与私钥:ca-public.pem 与ca-private.pem
API Server公钥与私钥:apiserver-public.pem与apiserver-private.pem
从节点公钥与私钥:kubelet-publi.pem与kubelet-private.pem
集群管理员公钥与私钥:admin.pem与admin-key.pem
二、根证书生成
我们需要一个证书来为自己颁发的证书签名,这个证书可从其他CA获取,或者是自签名的根证书。这里我们生成一个自签名的根证书。
1、CA根证书 ca-private.pem
生成一个2048位的密钥:
# openssl genrsa -out ca-private.pem 2048
2、生成CA私钥
我们自己做测试,那么证书的申请机构和颁发机构都是自己。直接生成证书私钥,-day指定证书有效期
# openssl req -x509 -new -nodes -key ca-private.pem -days 3650 -out ca-public.pem -subj "/CN=kube-ca"
注意:生成ca-private.pem时, -subi参数中"CN"的值通常为域名。
三、生成apiserver服务端证书
1、apiserver证书使用说明
kube-apiserver
使用的证书 | 证书作用 |
---|---|
ca-public.pem | CA根证书 |
ca-private.pem | CA端私钥 |
apiserver-public.pem | kube-apiserver的tls认证证书 |
apiserver-private.pem | kube-apiserver的tls认证私钥 |
--token-auth-file
指定了token.csv的位置,用于kubelet 组件 第一次启动时没有证书如何连接 apiserver 。 Token 和 apiserver 的 CA 证书被写入了 kubelet 所使用的 bootstrap.kubeconfig 配置文件中;这样在首次请求时,kubelet 使用 bootstrap.kubeconfig 中的 apiserver CA 证书来与 apiserver 建立 TLS 通讯,使用 bootstrap.kubeconfig 中的用户 Token 来向 apiserver 声明自己的 RBAC 授权身份
--tls-cert-file=
apiserver-public.pem指定kube-apiserver证书地址
--tls-private-key-file=
apiserver-private.pem指定kube-apiserver私钥地址
--client-ca-file=
ca-public.pem 指定根证书地址
--service-account-key-file=
ca-private.pem/apiserver-private.pem包含PEM-encoded x509 RSA公钥和私钥的文件路径,用于验证Service Account的token,如果不指定,则使用--tls-private-key-file指定的文件
--etcd-cafile=
ca-private.pem 到etcd安全连接使用的SSL CA文件
--etcd-certfile=
apiserver-public.pem 到etcd安全连接使用的SSL 证书文件
--etcd-keyfile=
apiserver-private.pem到etcd安全连接使用的SSL 私钥文件
基于masterssl.cnf创建apiserver-public.pem和apiserver-private.pem文件。
在生成apiserver.csr时, -subi参数中"/CN"指定的名字需为Master所在的主机名。
2、证书生成
1)证书配置
创建用于生成证书签名请求(CSR)的配置文件masterssl.cnf,该文件用于x509 v3版本的证书。
在该文件中主要需要设置:
(1)、Master服务器的hostname (k8s-master)、IP地址${MASTER_IPV4}(192.168.10.50),
(2)、Kubernetes Master Service的虚拟服务名称(kubernetes.default等)和使用自己规划作为kubernetes service IP端的首IP替换${K8S_SERVICE_IP}
即apiserver参数的--service-cluster-ip-range的首IP,
若--service-cluster-ip-range=192.168.10.0/16,则${K8S_SERVICE_IP}为192.168.0.1
若--service-cluster-ip-range=10.0.0.0/16,则${K8S_SERVICE_IP}为10.0.0.1
masterssl.cnf文件的示例如下:
[req] req_extensions = v3_req distinguished_name = req_distinguished_name [req_distinguished_name] [ v3_req ] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = @alt_names [alt_names] DNS.1 = kubernetes DNS.2 = kubernetes.default DNS.3 = kubernetes.default.svc DNS.4 = kubernetes.default.svc.cluster.local IP.1 = {K8S_SERVICE_IP} IP.2 = {MASTER_IPV4}
1)alt_names指的是最终可以访问的域名或者IP,所以,其实一个证书是可以多个网站同时使用的。被访问域名只要满足DNS和IP中的一个,其证书就是合法的。 SubjectAltName是X509 Version 3 (RFC 2459)的扩展,允许ssl证书指定多个可以匹配的名称。SubjectAltName 可以包含email 地址,ip地址,正则匹配DNS主机名,等等。
SAN(Subject Alternative Name)是 SSL 标准 x509 中定义的一个扩展。使用了 SAN 字段的 SSL 证书,可以扩展此证书支持的域名,使得一个证书可以支持多个不同域名的解析。
2)、生成apiserver服务端私钥:
openssl genrsa -out apiserver-private.pem 2048
3)、生成服务端证书签名请求文件(CSR):
和CA证书的生成不同的是,我们需要先生成一个csr证书请求文件文件(CSR,Cerificate Signing Request),有了这个文件之后再利用CA根证书生成最终的证书。
基于配置文件masterssl.cnf生成证书签名请求文件(CSR):
openssl req -new -key apiserver-private.pem -out apiserver.csr -subj "/CN=k8s-master" -config masterssl.cnf (这个是
NO SAN
命令:
openssl req -new -key apiserver-private.pem -out apiserver.csr 只执行NO SAN
命令也可以签发证书,不过却不能够添加多个域名。)
4)、生成apiserver服务端认证公钥
使用ca-private.pem、 ca-public.pem 和apiserver.csr 生成apiservertls认证公钥:
openssl x509 -req -in apiserver.csr -CA ca-public.pem -CAkey ca-private.pem -CAcreateserial -out apiserver-public.pem -days 3650 -extensions v3_req -extfile masterssl.cnf
全部执行完后会生成6个文件:
apiserver-private.csr apiserver-private.pem apiserver-public.pem ca-private.pem ca-public.pem ca-public.srl
查看证书:
openssl x509 -noout -text -in ./apiserver-public.pem
一般生成的根证书(ca-private.pem, ca-public.pem)与apiserver证书(apiserver-private.pem,apiserver-public.pem)放置在Master节点的某个目录(例如/mnt/app/kubernetes/ssl)
apiserver的配置中需要指定如下参数:
--service-account-key-file=/mnt/app/kubernetes/ssl/apiserver-private.pem --tls-private-key-file=/mnt/app/kubernetes/ssl/apiserver-private.pem --tls-cert-file=/mnt/app/kubernetes/ssl/apiserver-public.pem --client-ca-file=/mnt/app/kubernetes/ssl/ca-public.pem 同时,可以关掉非安全端口8080,设置安全端口为443 (默认为6443):
最后重启kube-apiserver服务。
3. kube-controller-manager客户端双向认证证书
kubelet 发起的 CSR 请求都是由 kube-controller-manager 来做实际签署的,所有使用的证书都是根证书的密钥对 。由于kube-controller-manager是和kube-apiserver部署在同一节点上,且使用非安全端口通信,故不需要证书。
使用的证书 | 证书作用 |
---|---|
ca.pem | CA根证书 |
ca-key.pem | kube-apiserver的tls认证私钥 |
--cluster-signing-cert-file:
指定签名的CA机构根证书,用来签名为 TLS BootStrap 创建的证书和私钥
--cluster-signing-key-file:
指定签名的CA机构私钥,用来签名为 TLS BootStrap 创建的证书和私钥
--service-account-private-key-file:
同上
--root-ca-file=:
根CA证书文件路径 ,用来对 kube-apiserver 证书进行校验,指定该参数后,才会在Pod 容器的 ServiceAccount 中放置该 CA 证书文件
--kubeconfig
:kubeconfig配置文件路径,在配置文件中包括Master的地址信息及必要认证信息
apiversion: v1 kind: Config users: - name: controllermanager user: client-certificate: client-key: /mnt/app/kubernetes/ssl/manager-client-private.pem clusters: - name: local cluster: certificate-authority: /var/run/kubernetes/ca.crt contexts: context: cluster: local user: controllermanager name: my-context current-context: my-context
controller-manager的配置中需要指定如下参数: --service-account-private-key-file=/mnt/app/kubernetes/ssl/apiserver-private.pem --root-ca-file=/mnt/app/kubernetes/ssl/ca-public.pem --cluster-signing-cert-file=/mnt/app/kubernetes/ssl/ca-public.pem --cluster-signing-key-file=/mnt/app/kubernetes/ssl/ca-private.pem
当然也可以为controller-manager创建证书,controller-manager相对于apiserver是客户端:
2)、设置kube-controller-manager的客户端证书、私钥和启动参数
$ openssl genrsa -out manager-client-private.pem 2048
$ openssl req -new -key manager-client-private.pem -subj "/CN=k8s-master" -out manager-client.csr
$ openssl x509 -req -in manager-client.csr -CA ca-public.pem -CAkey ca-private.pem -CAcreateserial -out manager-client-public.pem -days 5000
然后可以通过curl测试:
curl --cacert /mnt/app/kubernetes/ssl/ca-public.pem --key /mnt/app/kubernetes/ssl/manager-client-private.pem --cert /mnt/app/kubernetes/ssl/manager-client-public.pem https://k8s-master:6443
如果看到下面错误,说明认证有问题。 { "kind": "Status", "apiVersion": "v1", "metadata": { }, "status": "Failure", "message": "Unauthorized", "reason": "Unauthorized", "code": 401 }
/mnt/app/kubernetes/ssl/kubeconfig.yaml
apiVersion: v1 kind: Config users: - name: controllermanager user: client-certificate:/mnt/app/kubernetes/ssl/manager-client-public.pem client-key:/mnt/app/kubernetes/ssl/manager-client-private.pem clusters: - name: local cluster: certificate-authority: /mnt/app/kubernetes/ssl/ca-public.pem contexts: - context: cluster: local user: controllermanager name: my-context current-context: my-context
5、删除相关serviceAccount的token
由于系统重新生成证书,需要删除相关serviceAccount的token,然后重启apiserver,apiserver根据最新
kubectl get secret -n kube-system NAME TYPE DATA AGE coredns-token-cdn9x kubernetes.io/service-account-token 3 3d default-token-lht2v kubernetes.io/service-account-token 3 3d
kubectl delete secret coredns-token-cdn9x -n kube-system secret "coredns-token-cdn9x" deleted
四、node节点客户端双向证书生成
设置每台Node上kubelet的客户端证书、私钥和启动参数
1)、首先复制kube-apiserver的ca-public.pem和ca-private.pem文件到Node上,
2)、在生成kubelet-public.pem时-CA参数和-CAkey参数使用的是apiserver的ca-public.pem和ca-private.pem文件。
3)、在生成kubelet client.csr时-subj参数中的"/CN"设置为本Node的IP地址。
-subj 指定证书申请者的个人信息
可以将节点IP放入到环境变量
# Export this worker's IP address.
export WORKER_IP=<WORKER_IPV4>
openssl genrsa -out kubelet-private.pem 2048 openssl req -new -key kubelet-private.pem -out kubelet.csr -subj "/CN=kubelet-key" -config kubelet-openssl.cnf openssl x509 -req -in kubelet.csr -CA ca-public.pem -CAkey ca-private.pem -CAcreateserial -out kubelet-public.pem -days 3650 -extensions v3_req -extfile kubelet-openssl.cnf
openssl genrsa -out kubelet-private.pem 2048 openssl req -new -key kubelet-private.pem -out kubelet.csr -subj "/CN=kubelet-key" openssl x509 -req -in kubelet.csr -CA ca-public.pem -CAkey ca-private.pem -CAcreateserial -out kubelet-public.pem -days 3650
curl --cacert /mnt/app/kubernetes/ssl/ca-public.pem --key /mnt/app/kubernetes/ssl/kubelet-private.pem --cert /mnt/app/kubernetes/ssl/kubelet-public.pem https://k8s-master:6443
将这些文件复制到一个目录中(例如/etc/kubernetes/ssl/)。
其中kubelet-openssl.cnf内容如下:
[req] req_extensions = v3_req distinguished_name = req_distinguished_name [req_distinguished_name] [ v3_req ] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = @alt_names [alt_names] IP.1 = $ENV::WORKER_IP
从节点上配置kubelet所使用的配置文件worker-kubeconfig.yaml (kubelet和kube-proxy进程共用)指定证书:
配置客户端证书等相关参数,内容如下:
kubelet的如下参数使用证书:
--kubeconfig=/etc/kubernetes/worker-kubeconfig.yaml --tls-private-key-file=/etc/kubernetes/ssl/kubelet-private.pem --tls-cert-file=/etc/kubernetes/ssl//kubelet-public.pem
重启kubelet
kube-proxy复用上一步kubelet创建的客户端证书,配置启动参数:
--master=https://192.168.18.3:443
--kubeconfig=/etc/kubernetes/worker-kubeconfig.yaml
重启kube-proxy服务。
至此,一个基于CA的双向数字证书认证的Kubernetes集群环境就搭建完成了。
五、集群管理员双向认证证书生成
此证书用于kubectl,设置方式如下:
openssl genrsa -out admin-key.pem 2048 openssl req -new -key admin-key.pem -out admin.csr -subj "/CN=kube-admin" openssl x509 -req -in admin.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out admin.pem -days 365 # 配置一个名为default的集群,并指定服务地址与根证书 kubectl config set-cluster default --server=https://172.17.4.101:443 --certificate-authority={PWD}/ssl/ca.pem
# 设置一个管理用户为admin,并配置访问证书 kubectl config set-credentials admin --certificate-authority={PWD}/ssl/ca.pem --client-key={PWD}/ssl/admin-key.pem --client-certificate=
# 设置一个名为default使用default集群与admin用户的上下文, kubectl config set-context default --cluster=default --user=admin
# 启用default为默认上下文 kubectl config use-context default