You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GitHub Actions工作流无法访问Google Cloud Storage Bucket问题求助

Django测试GCS存储桶遇403权限错误?看这几点排查

问题情况

我写了个Django测试用例test_retrieve_bucket,用来测Google Cloud Storage(GCS)存储桶的访问。本地跑测试全过,但在GitHub Actions里执行就失败,报缺少storage.buckets.get权限。

测试代码

from django.test import TestCase
from google.cloud import storage
from datetime import datetime
from .models import Expense

class DemoTest(TestCase):
    def setUp(self):
        self.expense = Expense.objects.create(
            invoice_number = "ABC",
            account_number = "123",
            customer_name = "XYZ",
            invoice_amount = 12.50,
            invoice_date = datetime.now()
        )
    
    def test1(self):
        self.assertEqual(self.expense.invoice_number, "ABC")
    
    def test2(self):
        self.assertEqual(self.expense.account_number, "123")
    
    def test3(self):
        self.assertEqual(self.expense.customer_name, "XYZ")

    def test_retrieve_bucket(self):
        bucket_name = "test_bucket_8866"
        client = storage.Client()
        bucket = client.bucket(bucket_name)
        self.assertTrue(bucket.exists())

注:原代码缺少datetime和Expense模型的导入,本地能跑可能是环境隐含支持,但建议补上;另外原测试用return代替断言,Django测试框架不会识别这类逻辑,必须改成self.assertEqual这类官方断言方法。

报错信息

google.api_core.exceptions.Forbidden: 403 GET https://storage.googleapis.com/storage/v1/b/test_bucket_8866?fields=name&prettyPrint=false: test-service-account@tbi-finance.iam.gserviceaccount.com does not have storage.buckets.get access to the Google Cloud Storage bucket. Permission 'storage.buckets.get' denied on resource (or it may not exist).

已配置的GitHub Actions工作流

name: Django CI

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      max-parallel: 4
      matrix:
        python-version: [3.12.4]

    steps:
    - uses: actions/checkout@v4
    - name: auth
      uses: google-github-actions/auth@v2.0.0
      with:
        workload_identity_provider: 'projects/334572487877/locations/global/workloadIdentityPools/learn-github-actions-pool/providers/github-cdci'
        service_account: 'test-service-account@tbi-finance.iam.gserviceaccount.com'
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v3
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install Dependencies
      run: |
        pip install pipenv && pipenv install --system
    - name: Run Tests
      run: |
        python manage.py test
permissions:
  contents: 'read'
  id-token: 'write'

已完成的配置

  1. 通过Workload Identity Federation完成服务账号认证
  2. 给服务账号配置了Storage Object Admin权限
  3. 为工作负载身份池添加WorkloadIdentityUser角色,执行命令:
gcloud iam service-accounts add-iam-policy-binding "test-service-account@tbi-finance.iam.gserviceaccount.com" \
        --project="tbi-finance" \
        --role="roles/iam.workloadIdentityUser" \
        --member="principalSet://iam.googleapis.com/projects/334572487877/locations/global/workloadIdentityPools/learn-github-actions-pool/attribute.repository/duybtr/django_cdci"

排查与解决

关键问题

Storage Object Admin仅负责存储桶内对象的操作权限(如增删改查对象),不包含存储桶本身的读取权限——而bucket.exists()方法需要调用storage.buckets.get权限来确认桶是否存在,这就是报错的核心原因。

解决办法

  1. 给服务账号添加存储桶读取权限
    给test-service-account@tbi-finance.iam.gserviceaccount.com添加Storage Bucket Viewer角色(该角色包含storage.buckets.get权限),执行以下命令二选一即可:

    # 方式一:给整个项目添加权限(适用于需要访问多个桶的场景)
    gcloud projects add-iam-policy-binding tbi-finance \
      --member="serviceAccount:test-service-account@tbi-finance.iam.gserviceaccount.com" \
      --role="roles/storage.bucketViewer"
    
    # 方式二:仅给目标桶添加权限(更安全,遵循最小权限原则)
    gcloud storage buckets add-iam-policy-binding gs://test_bucket_8866 \
      --member="serviceAccount:test-service-account@tbi-finance.iam.gserviceaccount.com" \
      --role="roles/storage.bucketViewer"
    
  2. 验证权限是否生效
    执行命令查看目标桶的IAM配置,确认服务账号已拥有对应权限:

    gcloud storage buckets get-iam-policy gs://test_bucket_8866
    
  3. 修正测试代码的断言逻辑
    原测试中test1、test2、test3用return语句,Django测试框架不会将其识别为断言验证,必须改成self.assertEqual()这类官方断言方法,否则这些测试等于未执行验证逻辑。

  4. 确认GitHub Actions的认证状态
    可在工作流中添加步骤打印认证信息,确保服务账号身份已正确获取:

    - name: Check Auth Status
      run: |
        gcloud auth list
        gcloud config get-value account
    

额外建议

如果测试仅需要操作存储桶内的对象,无需验证桶是否存在,可以直接去掉bucket.exists()的调用,这样就能避免对storage.buckets.get权限的依赖。另外本地测试能通过,大概率是因为本地使用的认证方式(如gcloud CLI登录)权限更宽泛,而GitHub Actions中使用的服务账号是最小权限配置,因此需要精准配置权限。

内容的提问来源于stack exchange,提问作者auco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 04:57:34