Kubernetes - Kubelet TLS Bootstrapping


一、簡單說明

寫這個的初衷是自己搜索TLS Bootstrapping的時候沒有搜到自己想要的東西,因為TLS Bootstrapping經過很多版本之后也發生了一些變化,所以網上很多也是老的內容了。其實很早的時候就知道了TLS Bootstrapping了,而且也看了官方文檔,並且也能根據文檔搭建,但是可能還是對他沒有徹底了解,所以過了一段時間就忘了,不知道如何使用了。由於之前改功能一直處於開發變動之中,所以也不好寫什么,在kubernetes v1.18.0之后,該功能也基本成熟了,所以將該功能整理記錄下來。希望這次可以將Kubelet TLS Bootstrapping徹底搞清楚,從出現它的需求、它需要實現的目標、它的配置、它的源碼各方面搞懂才好,我現在還沒有開始研究源碼,所以這里就沒有源碼的解析。如果以后有機會去看源碼,也希望能將體會分享在這里。

二、需求

我們都知道,kubernetes對安全性的要求是比較高的,而且也一直踐行全站安全的規范,基本上各種訪問調用都需要TLS證書進行認證及授權。但是TLS對於具體實現的時候成本就相對增加了很多。尤其集群中眾多的kubelet都需要與kube-apiserver通信,如果由管理員是管理證書及權限,很有可能會因為證書過期等問題出現混亂。所以,對於更加簡單的部署kubelet的需求就不難理解了。

Kubelet TLS Bootstrapping需求由 CoreOS社區的開發者在2015年12月提出來,並且描述詳細。主要需要實現兩個功能,第一,實現kubelet與kube-apiserver之間的自動認證通信;第二,限制相關訪問kube-apiserver的權限。

https://github.com/kubernetes/kubernetes/issues/18112

https://docs.google.com/document/d/1XPPuq9NBGNXLgZ94LvAANq8lP89nXiQFRHTzjzuE2kI/edit?usp=sharing

https://github.com/kubernetes/kubernetes/pull/20439

三、Kubelet認證過程簡述

### kubelet啟動時候向kube-apiserver進行認證過程:

1. kubelet啟動時查找配置的kubeconfig文件

2. 從kubeconfig文件中得到apiserver的URL和認證信息(一般是TLS key和CA簽發的證書)

3. 使用認證信息向apiserver進行認證

### 集群管理需要為kubelet做的事:

1. 為kubernetes集群創建CA和CA-KEY

2. 將CA和CA-KEY給kube-apiserver使用

3. 為每個node的kubelet創建證書和key(強烈建議每個node使用唯一證書,並設置唯一CN)

4. 使用CA-KEY簽發kubelet的證書

5. 將kubelet的證書給kubelet使用

TLS Bootstrapping旨在簡化從第三步開始的步驟,因為這是每個kubelet都需要的。

### TLS Bootstrap初始化過程:

1. kubelet進程啟動

2. kubelet查找kubeconfig,沒找到(因為沒配置)

3. kubelet查找到bootstrap-kubeconfig文件

4. kubelet通過bootstrap-kubeconfig文件,查找到apiserver的URL和有限制權限的"token",該"token"可以通過apiserver的認證,且只能向apiserver發送CSR請求

5. kubelet使用"token"向apiserver認證

6. kubelet現在有權限創建一個CSR並發給apiserver

7. kubelet創建一個key和cert,並使用cert創建一個帶signerName=kubernetes.io/kube-apiserver-client-kubelet的CSR,並發送給apiserver

8. apiserver簽發該CSR:

    如果配置了自動簽發,kube-controller-manager將會自動簽發該CSR

    可以使用集群外的程序或人使用kubectl或Kubernetes API進行簽發

9. 為kubelet簽發證書(一般證書有效期為1年)

10. 將簽發好的證書分發給kubelet

11. kubelet得到簽發的證書

12. kubelet使用key和簽發的證書生成kubeconfig

13. kubelet現在可以正常與apiserver交互了

14. 可選:如果配置了,kubelet將會在證書快過期的時候,自動發起新的CSR請求更新自己的證書

