在通過kubectl訪問pod信息,例如執行kubectl logs,常常會遇到類似如下錯誤:
Error from server (Forbidden): Forbidden (user=system:anonymous, verb=get, resource=nodes, subresource=proxy) ( pods/log tiller-deploy-6b5ffb6f-lg9jb)
網上搜索可以通過啟用anonymous訪問,也就是使用--anonymous-auth=true或者配置文件添加:
authentication:
anonymous:
enabled: true
但是設置之后錯誤依舊,為此我探究了一下kubelet的認證機制,終於將問題解決,其實很簡單,答案后面揭曉。
我們知道kubectl只會和apiserver交互,對於kubectl logs、kubectl exec等需要訪問pod的這些命令,實際上是apiserver調用kubelet接口完成的,上述錯誤正是出在這個過程,而不是kubectl到apiserver的過程。
kubelet通過port指定的端口(默認10250)對外暴露服務,這個服務是需要TLS認證的,同時也可以通過 readOnlyPort 端口(默認10255,0表示關閉)對外暴露只讀服務,這個服務是不需要認證的。apiserver通過--kubelet-https參數指定調用哪個服務,true為前者,false為后者,此時只能執行只讀操作。下面主要說一下前者。
認證過程
配置認證方式
有三種可配置認證方式:
-
TLS認證,這也是默認的
authentication: anonymous: enabled: false webhook: enabled: false x509: clientCAFile: xxxx
-
允許anonymous,這時可不配置客戶端證書
authentication: anonymous: enabled: true
-
webhook,這時可不配置客戶端證書
authentication: webhook: enabled: true
這時kubelet通過bearer tokens,找apiserver認證,如果存在對應的serviceaccount,則認證通過。
如果2開啟,則忽略x509和webhook認證;否則,如果1和3同時開啟,則按1、3的順序依次認證,任何一個認證通過則返回通過,否則認證不通過。
通過kubectl命令行訪問kubelet時,無法傳遞bearer tokens,所以無法使用webhook認證,這時只能使用x509認證。
證書配置
kubelet對外暴露https服務,必須設置服務端證書,如果通過x509證書認證客戶端,那么還需要配置客戶端證書。下面說明證書配置的三種方法:
手工指定證書
-
假設ca的證書和key:ca.pem,ca-key.pem
-
用上述ca生成kubelet服務端證書和key:kubelet-server.pem、kubelet-server-key.pem
-
用上述ca生成apiserver使用的客戶端證書和key:kubelet-client.pem、kubelet-client-key.pem,證書CN為kubelet-client
-
修改kubelet的配置文件:
tlsCertFile: kubelet-server.pem tlsPrivateKeyFile: kubelet-server-key.pem authentication: x509: clientCAFile: ca.pem
-
修改apiserver參數:
--kubelet-certificate-authority=ca.pem --kubelet-client-certificate=kubelet-client.pem --kubelet-client-key=kubelet-client-key.pem
-
授權kubelet-client用戶:
kubectl create clusterrolebinding kubelet-admin --clusterrole=system:kubelet-api-admin --user=kubelet-client
經過上面5步,認證的過程實際已經OK了,第6步是為授權過程服務的,kubelet的授權是通過webhook委托給apiserver的。
自簽名證書和key
實際上是上述過程的特化,不指定tlsCertFile和tlsPrivateKeyFile時,kubelet會自動生成服務端證書保存在--cert-dir指定目錄中,文件名為kubelet.crt和kubelet.key,這個證書是自簽名的,所以apiserver不需要指定--kubelet-certificate-authority,其他配置是一樣的。
通過TLS bootstrap機制
還可以通過TLS bootstrap機制分配kubelet服務證書。跟配置分配訪問apiserver的客戶端證書方法是一樣的(參考官方文檔),額外的配置如下:
-
修改kubelet配置文件:
serverTLSBootstrap: true
-
授權允許創建kubelet服務端證書
首先創建system:certificates.k8s.io:certificatesigningrequests:selfnodeserver,默認是沒有創建的。
selfnodeserver.yaml文件如下:
# 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"]
kubectl create -f selfnodeserver.yaml
然后創建綁定:
kubectl create clusterrolebinding node-server-auto-renew-crt --clusterrole=system:certificates.k8s.io:certificatesigningrequests:selfnodeserver --group=system:nodes
-
手工批准證書請求:
先查詢證書請求:
[vagrant@localhost etc]$ kubectl get csr NAME AGE REQUESTOR CONDITION csr-2jxvn 76s system:node:10.10.10.16 Pending
然后批准證書:
kubectl certificate approve csr-2jxvn
之后在相應kubelet的--cert-dir目錄可以看到服務端證書已經生成。
-
配置客戶端證書和前面的方法是一樣的,上面3步只是生成服務端證書。
選擇哪種方式
客戶端證書配置是免不了的,區別是在服務端證書,顯然自動生成更加方便,TLS bootstrap相對於自簽名證書更加安全,集群統一使用信任的CA簽名。
TLS bootstrap還可以配置證書過期后自動重新生成,方法是修改kubelet配置文件:
rotateCertificates: true
TLS bootstrap分配證書的有效期可以通過kube-controller-manager如下參數修改,默認8760h0m0s,也就是1年:
--experimental-cluster-signing-duration
授權過程
配置授權方式
可配置兩種授權方式:
-
AlwaysAllow:從字面意思就可知道
authorization: mode: AlwaysAllow
-
Webhook:這是默認模式
authorization: mode: Webhook
這時授權過程是委托給apiserver的,使用apiserver一樣的授權模式,也就是RBAC。
配置權限
如果通過Webhook授權,就需要通過RBAC為用戶配置權限。
首先要弄清楚通過認證的用戶是什么,通過x509證書認證的用戶名是客戶端證書中的CN字段,用戶組為O字段;通過webhook認證的用戶是token對應的serviceaccount;沒有通過認證或使能anonymous,則用戶為system:anonymous。
其次要弄清楚應該授權什么權限,系統已經存在一個system:kubelet-api-admin角色,這是最高的權限,可以根據需要創建低權限角色。
[vagrant@localhost kube-apiserver]$ kubectl describe clusterrole system:kubelet-api-admin
Name: system:kubelet-api-admin
Labels: kubernetes.io/bootstrapping=rbac-defaults
Annotations: rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
nodes/log [] [] [*]
nodes/metrics [] [] [*]
nodes/proxy [] [] [*]
nodes/spec [] [] [*]
nodes/stats [] [] [*]
nodes [] [] [get list watch proxy]
最后將用戶和角色綁定,即完成權限的配置。
總結
如何配置kubelet的認證和授權,歸結起來常用如下2種做法:
-
省事型,可用於開發環境
authentication: anonymous: enabled: true authorization: mode: AlwaysAllow
一開始出現的Forbidden問題就是沒有配置AlwaysAllow,默認是Webhook。
-
安全型,生產環境使用
authentication: anonymous: enabled: false authorization: mode: Webhook
服務端證書通過TLS bootstrap,客戶端證書需要手工配置。
歡迎訪問鍾潘的博客