从GKE通过spring-cloud-gcp访问GCS遇403权限拒绝问题排查
有两种简单方式可以确认应用当前使用的身份:
在Spring应用中添加身份打印逻辑
新增一个CommandLineRunner组件,启动时打印当前凭据对应的账号:import com.google.auth.oauth2.GoogleCredentials; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; @Component public class CredentialValidator implements CommandLineRunner { @Override public void run(String... args) throws Exception { GoogleCredentials credentials = GoogleCredentials.getApplicationDefault(); System.out.println("当前GCS访问身份: " + credentials.getAccount()); } }或者开启spring-cloud-gcp的DEBUG日志,在配置文件中添加:
logging.level.com.google.cloud.spring.core=DEBUG启动日志中会包含凭据加载的详细信息,包括使用的账号。
在GKE Pod内直接查询
先进入目标Pod:kubectl exec -it <你的Pod名称> -- /bin/bash然后通过令牌解析获取身份:
# 获取默认应用凭据的访问令牌 TOKEN=$(gcloud auth application-default print-access-token) # 调用OAuth2接口解析令牌信息 curl -H "Authorization: Bearer $TOKEN" https://www.googleapis.com/oauth2/v3/tokeninfo返回结果中的
email字段就是当前用于GCS访问的账号。
按以下顺序逐一排查:
确认Workload Identity绑定关系
检查GCP服务账号是否给K8s服务账号分配了workloadIdentityUser角色:gcloud iam service-accounts get-iam-policy <GCP服务账号邮箱>确认输出中存在
serviceAccount:<你的GKE项目ID>.svc.id.goog[<命名空间>/<K8s服务账号>]的条目,且角色为roles/iam.workloadIdentityUser。
同时检查K8s服务账号的注解是否正确:kubectl describe sa <K8s服务账号> -n <命名空间>确保
iam.gke.io/gcp-service-account注解的值是目标GCP服务账号的完整邮箱。验证GCP服务账号的权限范围
不要仅依赖"编辑"角色,直接测试所需的GCS权限:# 测试创建桶和写入对象的权限(替换为你的资源) gcloud iam service-accounts test-iam-permissions <GCP服务账号邮箱> \ --permissions storage.buckets.create,storage.objects.create \ --resource=<你的GCP项目ID> # 创建桶需要项目级权限如果是写入已有桶,把
--resource替换为gs://<你的桶名称>,测试桶级的写入权限。检查应用配置是否覆盖默认凭据
确认应用没有通过配置强制指定其他凭据:# 检查Pod内是否存在覆盖凭据的环境变量 kubectl exec -it <Pod名称> -- env | grep GOOGLE_APPLICATION_CREDENTIALS同时检查Spring配置文件(application.yml/properties)中是否设置了
spring.cloud.gcp.credentials.location,该配置会优先于Workload Identity/Compute Engine的默认凭据。确认GCS桶的IAM策略
检查目标桶的IAM权限是否包含当前使用的GCP服务账号:gsutil iam get gs://<你的桶名称>确保账号拥有
roles/storage.objectCreator或更高权限(如roles/storage.admin)。验证集群Workload Identity配置
确认集群已正确启用Workload Identity:gcloud container clusters describe <集群名称> --zone <集群区域> | grep workloadIdentityConfig确保
workloadPool字段存在且格式为<你的GCP项目ID>.svc.id.goog。
内容的提问来源于stack exchange,提问作者random alpha

