[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。
- 常用命令
- 安装
- 安装Kubeadm
- 安装单Master集群
- 安装高可用集群(手动分发证书)
- 安装高可用集群(自动分发证书)
- 启动参数解析
- certificate-key
- ETCD相关参数
- Kubernetes端口汇总
- 安装IPv4-IPv6双栈集群
- 下载二进制文件
- 使用Kata容器
- 快速安装shell脚本
- 存储
- 实践
- Ceph-RBD实践
- CephFS实践
- 对象存储
- 阿里云CSI
- CSI
- 安全
- 认证与授权
- 认证
- 认证-实践
- 授权
- ServiceAccount
- NodeAuthorizor
- TLS bootstrapping
- Kubelet的认证
- 准入控制
- 准入控制示例
- Pod安全上下文
- Selinux-Seccomp-Capabilities
- 给容器配置安全上下文
- PodSecurityPolicy
- K8S-1.8手动开启认证与授权
- Helm
- Helm命令
- Chart
- 快速入门
- 内置对象
- 模板函数与管道
- 模板函数列表
- 流程控制
- Chart依赖
- Repository
- 开源的Chart包
- CRD
- CRD入门
- 工作负载
- Pod
- Pod的重启策略
- Container
- 探针
- 工作负载的状态
- 有状态服务
- 网络插件
- Multus
- Calico+Flannel
- 容器网络限速
- 自研网络插件
- 设计文档
- Cilium
- 安装Cilium
- Calico
- Calico-FAQ
- IPAM
- Whereabouts
- 控制平面与Pod网络分开
- 重新编译
- 编译kubeadm
- 编译kubeadm-1.23
- 资源预留
- 资源预留简介
- imagefs与nodefs
- 资源预留 vs 驱逐 vs OOM
- 负载均衡
- 灰度与蓝绿
- Ingress的TLS
- 多个NginxIngressController实例
- Service的会话亲和
- CNI实践
- CNI规范
- 使用cnitool模拟调用
- CNI快速入门
- 性能测试
- 性能测试简介
- 制作kubemark镜像
- 使用clusterloader2进行性能测试
- 编译clusterloader2二进制文件
- 搭建性能测试环境
- 运行density测试
- 运行load测试
- 参数调优
- Measurement
- TestMetrics
- EtcdMetrics
- SLOMeasurement
- PrometheusMeasurement
- APIResponsivenessPrometheus
- PodStartupLatency
- FAQ
- 调度
- 亲和性与反亲和性
- GPU
- HPA
- 命名规范
- 可信云认证
- 磁盘限速
- Virtual-kubelet
- VK思路整理
- Kubebuilder
- FAQ
- 阿里云日志服务SLS