ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
[TOC] 前面两篇文章我们介绍了从外部访问Apiserver的安全端口时,客户端需要携带一个身份凭证,能够让apiserver认证为某个用户以及所属的组。在集群的容器中,有时也需要访问apiserver。既然要访问API,那么就必须要携带身份凭证,然后能够被apiserver认证出来并进行授权。这就是本节要介绍的内容--ServiceAccount ## **一、使用流程** 我们简化一个场景:我现在要创建一个Pod,从Pod中去获取集群的节点列表(`GET /api/v1/nodes`)。 那么使用ServiceAccount如何满足这个需要呢?很简单,只需要以下四步: #### **1.1 创建ServiceAccount** ``` kubectl create serviceaccount peng --namespace default ``` #### **1.2 授权ServiceAccount** 创建以下的ClusterRole与ClusterRoleBinding ``` apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: list-nodes rules: - apiGroups: - "" resources: - nodes verbs: - list ``` ``` apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: approve-list-nodes roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: list-nodes subjects: - kind: ServiceAccount name: peng namespace: default ``` #### **1.3 创建Pod,使用ServiceAccount** 使用以下的yaml文件创建Pod ``` apiVersion: v1 kind: Pod metadata: namespace: default name: pod-nginx spec: serviceAccountName: peng containers: - image: nginx:1.11.5 name: pod-nginx ``` #### **1.4 从Pod中访问API** 在Pod中执行以下的脚本,就能够获取集群的节点列表 ``` #!/bin/bash ServiceAccountToken=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) CaCrt="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" curl -H "Authoriztion: Bearer ${ServiceAccountToken}" --cacert ${CaCrt} https://kubernetes:443/api/v1/nodes ``` ## **二、原理** 接下来,我们详细地介绍一下上面每一步发生的事情,以及API请求能够被通过的原理。 > 注意:此内容只适用于k8s 1.22以前的版本,k8s 1.22开始,已开始变化。(见如下说明: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#manually-create-an-api-token-for-a-serviceaccount) #### **2.1 创建ServiceAccount** ``` kubectl create serviceaccount sa1 --namespace default ``` 我们使用如上的命令在`default`命令空间中创建了一个名字为`peng`的SerivceAccount后,我们来看一下这个ServiceAccount的内容。创建之后ServiceAccount的内容如下,它有名字、命名空间,以及一个Secret ``` $ kubectl get serviceaccount peng -o yaml apiVersion: v1 kind: ServiceAccount metadata: name: peng namespace: default uid: 75532a3a-f936-11e8-91da-000c29719bda secrets: - name: peng-token-hps6w ``` 那么这个Secret是如何来的呢?答案是,对于每一个ServiceAccount,controller-manager都会为它创建一个Secret。我们来看一下这个Secret的内容,如下。我们可以看到,该Secret的类型为`kubernetes.io/service-account-token`,然后`data`中有三个字段,这三个字段的值都是经过base64编码的 ``` apiVersion: v1 kind: Secret metadata: name: peng-token-hps6w namespace: default type: kubernetes.io/service-account-token data: ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNE1URXlNVEEzTkRBMU0xb1hEVEk0TVRFeE9EQTNOREExTTFvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTVQxCmRMTm9TYWQwK1J3MjEzdWhiZjNXM0l5UE5hZUxmQ3dDWko3bnVNVGZlSzBqeGdveHNnczQybVF5MkNkbEdsdzQKVWJPejhTcFhlSW4yRC9MREFmeEtqZGc0cWh5YllISmJjK1ZNVGVRRXNQb2VBejdBVWJDQ2hqMmlWdjlHK3p2QgpHWmtobXIzOUI4NWxuSklJTSsvRlliazBTbjBNdVhPc3BGZVJLK3lqbklZeXpxSEtTWVk4aW5SSDhhaExlUlNNCkFCTUVtRndyME1EdWdCR2YrbzFlQU5hamI0QzZ2K3NXV3B6Z01EelhEV1VoSTRpNzRVWHE5KzZOTDlMUGVFOTcKYTY3Yit1SE1DSTl1emg5WjlPcTV3QkY1OS8ram1QT1BzY2lrTnVSVkNEZHZ6enF2VzdjRERLUU1YcXpCYUxKQgpVVENZcDl2aml6c3J1bkpFTDNFQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFGMThHR3JvQmRCNytxa0xvM1RHOEJqTDE2SmcKTm9tL1E0cWJGdHZsaTQwbjZ5Z001cUdqNmI3VTRVT2NaRjl4aDd6cGxWVXJkM0Z0OGhKYjhnOThRaFYxbDVHNwo4a1RQWThQcnAxN2UxWlRjOVdGMXUzZXM4Y2p6VmVFOFAxMEE5c3JqY3ZDNldONnhiK2FNc2E0aEFJbEJ3WjNwCmErSFhhTVhLbVRGaE9KZHJ5QTBNcFJLdTB2eEl5VlNVVU5BdUtYZlk4L3d0bk1VR0JLK0FJTDF3OTRUZ2wxb2sKQ1J1MGhkWEtmek0xWnU0d0hzQVQrcVhWcWR2cUg4UGFWaHc0U2NRcmRlL2o5anBFckwvMUJaSXlBU0J2MndSdwpBZ2VOc3pnZDlRaVRmTWh6QXBLU3gyN2VseHhYRStObGJKbmJBeFJXdkQ2WHZJTmlKUDZuUFQ2eUF3UT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= namespace: ZGVmYXVsdA== token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklpSjkuZXlKcGMzTWlPaUpyZFdKbGNtNWxkR1Z6TDNObGNuWnBZMlZoWTJOdmRXNTBJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5OXpaWEoyYVdObFlXTmpiM1Z1ZEM5dVlXMWxjM0JoWTJVaU9pSmtaV1poZFd4MElpd2lhM1ZpWlhKdVpYUmxjeTVwYnk5elpYSjJhV05sWVdOamIzVnVkQzl6WldOeVpYUXVibUZ0WlNJNkluQmxibWN0ZEc5clpXNHRhSEJ6Tm5jaUxDSnJkV0psY201bGRHVnpMbWx2TDNObGNuWnBZMlZoWTJOdmRXNTBMM05sY25acFkyVXRZV05qYjNWdWRDNXVZVzFsSWpvaWNHVnVaeUlzSW10MVltVnlibVYwWlhNdWFXOHZjMlZ5ZG1salpXRmpZMjkxYm5RdmMyVnlkbWxqWlMxaFkyTnZkVzUwTG5WcFpDSTZJamMxTlRNeVlUTmhMV1k1TXpZdE1URmxPQzA1TVdSaExUQXdNR015T1RjeE9XSmtZU0lzSW5OMVlpSTZJbk41YzNSbGJUcHpaWEoyYVdObFlXTmpiM1Z1ZERwa1pXWmhkV3gwT25CbGJtY2lmUS5hWVZzSkROYkFBWVU5bDJZUWtBSkpxNHZ5Z0hjSmVVYlkwa0lzOEtCRG81WFcwcS1XR3prc1BCMjdPTFFhWWpSd2lwRmNpLUdXM2lXZ2QtMDdVaWVkempJbnFyU3dWZExkRjhDSTJHaWFaT3FrNERGWTM2ZDd3RFFNY0xObDJ1aHFxbEVjWk1lQ2VWbnMwaHQxNGJQRFpGaFJiUmFTbWRTek9UT3NoclFFQ3UzRzBNRkVWVFg5V3U3em5Rdm5Kd0hHU0dOQjF1MmZiSVFkS0xMcHA1ZUlEWEZLaEMtZHVqUFNydmxITXVWRjdISmVvQ1dPWXNLYUdSTFN2dl82Z1BJZm5DeEY1eEZDajdzTmgzOHZha2g5cWpHcDBHUWJHUTBuclFNWGZCbjhKV3pzR2xtQ1Z6TjdMWjlBSF9HOEFwS0UzQjV3b1k2MXNsLTVtTTFrM19la2c= ``` 我们来介绍一下`data`中的三个字段是怎么生成的 * `ca.crt`:它来自于controller-manager的启动参数`--root-ca-file`指定的文件内容 * `namespace`:该Secret的namespace,与其所属的ServiceAccount的namespace一致 * `token`:把该字段解码后,你会发现其实它是一个JWT(可以把它进行base64解码后,拷贝到 [jwt.io](jwt.io) 网站查看原始内容),它的signature加密所使用的密钥是由controller-manager的启动参数`--service-account-private-key-file`所指定,它的payload如下, ``` { "iss": "kubernetes/serviceaccount", "kubernetes.io/serviceaccount/namespace": "default", "kubernetes.io/serviceaccount/secret.name": "peng-token-hps6w", "kubernetes.io/serviceaccount/service-account.name": "peng", "kubernetes.io/serviceaccount/service-account.uid": "75532a3a-f936-11e8-91da-000c29719bda", "sub": "system:serviceaccount:default:peng" } ``` #### **2.2 创建Pod,使用ServiceAccount** 我们按照前面yaml文件创建Pod,那么apiserver将会把该ServiceAccount的Secret挂载到Pod的路径`/var/run/secrets/kubernetes.io/servicaccount`下。创建之后我们`kubectl get`一下这个Pod,发现yaml文件如下 ``` apiVersion: v1 kind: Pod metadata: name: pod-nginx namespace: default spec: containers: - image: nginx:1.11.5 name: pod-nginx volumeMounts: - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: peng-token-hps6w readOnly: true serviceAccount: peng serviceAccountName: peng volumes: - name: peng-token-hps6w secret: defaultMode: 420 secretName: peng-token-hps6w ``` 我们去到这个pod的内部,查看目录`/var/run/secrets/kubernetes.io/servicaccount`下的内容,发现该目录下有三个文件ca.crt、namesapce与token,且它们的内容就是secret中的对应字段的值通过base64解码得到的 ``` $ pwd /var/run/secrets/kubernetes.io/servicaccount $ ls ca.crt namespace token $ cat namespace default ``` 这个时候,我们就可以按照前面给的方法从Pod中去访问apiserver,如下 ``` #!/bin/bash ServiceAccountToken=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) CaCrt="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" curl -H "Authoriztion: Bearer ${ServiceAccountToken}" --cacert ${CaCrt} https://kubernetes:443/api/v1/nodes ``` #### **2.3 认证** apiserver收到了Pod里面的curl进程发来的请求,Header中包含了`"Authoriztion: Bearer ${ServiceAccountToken}"`。那么apiserver如何认证这个ServiceAccountToken呢?首先,apiserver必须要开启serviceaccount的准入机制,即在启动参数中声明`--admission-control=*,serviceaccount`。然后,然后apiserver的serviceaccount认证器拿到这个ServiceAccountToken后,利用参数`--service-account-key-file`指定的公钥文件对这个token进行验证。验证通过后,该token就会被认证为`subject: { kind: ServiceAccount, name: peng, namesapce: default}`以及`subject: { kind: User, name: system:serviceaccount:default:peng}` #### **2.4 授权** 在第二步中,我们创建了相应的授权规则,对`subject: { kind: ServiceAccount, name: peng, namesapce: default}`进行了授权,所以能够curl的请求能够通过。当然,由于该token也会被认证为`subject: { kind: User, name: system:serviceaccount:default:peng}`,我们也可以对该用户授权,curl的访问也是可以通过的。 ## **三、扩展阅读** #### **3.1 启动参数配置** 要使用serviceaccount,kube-apiserver与kube-controller-manager需要配置一定的参数 **kube-apiserver** * `--admission-control=*,serviceaccount` * `--service-account-key-file=/path/to/public-key.file` **kube-controller-manager** * `--serivce-account-private-key-file=/path/to/private-key.file` * `--root-ca-file=/path/to/ca.crt` #### **3.2 其他知识点** * controller-manager会为每个namespace自动创建一个名字叫`default`的ServiceAccount * controller-manager会为每个ServiceAccount自动创建一个Secret * 如果Pod没有指定使用哪个ServiceAccount,则apiserver会默认为该Pod配置Pod所属的命名空间下的`default`名字的ServiceAccount ## **四、K8S >= 1.22** #### **4.1 kube-api-access volume** 上面的机制只适用于K8S < 1.22的版本,对于1.22及以后的版本,ServiceAccount的机制有所变化,参考 [service-accounts-admin](https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin)。 我们创建一个如下的Pod(注意先创建好test这个serviceAccount): ``` apiVersion: v1 kind: Pod metadata: name: busybox spec: serviceAccountName: test containers: - name: busybox image: docker.io/library/busybox:latest imagePullPolicy: IfNotPresent command: ["tail", "-f", "/dev/null"] ``` 然后我们可以查看Pod的yaml文件,发现多了一个projected的volume(实际上是kube-apiserver中的ServiceAccount Admission Controller自动注入的): ``` $ kubectl get pod busybox -o yaml apiVersion: v1 kind: Pod metadata: creationTimestamp: "2023-08-30T06:12:19Z" name: busybox namespace: default uid: 0e473379-db12-4f63-b771-401a6c698243 spec: containers: - command: - tail - -f - /dev/null image: docker.io/library/busybox:latest imagePullPolicy: IfNotPresent name: busybox volumeMounts: - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: kube-api-access-b6xjz readOnly: true volumes: - name: kube-api-access-b6xjz projected: defaultMode: 420 sources: - serviceAccountToken: expirationSeconds: 3607 # 告知kubelet请求token时携带的过期时间参数 path: token # 容器挂载目录下的文件名 - configMap: items: - key: ca.crt path: ca.crt name: kube-root-ca.crt - downwardAPI: items: - fieldRef: apiVersion: v1 fieldPath: metadata.namespace path: namespace ... ``` 我们进入到容器中,去到`/var/run/secrets/kubernetes.io/serviceaccount`目录下,查看文件及内容: ``` $ ls /var/run/secrets/kubernetes.io/serviceaccount ca.crt namespace token $ cat /var/run/secrets/kubernetes.io/serviceaccount/token eyJhbGciOiJSUzI1NiIsImtpZCI6IkU4OEtFczlIc2lrSmJicDFMUlJjZU5sRUlzUDMxYXZlNlBvWVNHangzbHMifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzI0OTExOTM5LCJpYXQiOjE2OTMzNzU5MzksImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJidXN5Ym94IiwidWlkIjoiMGU0NzMzNzktZGIxMi00ZjYzLWI3NzEtNDAxYTZjNjk4MjQzIn0sInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJ0ZXN0IiwidWlkIjoiNzA5Yzk5MmQtNGU3ZS00NjFkLWJmZjYtYzRjN2RkNGY4YmQxIn0sIndhcm5hZnRlciI6MTY5MzM3OTU0Nn0sIm5iZiI6MTY5MzM3NTkzOSwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6dGVzdCJ9.Vuznc430UQEWWpEV-6eL-HcaIUstHTieUWyt7fh88NvXYX5lj18cGlLlRdTTpCeX6k6lMJDTiZkHnE2fBPyJA01wogVAT9Vv4ydBV2YFPxYHyR7RsZT6W-MNQ0JgQqGQWOGnicKE8Y862cR08RG0j3O-ADgcNJU5G1UgLklQmsz0UTpWtEJSPixHtD_ycbLTcr8jVoZCKaV_hSANVFXFhQx0h4ZmV4ZalI59Oj6ZXBTwdZqduOBthjdHu7K1jk5fjQU6RiH03aRjw7iQtJxJMfDTIHX3qROR2EjzReyQ-zE3ruJVDGuKtwErIs0b4sq8WfAXAPhckUrUh2mz4ZmG1A ``` 上面的token文件的内容,是kubelet通过TokenReqeust接口生成,我们把上面的内容放到 [jwt.io](jwt.io) 网站中解码,payload内容如下: ``` { "aud": [ "https://kubernetes.default.svc.cluster.local" ], "exp": 1724911939, # 2024-08-29 14:12:19 +0800 "iat": 1693375939, # 2023-08-30 14:12:19 +0800 "iss": "https://kubernetes.default.svc.cluster.local", "kubernetes.io": { "namespace": "default", "pod": { "name": "busybox", "uid": "0e473379-db12-4f63-b771-401a6c698243" }, "serviceaccount": { "name": "test", "uid": "709c992d-4e7e-461d-bff6-c4c7dd4f8bd1" }, "warnafter": 1693379546 }, "nbf": 1693375939, "sub": "system:serviceaccount:default:test" } ``` 这里有点奇怪, 这个token的有效期为365天,和projected volumes中指定的3607秒不一致,可能kubelet在请求token时,忽略了tokenExpirationSeconds这个参数。 #### **4.2 手动请求一个Token** 我们可能使用kubectl命令手动申请一个有效时间为3600秒的test这个serviceaccount的token(实验发现kubectl-1.23没有kubectl create token这个命令,下面的kubectl及k8s集群版本为1.26;另外是没有kubectl get token这个命令的) ``` $ kubectl create token test --duration 1h eyJhbGciOiJSUzI1NiIsImtpZCI6IkU4OEtFczlIc2lrSmJicDFMUlJjZU5sRUlzUDMxYXZlNlBvWVNHangzbHMifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjkzMzc5ODg5LCJpYXQiOjE2OTMzNzYyODksImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0Iiwic2VydmljZWFjY291bnQiOnsibmFtZSI6InRlc3QiLCJ1aWQiOiI3MDljOTkyZC00ZTdlLTQ2MWQtYmZmNi1jNGM3ZGQ0ZjhiZDEifX0sIm5iZiI6MTY5MzM3NjI4OSwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6dGVzdCJ9.hQx-LfBiKRevtkzhXvvkN0lIPlwb3uhHShA3BTvIIHYwxYbrHviTr0zoBxiCbxjU8_X3kPEoDhJg3Fb3bmnVAQ1YDo_JoHqSfpepoxhU-5QY1kKS0B2Intnyh85V6sHeMYCo5RTbcmAxGGmmvD_GF31aqkFhb6bT_6mNt-PuXuFLTBX06S9LF9hQaoDNXS4mQZ_qZSiCdqb6jsl9SXkmdH5QAj3ZzdziRGp95s24teyXidvgHRFTWbeAv-KqUPzLUT0msi_bDhyr3fkTv06scjlfiRH5Hl4c0AWn3evNnIpWPn7t2UJPkFGoGBNsp9UW7FuS2gkIz0OBtuLuZcMi9A ``` 然后,该命令就会返回一个token。我们这个token拷贝到 [jwt.io](jwt.io) 网站上,查看它的payload,如下: ``` { "aud": [ "https://kubernetes.default.svc.cluster.local" ], "exp": 1693379889, "iat": 1693376289, "iss": "https://kubernetes.default.svc.cluster.local", "kubernetes.io": { "namespace": "default", "serviceaccount": { "name": "test", "uid": "709c992d-4e7e-461d-bff6-c4c7dd4f8bd1" } }, "nbf": 1693376289, "sub": "system:serviceaccount:default:test" } ``` 其实上面的kubectl create toekn命令,就是调用了TokenRequest的POST请求。TokenReqeust的API参考 [token-request-v1](https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/token-request-v1/) 。我们用curl命令来调用一下这个接口,申请一个token。 首先,我们在master上用kubectl做一个反向代理,这样curl调用时就不用认证: ``` $ kubectl proxy --address 0.0.0.0 Starting to serve on [::]:8001 ``` 然后,我们就可以通过master主机的8001端口进行请求(实测发现只能通过127.0.0.1,通过master主机的其他IP访问会报401,可能是为了安全) 该接口详情参考 [http-request](https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/token-request-v1/#http-request),需要注意:(1)body参数中的metadata.name必须与serviceaccount的名字一致,比如这里我们请求是test这个sa的token (2)文档中要求body参数中的 spec.audiences 为 required,但是发现没填也没问题 ``` $ curl -X POST -H 'Content-Type: application/json; charset=utf-8' http://127.0.0.1:8001/api/v1/namespaces/default/serviceaccounts/test/token -d '{"apiVersion":"authentication.k8s.io/v1","kind":"TokenRequest","metadata":{"name":"test"},"spec":{"expirationSeconds":3600}}' { "kind": "TokenRequest", "apiVersion": "authentication.k8s.io/v1", "metadata": { "name": "test", "namespace": "default", "creationTimestamp": "2023-08-30T08:27:18Z", "managedFields": [ { "manager": "curl", "operation": "Update", "apiVersion": "authentication.k8s.io/v1", "time": "2023-08-30T08:27:18Z", "fieldsType": "FieldsV1", "fieldsV1": { "f:spec": { "f:expirationSeconds": {} } }, "subresource": "token" } ] }, "spec": { "audiences": [ "https://kubernetes.default.svc.cluster.local" ], "expirationSeconds": 3600, "boundObjectRef": null }, "status": { "token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IkU4OEtFczlIc2lrSmJicDFMUlJjZU5sRUlzUDMxYXZlNlBvWVNHangzbHMifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjkzMzg3NjM4LCJpYXQiOjE2OTMzODQwMzgsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0Iiwic2VydmljZWFjY291bnQiOnsibmFtZSI6InRlc3QiLCJ1aWQiOiI3MDljOTkyZC00ZTdlLTQ2MWQtYmZmNi1jNGM3ZGQ0ZjhiZDEifX0sIm5iZiI6MTY5MzM4NDAzOCwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6dGVzdCJ9.lRYpxoK3UoUMpCyF1DWZ3TTWrwdJ1V26o-BapmjExss-lkKCqlRzTUyaJFrmtJVcHy29IfQ-pBR2fZrVDGa1WX4_8yTx40gaLimzwascaPSk4m-ebq6GGiEQ_PTKspiRg4ecDYQCZ0qkEtgrCeRt0xFmKFcee_xavoxRpE7FAfgz69G6Sa3zs4A-V65SMDHUIOrDc_QbzGd_VU9HMrdzy8UoQARmsFvjDQwo49uSniXSAmiBVzTz1ICEsREBSW5aaWspxTPqFxGwaLxfTf54Qb64FAzfu1q0Pjmpt9xZBTXa3m_fAmPLMIDowFnOyg2H0K0c49i673oT_HEz2tdEfg", "expirationTimestamp": "2023-08-30T09:27:18Z" } } ``` 我们把返回的TokenRequest.Status.Token拷贝到jwt.io进行查看,payload内容如下: ``` { "aud": [ "https://kubernetes.default.svc.cluster.local" ], "exp": 1693387638, "iat": 1693384038, "iss": "https://kubernetes.default.svc.cluster.local", "kubernetes.io": { "namespace": "default", "serviceaccount": { "name": "test", "uid": "709c992d-4e7e-461d-bff6-c4c7dd4f8bd1" } }, "nbf": 1693384038, "sub": "system:serviceaccount:default:test" } ``` #### **4.3 手动创建不过期的Secret** 当然,我们也可以继续使用以前的方法,此时我们只需要 [手动创建](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#manually-create-a-long-lived-api-token-for-a-serviceaccount) 一个如下的Secret,在annotation中指明关联的ServiceAccount: ``` apiVersion: v1 kind: Secret metadata: name: coredns annotations: kubernetes.io/service-account.name: coredns type: kubernetes.io/service-account-token ``` 这样,controller-manager便会自动填充secret中的三个字段。apiserver会为Pod像以前一样的机制添加secret类型的volume。