使用ServiceAccount Token卷投影

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卷投影功能,无需手动操作。如需升级集群,请参见手动升级集群1.png

    集群的系统组件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
EOF

ServiceAccount创建完成后,您可以执行kubectl get serviceaccounts/build-robot -o yaml命令查看该ServiceAccount的完整信息。

步骤二:部署使用ServiceAccount Token投影的Pod应用

您可以将该ServiceAccount以卷的形式投射到Pod中,Pod中的容器便可以使用该Token访问集群API Server,并使用该ServiceAccount来进行身份验证。例如,您可以指定Token的audience、有效期限(expirationSeconds)等属性,将其投射到一个Pod应用中。

  1. 使用以下示例代码,创建nginx.yaml文件,其中Pod声明了需要使用audiencevault且有效期限为2个小时的ServiceAccount。

    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
    spec:
      containers:
      - image: nginx
        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
  2. 执行以下命令,部署使用卷投影的Pod应用。

    kubectl apply -f nginx.yaml
  3. 验证该Pod中挂载的Token的有效期。

    1. 执行以下命令,确认Pod已正常运行。

      kubectl get pod nginx

      预期输出:

      NAME    READY   STATUS    RESTARTS   AGE
      nginx   1/1     Running   0          3m15s
    2. 下载Pod容器中挂载的Token。

      kubectl exec -t nginx -- cat /var/run/secrets/tokens/vault-token > vault-token
    3. 执行以下命令,获取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)。