15. apiserver或手動或自動簽發kubelet發送的更新證書的CSR請求

四、Token

### 格式

Token格式:[a-z0-9]{6}\.[a-z0-9]{16}

點號之前的是token ID,之后的是token Secret

如:abcdef.0123456789abcdef

### 權限

token認證的所使用的用戶名是system:bootstrap:<token id>,屬於system:bootstrappers組,可以在secret中的auth-extra-groups字段添加額外組

### 生成bootstrap-kubeconfig

kubectl config --embed-certs=true --kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig set-cluster bootstrap --server='https://192.168.81.10:6443' --certificate-authority=/var/lib/kubernetes/ca.pem
kubectl config --kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig set-credentials kubelet-bootstrap --token=10001.be31df5b85f4f55404b96bffe768562a
kubectl config --kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig set-context bootstrap --user=kubelet-bootstrap --cluster=bootstrap
kubectl config --kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig use-context bootstrap
# 將bootstrap-kubeconfig文件分發到kubelet上

五、Kubelet TLS Bootstrapping配置

### 需要配置的組件

1. kube-apiserver(--enable-bootstrap-token-auth)

2. kube-controller-manager

3. kubelet

4. in-cluster resources: ClusterRoleBinding and potentially ClusterRole

`注意:需要使用到你的CA`

### kubelet向kube-apiserver認證方式

kubernetes 認證器(authenticators):

https://kubernetes.io/docs/reference/access-authn-authz/authentication/

* X509 Client Certs

* Static Token File(推薦用於bootsrap)

* Bootstrap Tokens(推薦用於bootsrap)

* Service Account Tokens

* OpenID Connect Tokens

* Using kubectl

* Webhook Token Authentication

* Anonymous requests

* User impersonation

* client-go credential plugins

1. 生成token

token由token-id和token-secret組成,id相當於用戶名,secret相當於密碼。

token-id由自己取一個,密碼可以通過以下命令生成。

生成token密碼:

head -c 16 /dev/urandom | od -An -t x | tr -d ' '

2. kube-apiserver配置

配置kube-apiserver參數

--client-ca-file=FILENAME

該CA用於驗證客戶端證書的有效性。

* 用於認證bootstrapping kubelet的組system:bootstrappers

* 批准CSR

kube-apiserver啟用token認證

--enable-bootstrap-token-auth

#### 方法一:Bootstrap Tokens Kubernetes `v1.18 [stable]`

這是一種更加簡單方便的認證方式。

1. 創建包含token ID,token密碼,作用范圍的secret

apiVersion: v1
kind: Secret
metadata:
  # Name MUST be of form "bootstrap-token-<token id>"
  name: bootstrap-token-07401b
  namespace: kube-system
  # Type MUST be 'bootstrap.kubernetes.io/token'
type: bootstrap.kubernetes.io/token
stringData:
  # Human readable description. Optional.
  description: "The default bootstrap token generated by 'kubeadm init'."
  # Token ID and secret. Required.
  token-id: "07401b"
  token-secret: f395accd246ae52d
  # Expiration. Optional.
  #expiration: 2017-03-10T03:22:11Z
  # Allowed usages.
  usage-bootstrap-authentication: "true"
  usage-bootstrap-signing: "true"
  # Extra groups to authenticate the token as. Must start with "system:bootstrappers:"
auth-extra-groups: system:bootstrappers:worker,system:bootstrappers:ingress

**Secret說明:**

* # https://github.com/kubernetes/community/blob/master/contributors/design-proposals/cluster-lifecycle/bootstrap-discovery.md

* type: bootstrap.kubernetes.io/token

* name: bootstrap-token-<token id>

* token-id: 自己定義的

* token-secret: 自己生成的

* expiration: 過期時間

* usage-bootstrap-signing: 為true時,表示允許這個token的請求簽發bootstrap配置

* usage-bootstrap-authentication: 這個token是否允許用於apiserver的認證

* description(optional): 描述信息

