ServiceAccount
Kubernetes中所有的访问,无论外部内部,都会通过API Server处理,访问Kubernetes资源前需要经过认证与授权。
- Authentication:用于识别用户身份的认证,Kubernetes分外部服务账号和内部服务账号,采取不同的认证机制,具体请参见认证与ServiceAccount。
- Authorization:用于控制用户对资源访问的授权,对访问的授权目前主要使用RBAC机制,将在RBAC介绍。
认证与ServiceAccount
Kubernetes的用户分为服务账户(ServiceAccount)和普通账户两种类型。
- 服务账户与Namespace绑定,关联一套凭证,Pod创建时挂载Token,从而允许与API Server之间调用。
- Kubernetes中没有代表普通账户的对象,这类账户默认由外部服务独立管理,比如在CCE的用户是由IAM管理的。
与Pod、ConfigMap类似,ServiceAccount是Kubernetes中的资源,属于命名空间级别。当创建一个新的命名空间时,系统会自动在其中生成一个名为default的ServiceAccount。
使用下面命令可以查看ServiceAccount。
kubectl get sa
NAME SECRETS AGE default 1 30d
- 1.21以前版本的集群中,Pod中获取Token的形式是通过挂载ServiceAccount的Secret来获取Token,这种方式获得的Token是永久的。该方式在1.21及以上的版本中不再推荐使用,并且根据社区版本迭代策略,在1.25及以上版本的集群中,ServiceAccount将不会自动创建对应的Secret。
1.21及以上版本的集群中,直接使用TokenRequest API获得Token,并使用投射卷(Projected Volume)挂载到Pod中。使用这种方法获得的Token具有固定的生命周期,并且当挂载的Pod被删除时这些Token将自动失效。详情请参见Token安全性提升说明。
- 如果您在业务中需要一个永不过期的Token,您也可以选择手动管理ServiceAccount的Secret。尽管存在手动创建永久ServiceAccount Token的机制,但还是推荐使用TokenRequest的方式使用短期的Token,以提高安全性。
1.25以前版本的集群中,ServiceAccount会自动创建对应的Secret。1.25及以上版本的集群中,ServiceAccount将不会自动创建对应的Secret。下面分别查看两种集群下的ServiceAccount状态。
- 1.25以前版本集群,查看名为default的ServiceAccount状态。
回显内容如下,说明default自动创建对应的Secret,即default-token-vssmw。
Name: default Namespace: default Labels: <none> Annotations: <none> Image pull secrets: <none> Mountable secrets: default-token-vssmw Tokens: default-token-vssmw Events: <none>
- 1.25及以上版本集群,查看名为default的ServiceAccount状态。
由回显内容可知,default未自动创建对应的Secret。
Name: default Namespace: default Labels: <none> Annotations: <none> Image pull secrets: <none> Mountable secrets: <none> Tokens: <none> Events: <none>
在Pod的定义文件中,可以用指定账户名称的方式将一个ServiceAccount赋值给一个Pod,如果不指定就会使用默认的ServiceAccount。当API Server接收到一个带有认证Token的请求时,API Server会用这个Token来验证发送请求的客户端所关联的ServiceAccount是否允许执行请求的操作。
创建ServiceAccount
- 以1.29版本集群为例,使用如下命令在default命名空间内创建ServiceAccount。
kubectl create serviceaccount sa-example
serviceaccount/sa-example created
使用以下命令可以检查sa-example是否创建成功,若NAME列出现sa-example则说明创建成功。
kubectl get sa
NAME SECRETS AGE default 1 30d sa-example 0 2s
由于本案例使用的集群版本在1.25以上,ServiceAccount将不会自动创建对应的Secret。使用以下命令可以查看创建的ServiceAccount的详细信息,回显中Mountable secrets和Tokens值为none,则说明该ServiceAccount没有自动创建Secret。
kubectl describe sa sa-example
Name: sa-example Namespace: default Labels: <none> Annotations: <none> Image pull secrets: <none> Mountable secrets: <none> Tokens: <none> Events: <none>
- 这里选择手动管理Secret,从而得到永不过期的Token。利用以下代码,手动创建名为sa-example-token的Secret,并与名为sa-example的ServiceAccount关联。
kubectl apply -f - <<EOF apiVersion: v1 kind: Secret metadata: namespace: default name: sa-example-token annotations: kubernetes.io/service-account.name: sa-example type: kubernetes.io/service-account-token EOF
- 检查sa-example-token是否创建成功。若命名空间default的Secrets中出现sa-example-token,则说明创建成功。
kubectl get secrets
NAME TYPE DATA AGE default-secret kubernetes.io/dockerconfigjson 1 6d20h paas.elb cfe/secure-opaque 1 6d20h sa-example-token kubernetes.io/service-account-token 3 16s
查看Secret的内容,可以发现ca.crt、namespace和token三个数据。
kubectl describe secret sa-example-token
Name: sa-example-token Namespace: default Labels: <none> Annotations: kubernetes.io/service-account.name: sa-example kubernetes.io/service-account.uid: 4b7d3e19-1dfe-4ee0-bb49-4e2e0c3c5e25 Type: kubernetes.io/service-account-token Data ==== ca.crt: 1123 bytes namespace: 7 bytes token: eyJhbGciOiJSU...
- 检验ServiceAccount与新建的Secret关联是否成功,即检查ServiceAccount是否获取到Token。由回显内容可知,sa-example与sa-example-token关联成功。
kubectl describe sa sa-example
Name: sa-example Namespace: default Labels: <none> Annotations: <none> Image pull secrets: <none> Mountable secrets: <none> Tokens: sa-example-token Events: <none>
在Pod中使用ServiceAccount
Pod中使用ServiceAccount非常方便,只需要指定ServiceAccount的名称即可。下面以“nginx:latest”为例,演示具体步骤。
- 创建一个名为sa-pod.yaml的描述文件。其中,mysql.yaml为自定义名称,您可以随意命名。
vim sa-pod.yaml
为了确保Pod能够使用手动创建的Secret中的Token,您需要明确地将该Secret挂载到容器中,挂载方式请参见描述文件中的加粗代码。
文件内容如下:
apiVersion: v1 kind: Pod metadata: name: sa-pod spec: serviceAccountName: sa-example # 指定sa-example为Pod使用的服务账户 imagePullSecrets: - name: default-secret containers: - image: nginx:latest name: container-0 resources: limits: cpu: 100m memory: 200Mi requests: cpu: 100m memory: 200Mi volumeMounts: # 将名为secret-volume的存储卷挂载到Pod - name: secret-volume readOnly: true # 表示挂载的存储卷是只读的 mountPath: "/etc/secret-volume" # 指定存储卷在容器内部的挂载路径,可以自定义 volumes: # 定义Pod可以使用的Secret存储卷 - name: secret-volume # 指定Secret存储卷的名称,可以自定义 secret: # 指定这个存储卷的类型为Secret secretName: sa-example-token # 将之前建立的sa-example-token挂载到定义的存储卷
- 创建并查看这个Pod,可以看到Pod挂载了sa-example-token,即Pod可以使用这个Token来做认证。
kubectl create -f sa-pod.yaml
回显内容如下:
pod/sa-pod created
使用以下代码,检验Pod是否创建成功。
kubectl get pod
回显内容如下,若sa-pod的状态为Running,则说明Pod创建成功
NAME READY STATUS RESTARTS AGE sa-pod 1/1 running 0 5s
- 查看sa-pod的具体信息,可以检验sa-example-token是否挂载成功。
kubectl describe pod sa-pod
回显内容如下:
... Containers: container-0: Container ID: Image: nginx:latest Image ID: Port: <none> Host Port: <none> State: Waiting Reason: ImagePullBackOff Ready: False Restart Count: 0 Limits: cpu: 100m memory: 200Mi Requests: cpu: 100m memory: 200Mi Environment: <none> Mounts: # 表示Pod已挂载sa-example-token,即Pod可以使用这个Token来做认证 /etc/secret-volume from secret-volume (ro) # 自动挂载的TokenRequest,可以提供短期的Token /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-2s4sw (ro) ...
进入Pod内部,还可以看到对应的文件,具体命令如下。其中,cd后的路径与secret-volume的挂载路径一致。
kubectl exec -it sa-pod -- /bin/sh
cd /etc/secret-volume
ls
回显内容如下:
ca.crt namespace token
- 验证手动创建的ServiceAccount Token能否生效。
- 在Kubernetes集群中,默认为API Server创建了一个名为kubernetes的Service,通过这个Service可以访问集群内的Pod资源。ctrl+d退出Pod后,使用以下命令可以查看该服务的具体信息。
回显内容如下:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.247.0.1 <none> 443/TCP 34
- 进入Pod,并检查Pod是否能够在不使用Token的情况下通过API Server访问集群内的Pod资源。
kubectl exec -it sa-pod -- /bin/sh
curl https://10.247.0.1:443/api/v1/namespaces/default/pods
回显结果如下,说明Pod不能直接通过API Server访问集群内的Pod资源。
curl: (60) SSL certificate problem: unable to get local issuer certificate More details here: https://curl.se/docs/sslcerts.html curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. To learn more about this situation and how to fix it, please visit the web page mentioned above.
- 设置ca.crt的环境变量。将ca.crt的路径设置到CURL_CA_BUNDLE环境变量中,这将指示curl命令使用该证书文件作为信任锚点。
- 将Token的内容放到TOKEN中。
TOKEN=$(cat /etc/secret-volume/token)
检验TOKEN是否设置成功。
echo $TOKEN
若回显内容如下,则设置成功。
eyJhbGciOiJSUzI1NiIsImtpZCI6I...
- 利用TOKEN访问API Server。
curl -H "Authorization: Bearer $TOKEN" https://10.247.0.1:443/api/v1/namespaces/default/pods
回显结果如下,则说明Pod能够通过认证,即手动创建的ServiceAccount Token能够生效。若API Server返回的是cannot get path \"/api/v1/namespaces/default/pods\"",则说明没有权限访问,需要得到授权才能访问,授权机制请参见RBAC。
"kind": "PodList", "apiVersion": "v1", "metadata": { "resourceVersion": "13267712" }, "items": [ { "metadata": { "name": "hpa-example-77b9b446f6-nc7b6", ...
- 在Kubernetes集群中,默认为API Server创建了一个名为kubernetes的Service,通过这个Service可以访问集群内的Pod资源。ctrl+d退出Pod后,使用以下命令可以查看该服务的具体信息。