一.基於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=${PWD}/ssl/admin.pem
# 設置一個名爲default使用default集羣與admin用戶的上下文,
kubectl config set-context default --cluster=default --user=admin
# 啓用default爲默認上下文
kubectl config use-context default