ServiceAccount Token作为身份验证的凭证,使Pod中运行的应用程序可以安全地与Kubernetes API进行通信。为解决传统的ServiceAccount Token以Secret的形式自动挂载到Pod中可能带来的安全风险,您可以通过ACK的服务账户令牌卷投影功能,使Pod以卷投影的形式将ServiceAccount Token或其他相关证书挂载到容器中,减少Secret的暴漏风险。
功能介绍
ServiceAccount是Pod和集群API Server通讯的访问凭证。传统方式下,在Pod中使用ServiceAccount可能会面临以下挑战:
- ServiceAccount中的JSON Web Token (JWT) 没有绑定 - audience身份,因此所有ServiceAccount的使用者都可以彼此扮演,存在伪装攻击的可能。
- 传统方式下,每个ServiceAccount都需要存储在一个对应的Secret中,并且会以文件形式存储在对应的应用节点上,而集群的系统组件在运行过程中也会使用到一些权限很高的ServiceAccount,这增大了集群控制面的攻击面,攻击者可以通过获取这些管控组件使用的ServiceAccount非法提权。 
- ServiceAccount中的JWT Token没有设置过期时间,当上述ServiceAccount泄露情况发生时,您只能通过轮转ServiceAccount的签发私钥来进行防范,而client-go中还不支持这样的自动化流程,这需要一个繁琐的手动运维流程。 
- 每一个ServiceAccount都需要创建一个与之对应的Secret,在大规模的应用部署下存在弹性和容量风险。 
ServiceAccount Token卷投影特性用于增强ServiceAccount的安全性,以更安全、更灵活的方式向Pod提供ServiceAccount相关的认证信息。ServiceAccount Token卷投影可使Pod以卷投影的形式将ServiceAccount挂载到容器中,从而避免了对Secret的依赖。
前提条件
- 已创建ACK托管集群、ACK专有集群、ACK Serverless集群,且集群版本为1.20及以上。具体操作,请参见创建ACK托管集群、创建ACK专有集群(已停止新建)、创建集群。 
- 已在创建集群的过程中启用ServiceAccount Token卷投影功能。 - 1.22及以上版本的集群默认启用ServiceAccount Token卷投影功能,无需手动操作。如需升级集群,请参见手动升级集群。  - 集群的系统组件API Server和Controller Manager会自动开启绑定ServiceAccount Token卷投影的特性门控,同时在API Server的启动参数中增加以下配置。 - 参数 - 说明 - 默认值 - 控制台配置 - service-account-issuer - ServiceAccount Token中的签发身份,即Token payload中的 - iss字段。- https://kubernetes.default.svc - 支持。 - api-audiences - 合法的请求Token身份,用于API Server服务端认证请求Token是否合法。 - https://kubernetes.default.svc - 支持。可以配置多个 - audience,通过英文半角逗号- ,分割。- service-account-signing-key-file - Token签名私钥文件路径。 - /etc/kubernetes/pki/sa.key - 不支持。默认使用/etc/kubernetes/pki/sa.key,无需配置。 
步骤一:创建一个ServiceAccount对象
每个命名空间会存在一个默认的default ServiceAccount,您可以通过kubectl get serviceaccounts命令来查看。如果您需要为Pod中运行的进程提供其他身份标识,您可以参见以下代码创建一个新的ServiceAccount。
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: build-robot
EOFServiceAccount创建完成后,您可以执行kubectl get serviceaccounts/build-robot -o yaml命令查看该ServiceAccount的完整信息。
步骤二:部署使用ServiceAccount Token卷投影的Pod应用
您可以将该ServiceAccount以卷的形式投射到Pod中,Pod中的容器便可以使用该Token访问集群API Server,并使用该ServiceAccount来进行身份验证。例如,您可以指定Token的audience、有效期限(expirationSeconds)等属性,将其投射到一个Pod应用中。
- 使用以下示例代码,创建nginx.yaml文件,其中Pod声明了需要使用 - audience为- vault且有效期限为2个小时的ServiceAccount。- apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6 name: nginx volumeMounts: - mountPath: /var/run/secrets/tokens name: vault-token serviceAccountName: build-robot volumes: - name: vault-token projected: sources: - serviceAccountToken: path: vault-token expirationSeconds: 7200 audience: vault
- 执行以下命令,部署使用卷投影的Pod应用。 - kubectl apply -f nginx.yaml
- 验证该Pod中挂载的Token的有效期。 - 执行以下命令,确认Pod已正常运行。 - kubectl get pod nginx- 预期输出: - NAME READY STATUS RESTARTS AGE nginx 1/1 Running 0 3m15s
- 下载Pod容器中挂载的Token。 - kubectl exec -t nginx -- cat /var/run/secrets/tokens/vault-token > vault-token
- 执行以下命令,获取Token过期时间。 - cat vault-token |awk -F '.' '{print $2}' |base64 -d 2>/dev/null |jq '.exp' | xargs -I {} date -d @{}- 示例输出: - 一 8 26 15:45:59 CST 2024
 
- 请您确保Pod中能够实时获取到轮转后最新的Token,也就是确保Pod逻辑中能够定期重新加载目标Token(建议为5分钟)。官方Kubernetes在client-go 10.0.0版本后已经支持自动获取最新的Token。 
- 容器中ServiceAccount对应的Token文件属性不再是644,在使用绑定ServiceAccount Token卷投影时,对应的Token文件属性已经改为600(使用fsGroup特性时为640)。