* auth-groups(or auth-extra-groups?): 逗號分隔的認證組列表,必須以system:bootstrappers:開頭

* ConfigMap Signing

#### 方法二:Token authentication file

https://kubernetes.io/docs/reference/access-authn-authz/authentication/#static-token-file

生成token文件

如:`02b50b05283e98dd0fd71db496ef01e8,kubelet-bootstrap,10001,"system:bootstrappers"` token,user,uid,"group1,group2,group3"

kube-apiserver添加參數

--token-auth-file=FILENAME

3. 配置bootstrapper有生成CSR的權限

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: system:node-bootstrapper
rules:
- apiGroups:
  - certificates.k8s.io
  resources:
  - certificatesigningrequests
  verbs:
  - create
  - get
  - list
  - watch
---
# enable bootstrapping nodes to create CSR
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: create-csrs-for-bootstrapping
subjects:
- kind: Group
  name: system:bootstrappers
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: system:node-bootstrapper
  apiGroup: rbac.authorization.k8s.io

4. kube-controller-manager配置

簽發kubelet證書所用的ca和ca-key,這個ca應用和kube-apiserver中的--client-ca-file一致

--cluster-signing-cert-file="/var/lib/kubernetes/ca.pem" --cluster-signing-key-file="/var/lib/kubernetes/ca-key.pem"

在kubernetes v1.19中提供了更加細致的CA配置,僅供參考

Csrsigning controller flags:

      --cluster-signing-cert-file string                         Filename containing a PEM-encoded X509 CA certificate used to issue
cluster-scoped certificates.  If specified, no more specific --cluster-signing-* flag may be specified.
      --cluster-signing-duration duration                        The length of duration signed certificates will be given. (default 8
760h0m0s)
      --cluster-signing-key-file string                          Filename containing a PEM-encoded RSA or ECDSA private key used to s
ign cluster-scoped certificates.  If specified, no more specific --cluster-signing-* flag may be specified.
      --cluster-signing-kube-apiserver-client-cert-file string   Filename containing a PEM-encoded X509 CA certificate used to issue
certificates for the kubernetes.io/kube-apiserver-client signer.  If specified, --cluster-signing-{cert,key}-file must not be set.
      --cluster-signing-kube-apiserver-client-key-file string    Filename containing a PEM-encoded RSA or ECDSA private key used to s
ign certificates for the kubernetes.io/kube-apiserver-client signer.  If specified, --cluster-signing-{cert,key}-file must not be set
.
      --cluster-signing-kubelet-client-cert-file string          Filename containing a PEM-encoded X509 CA certificate used to issue
certificates for the kubernetes.io/kube-apiserver-client-kubelet signer.  If specified, --cluster-signing-{cert,key}-file must not be
 set.
      --cluster-signing-kubelet-client-key-file string           Filename containing a PEM-encoded RSA or ECDSA private key used to s
ign certificates for the kubernetes.io/kube-apiserver-client-kubelet signer.  If specified, --cluster-signing-{cert,key}-file must no
t be set.
      --cluster-signing-kubelet-serving-cert-file string         Filename containing a PEM-encoded X509 CA certificate used to issue
certificates for the kubernetes.io/kubelet-serving signer.  If specified, --cluster-signing-{cert,key}-file must not be set.
      --cluster-signing-kubelet-serving-key-file string          Filename containing a PEM-encoded RSA or ECDSA private key used to s
ign certificates for the kubernetes.io/kubelet-serving signer.  If specified, --cluster-signing-{cert,key}-file must not be set.
      --cluster-signing-legacy-unknown-cert-file string          Filename containing a PEM-encoded X509 CA certificate used to issue
certificates for the kubernetes.io/legacy-unknown signer.  If specified, --cluster-signing-{cert,key}-file must not be set.
      --cluster-signing-legacy-unknown-key-file string           Filename containing a PEM-encoded RSA or ECDSA private key used to s
ign certificates for the kubernetes.io/legacy-unknown signer.  If specified, --cluster-signing-{cert,key}-file must not be set.

