在 Kubernetes 中,如何使用 Workload Identity 绑定代理?

解读

面试官真正想考察的是:

  1. 你是否理解 Workload Identity(WI) 在 Google Kubernetes Engine(GKE)中的定位——把 K8s ServiceAccount 映射成 Google IAM ServiceAccount,从而让 Pod 以“云原生”方式调用任何 Google Cloud API,包括 Cloud SQL。
  2. 你是否能把“绑定代理”这一动作落地:即 让 Cloud SQL Auth Proxy 容器以 WI 身份启动,而不是把 JSON 密钥挂在磁盘或环境变量里。
  3. 你是否清楚国内网络环境下 GKE 与 Google IAM 的连通性(需合规专线或 VPN),以及 IAM 条件绑定、最小权限、Pod 级隔离 等安全细节。
    回答时要体现“零密钥、零运维、可审计”三大优势,并给出可复制的 YAML 片段,才能打动考官。

知识点

  • Workload Identity 原理:GKE 元数据服务器把 Pod 的 K8s ServiceAccount 令牌换成 Google STS 令牌,最终拿到 IAM 凭据。
  • Cloud SQL Auth Proxy 工作模式:Sidecar 容器通过 Unix Socket 或 TCP 暴露 3307/5432/1433 端口,代表应用与 Cloud SQL 实例建立 TLS 加密的 IAM 认证通道
  • IAM 最小权限:只需授予代理使用的 Google ServiceAccount 角色 roles/cloudsql.client(国内项目常加条件 resource.name == "//sqladmin.googleapis.com/projects/xxx/instances/yyy")。
  • 国内落地差异
    – GKE 集群需 开启 Workload Identity 池(国内项目池命名格式 PROJECT_ID.svc.id.goog)。
    – 若无法直连 oauth2.googleapis.com,需在 VPC 出口 NAT 或 Cloud VPN 放通 accounts.google.com:443sqladmin.googleapis.com:443
  • Terraform 模板:用 google_service_account_iam_bindingroles/iam.workloadIdentityUser 绑定到 K8s ServiceAccount 的 member 字符串 serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]
  • 安全加固
    – 给 Pod 加 securityContext.fsGroup=65534 保证 Socket 可读。
    – 用 PodDisruptionBudget 保证代理容器先于业务容器终止,防止连接闪断。

答案

步骤一:创建 Google ServiceAccount 并授权

export PROJECT_ID=my-gcp-project
export SQL_INSTANCE=my-project:us-central1:mydb
gcloud iam service-accounts create sql-proxy-gsa \
  --display-name="GKE Cloud SQL proxy identity"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member="serviceAccount:sql-proxy-gsa@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role="roles/cloudsql.client"

步骤二:启用集群 Workload Identity 并建立映射

gcloud container clusters create my-cluster \
  --region=us-central1 \
  --workload-pool=${PROJECT_ID}.svc.id.goog
kubectl create namespace demo
kubectl create serviceaccount sql-proxy-ksa -n demo
gcloud iam service-accounts add-iam-policy-binding \
  sql-proxy-gsa@${PROJECT_ID}.iam.gserviceaccount.com \
  --role=roles/iam.workloadIdentityUser \
  --member="serviceAccount:${PROJECT_ID}.svc.id.goog[demo/sql-proxy-ksa]"
kubectl annotate serviceaccount -n demo sql-proxy-ksa \
  iam.gke.io/gcp-service-account=sql-proxy-gsa@${PROJECT_ID}.iam.gserviceaccount.com

步骤三:部署带代理的 Pod(以 MySQL 为例)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
  namespace: demo
spec:
  replicas: 2
  selector:
    matchLabels: {app: webapp}
  template:
    metadata:
      labels: {app: webapp}
    spec:
      serviceAccountName: sql-proxy-ksa          # 关键:使用已绑定 WI 的 KSA
      containers:
      - name: app
        image: registry.cn-shanghai.aliyuncs.com/myrepo/app:1.2.0
        env:
        - name: DB_SOCKET
          value: "/cloudsql/my-project:us-central1:mydb"
      - name: cloudsql-proxy
        image: gcr.io/cloudsql-docker/gce-proxy:1.33.0
        command: ["/cloud_sql_proxy",
                  "-instances=my-project:us-central1:mydb=tcp:0.0.0.0:3307",
                  "-use_http_health_check",
                  "-credential_file="]               # 空值即强制走 WI
        securityContext:
          runAsNonRoot: true
          runAsUser: 65534
        resources:
          requests: {cpu: "50m", memory: "64Mi"}

步骤四:验证

kubectl exec -n demo deploy/webapp -c app -- \
  mysql -u myuser -p --host=127.0.0.1 --port=3307 --ssl-mode=REQUIRED

若成功登录,说明 Workload Identity 已代替传统密钥完成代理认证

拓展思考

  1. 多集群复用:把 IAM 条件绑定attribute.kubernetes_namespace 可实现同一 Google ServiceAccount 被多个 GKE 集群共享,但每个集群只能访问指定命名空间,降低密钥爆炸风险。
  2. 审计与排障:国内项目常因 VPC 出口 IP 变化 导致 STS 调用失败,可在 Cloud Logging 过滤 protoPayload.methodName="GenerateAccessToken" 查看拒绝原因;同时给代理加 -verbose=true 把日志打到 stdout,便于在 阿里云日志服务 SLS 做二次聚合。
  3. 零信任延伸:结合 Binary AuthorizationIAM Conditions,可限定只有 签名校验通过且来自指定命名空间 的 Pod 才能拿到 Cloud SQL 访问令牌,实现“代码-身份-网络”三重校验,满足国内金融云合规要求。