GitLab CI/CD无JSON密钥连GCP,Terraform远程状态报403权限错误
问题根源
GitLab CI的每个Job都是独立运行在各自的容器环境中,彼此之间不会共享文件系统或认证状态。你在gcp-auth任务里完成的GCP认证,只会在该任务的容器内生效,不会自动传递到tf-stuff任务中,这就是Terraform初始化时触发403权限错误的原因。
解决方案
下面提供几种可落地的解决方式:
方法1:传递认证凭证作为Artifact
修改gcp-auth任务,将生成的认证凭证文件标记为Artifact,让后续任务可以下载使用:
gcp-auth: stage: auth image: google/cloud-sdk:slim script: - echo ${CI_JOB_JWT_V2} > .ci_job_jwt_file - gcloud iam workload-identity-pools create-cred-config ${GCP_WORKLOAD_IDENTITY_PROVIDER} --service-account="${GCP_SERVICE_ACCOUNT}" --output-file=.gcp_temp_cred.json --credential-source-file=.ci_job_jwt_file - gcloud auth login --cred-file=`pwd`/.gcp_temp_cred.json - gcloud auth list - gsutil cp test-file gs://your-state-bucket/ # 验证权限 artifacts: paths: - .gcp_temp_cred.json expire_in: 1h # 缩短凭证有效期,降低安全风险
接着修改tf-stuff任务,加载凭证文件并设置Terraform能识别的环境变量:
tf-stuff: stage: validate image: name: hashicorp/terraform:light entrypoint: - '/usr/bin/env' - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' before_script: - export TF_LOG=DEBUG - cd terraform - rm -rf .terraform - terraform --version # 设置GCP认证环境变量,让Terraform使用该凭证 - export GOOGLE_APPLICATION_CREDENTIALS="../.gcp_temp_cred.json" - terraform init script: - terraform validate
方法2:在tf-stuff任务内直接完成认证
既然每个Job独立,直接在tf-stuff里完成Workload Identity认证,省去文件传递步骤:
tf-stuff: stage: validate image: name: hashicorp/terraform:light entrypoint: - '/usr/bin/env' - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' before_script: - export TF_LOG=DEBUG # 安装gcloud SDK(terraform镜像默认不带) - apt-get update && apt-get install -y curl gnupg - echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list - curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - - apt-get update && apt-get install -y google-cloud-sdk # 执行Workload Identity认证流程 - echo ${CI_JOB_JWT_V2} > .ci_job_jwt_file - gcloud iam workload-identity-pools create-cred-config ${GCP_WORKLOAD_IDENTITY_PROVIDER} --service-account="${GCP_SERVICE_ACCOUNT}" --output-file=.gcp_temp_cred.json --credential-source-file=.ci_job_jwt_file - export GOOGLE_APPLICATION_CREDENTIALS=".gcp_temp_cred.json" - cd terraform - rm -rf .terraform - terraform --version - terraform init script: - terraform validate
方法3:直接传递临时访问令牌(推荐)
不用生成凭证文件,直接获取临时访问令牌传递给Terraform:
tf-stuff: stage: validate image: name: hashicorp/terraform:light entrypoint: - '/usr/bin/env' - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' before_script: - export TF_LOG=DEBUG # 安装gcloud SDK - apt-get update && apt-get install -y curl gnupg - echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list - curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - - apt-get update && apt-get install -y google-cloud-sdk # 生成认证配置并获取临时访问令牌 - echo ${CI_JOB_JWT_V2} > .ci_job_jwt_file - gcloud iam workload-identity-pools create-cred-config ${GCP_WORKLOAD_IDENTITY_PROVIDER} --service-account="${GCP_SERVICE_ACCOUNT}" --output-file=.gcp_temp_cred.json --credential-source-file=.ci_job_jwt_file - export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token --cred-file=.gcp_temp_cred.json) - cd terraform - rm -rf .terraform - terraform --version - terraform init script: - terraform validate
额外检查项
- 确认
GCP_SERVICE_ACCOUNT拥有目标GCS存储桶的roles/storage.objectAdmin或roles/storage.admin权限,确保能读写Terraform状态文件。 - 检查Terraform的backend配置是否正确指向存储桶,示例配置:
terraform { backend "gcs" { bucket = "your-terraform-state-bucket" prefix = "terraform/state" } }
内容的提问来源于stack exchange,提问作者Gary Turner
相关产品推荐
相关产品推荐