看個實踐的例子

 
         

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"19", GitVersion:"v1.19.0", GitCommit:"e19964183377d0ec2052d1f1fa930c4d7575bd50", GitTreeState:"clean", BuildDate:"2020-09-04T02:07:01Z", GoVersion:"go1.15", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"19", GitVersion:"v1.19.0", GitCommit:"e19964183377d0ec2052d1f1fa930c4d7575bd50", GitTreeState:"clean", BuildDate:"2020-09-04T02:07:01Z", GoVersion:"go1.15", Compiler:"gc", Platform:"linux/amd64"}


$ kubectl get csr NAME AGE SIGNERNAME REQUESTOR CONDITION csr
-9d7qd 0s kubernetes.io/kubelet-serving system:node:k8s00.99bill.com Pending #沒有手工簽發前的server證書csr csr-qzbmz 8s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:07401b Approved,Issued # client證書csr $ kubectl certificate approve csr-9d7qd certificatesigningrequest.certificates.k8s.io/csr-9d7qd approved $ kubectl get csr NAME AGE SIGNERNAME REQUESTOR CONDITION csr-9d7qd 43s kubernetes.io/kubelet-serving system:node:k8s00.99bill.com Approved,Issued csr-qzbmz 51s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:07401b Approved,Issued

證書有效期參數

--cluster-signing-duration

自動續簽證書請求參數(默認開啟)

--feature-gates=RotateKubeletServerCertificate=true

(可選)自動刪除過期token,在controller-manager添加參數,tokencleaner控制器負責這個工作。

--controllers=*,tokencleaner(默認開啟)

簽發證書配置:

為了批准csr,您需要告訴controller-manager批准它們是可以接受的。這是通過將RBAC權限授予正確的組來實現的。

有2種權限需要授予

* nodeclient: 如果一個節點正在為一個節點創建一個新證書,那么它還沒有證書。它使用上面列出的令牌之一進行身份驗證,因此是組system:bootstrappers的一部分

* selfnodeclient: 如果一個節點正在更新它的證書,那么它已經有一個證書,它作為組system:nodes進行驗證。

5. 配置證書自動簽發權限(僅針對)

證書簽發有CSR approving controllers實現,自動簽發只針對client證書。

創建clusterrole

# A ClusterRole which instructs the CSR approver to approve a user requesting
# node client credentials.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: system:certificates.k8s.io:certificatesigningrequests:nodeclient
rules:
- apiGroups: ["certificates.k8s.io"]
  resources: ["certificatesigningrequests/nodeclient"]
  verbs: ["create"]
---
# A ClusterRole which instructs the CSR approver to approve a node renewing its
# own client credentials.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
rules:
- apiGroups: ["certificates.k8s.io"]
  resources: ["certificatesigningrequests/selfnodeclient"]
  verbs: ["create"]

創建clusterrolebinding

#自動批准 kubelet 的首次 CSR 請求(用於與 apiserver 通訊的證書)

kubectl create clusterrolebinding auto-approve-csrs-for-group --clusterrole=system:certificates.k8s.io:certificatesigningrequests:nodeclient --group=system:bootstrappers

#自動批准 kubelet 后續 renew 用於與 apiserver 通訊證書的 CSR 請求

kubectl create clusterrolebinding auto-approve-renewals-for-nodes --clusterrole=system:certificates.k8s.io:certificatesigningrequests:selfnodeclient --group=system:nodes

#自動批准 kubelet 發起的用於 10250 端口鑒權證書的 CSR 請求(包括后續 renew)(下面用到的clusterrole是不會默認創建的,需要手工創建一下)

kubectl create clusterrolebinding node-server-auto-renew-crt --clusterrole=approve-node-server-renewal-csr --group=system:nodes

6. kubelet配置

kubelet加參數啟動

--feature-gates=RotateKubeletClientCertificate=true,RotateKubeletServerCertificate=true(1.12后默認開啟)
--rotate-certificates
--rotate-server-certificates
--bootstrap-kubeconfig="/var/lib/kubelet/bootstrap-kubeconfig"
--kubeconfig="/var/lib/kubelet/kubeconfig"

kubelet配置bootstrap需要以下東西:

* 存儲簽發好的證書的路徑(可以使用默認/var/lib/kubelet/pki)

* 存放kubeconfig文件的路徑(kubeconfig還不存在)

* bootstrap kubeconfig文件

* (可選)rotate證書

當kubelet啟動時,如果kubeconfig文件不存在,將使用bootstrap-kubeconfig文件

獲取到的證書將放在`--cert-dir`路徑下

7. Kubelet client和server證書

client證書:kubelet向kube-apiserver通信時,由於kubelet與kube-apiserver使用雙向認證,即不僅client端要驗證server端的身份,server也會驗證client端的身份,client證書即是kube-apiserver需要對client端的身份進行驗證的證書。

server證書:kubelet本身也會提供https服務,用的就是該證書。

可以使用參數指定client證書和key:

* --tls-private-key-file

* --tls-cert-file

如果沒有指定,則創建自簽的證書和key,然后向kube-apiserver請求簽發

注意:默認情況下,TLS bootstrap簽發的證書僅用於client auth,出於安全考慮,不會用於server auth。如果想要自動簽發server證書,打開RotateKubeletServerCertificate特性,並且自己實現一個自動簽發server證書的controller。但是,你也可以啟動服務器證書,至少支持kubelet發送證書輪詢請求,但是kube-controller-manager不能自動簽發。

六、kubelet自動續簽證書請求

默認情況下kube-apiserver簽發的證書有效期1年,當然可以調整kube-controller-manager參數`--cluster-signing-duration`(早期版本是`--experimental-cluster-signing-duration`)修改有效期,但是生產環境不建議將時間修改得太長。

kubelet開啟client證書輪詢:`--rotate-certificates`

kubelet開啟server證書輪詢:`--rotate-server-certificates`

開啟了參數之后,kubelet在證書將要到期的時候會向kube-apiserver發送續簽證書請求。

該功能需要kubelet開啟特性RotateKubeletClientCertificate(beta默認開始) 和 RotateKubeletServerCertificate(beta默認開啟)

https://kubernetes.io/docs/tasks/tls/certificate-rotation/

`注意:由於安全原因,在Kubernetes核心中實現的CSR審批控制器不審批節點serving證書。要使用RotateKubeletServerCertificate,需要運行自定義的審批控制器,或手動審批提供服務的證書請求。`

七、其它需要與kube-apiserver認證的組件

向kube-proxy以及一些監控組件可能也需要與kube-apiserver進行驗證,主要有以下方法:

①傳統老路:在kubelet進行TLS bootstrapping之前,可以手動生成可以通過驗證相關的證書及key

②DaemonSet:由於kubelet安裝成功之后就可以調度pod,你可以kube-proxy或特定服務封裝成Daemonset,放到kube-system命名空間中。由於在kubernetes集群內部,你就可以使用有相關權限的serviceaccount啟動你的pod

八、通過或拒絕證書請求

①手工通過請求:

kubectl get csr
kubectl describe csr <name>
kubectl certificate approve <name>
kubectl certificate deny <name>

②使用kube-controller-manager自動簽發

注意:server端證書不能自動簽發,需要自己手動簽發

九、參考

kubelet TLS Bootstrapping

https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/

TLS Bootstrap參考資料

https://mritd.me/2018/01/07/kubernetes-tls-bootstrapping-note/

生成CA及證書工具

https://kubernetes.io/docs/concepts/cluster-administration/certificates/

kubernetes集群證書

https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-authentication-authorization/

配置bootsrap token驗證方式

https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/

kubernetes集群相關證書種類及參數

https://kubernetes.io/docs/setup/best-practices/certificates/

配置證書輪詢

https://kubernetes.io/docs/tasks/tls/certificate-rotation/

利用CSR功能簽發集群認可的證書自己使用

https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster/

更新kubernetes集群CA

https://kubernetes.io/docs/tasks/tls/manual-rotation-of-ca-certificates/

v1.19.0中CSR相關介紹, Kubernetes v1.19 [stable]

https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM