GitHub Actions Docker环境下R的bigrquery无法通过WIF认证
问题:GitHub Actions中WIF认证下gcloud可正常工作但bigrquery无法识别凭证
问题背景
开发基于GitHub Actions的工作流,通过Workload Identity Federation(WIF)向Google Cloud认证。容器内的gcloud CLI命令可成功完成认证并执行BigQuery操作,但R的bigrquery包始终无法识别凭证,所有认证尝试均失败。
工作流相关代码片段
# Step 3: Authenticate to Google Cloud via Workload Identity Federation - name: Authenticate to Google Cloud uses: google-github-actions/auth@v2.1.7 id: auth with: workload_identity_provider: ${{ secrets.WIF_PROVIDER }} service_account: ${{ secrets.WIF_SERVICE_ACCOUNT }} token_format: "access_token" create_credentials_file: true # Step 5: Docker login to Artifact Registry using the WIF token - name: Docker login to Artifact Registry run: | echo ${{ steps.auth.outputs.access_token }} | docker login -u oauth2accesstoken --password-stdin https://${{ env.location }}-docker.pkg.dev # Step 6: Pull the specified Docker image - name: Pull Docker image run: docker pull ${{ env.location }}-docker.pkg.dev/${{ env.project }}/${{ env.repository }}/base-image:latest - name: Debug for google auth in R run: | docker run --rm \ -v ${{ steps.auth.outputs.credentials_file_path }}:/gcp/creds.json:ro \ -e GOOGLE_APPLICATION_CREDENTIALS=/gcp/creds.json \ -e SUPABASE_API_URL="${{ secrets.SUPABASE_API_URL }}" \ -e SUPABASE_SERVICE_KEY="${{ secrets.SUPABASE_SERVICE_KEY }}" \ -e GCP_PROJECT=${{ env.project}} \ ${{ env.location }}-docker.pkg.dev/${{ env.project }}/${{ env.repository }}/base-image:latest \ sh -c ' gcloud auth login --cred-file=/gcp/creds.json gcloud config set project $GCP_PROJECT bq ls --project_id=$GCP_PROJECT --format=prettyjson # works fine # 以下R代码均认证失败 # Rscript -e "library(bigrquery); bq_auth(use_oob = TRUE); print(bq_project_datasets($GCP_PROJECT))" # Rscript -e "library(bigrquery); bq_auth(path = \"/gcp/creds.json\"); print(bq_project_datasets($GCP_PROJECT))" # Rscript -e "library(bigrquery); library(gargle); gargle_token <- gargle::credentials_service_account(path = \"/gcp/creds.json\", scopes = \"https://www.googleapis.com/auth/cloud-platform\"); bq_auth(token = gargle_token); print(bq_project_datasets(${{ env.GCP_PROJECT }}))" # Rscript -e "library(bigrquery); library(gargle); gargle_token <- gargle::credentials_app_default(scopes = \"https://www.googleapis.com/auth/cloud-platform\"); bq_auth(token = gargle_token); print(bq_project_datasets(${{ env.GCP_PROJECT }}))" # Rscript -e "library(bigrquery); library(gargle); gargle_token <- gargle::credentials_external_account(path = Sys.getenv(\"GOOGLE_APPLICATION_CREDENTIALS\"), scopes = \"https://www.googleapis.com/auth/cloud-platform\"); bq_auth(token = gargle_token); print(bq_project_datasets(${{ env.GCP_PROJECT }}))" '
可正常运行的操作
- WIF认证流程:GitHub Actions成功获取访问令牌并生成凭证JSON文件。
- 容器内gcloud命令:
gcloud auth login --cred-file=/gcp/creds.json gcloud config set project ${{ env.GCP_PROJECT }} bq ls --project_id=${{ env.GCP_PROJECT }} --format=prettyjson
以上命令均可正常执行,说明gcloud层面的认证完全正常。
无法运行的操作
所有尝试用bigrquery(及底层gargle包)认证的R代码均失败,尝试过的方式包括:
# 方式1 library(bigrquery) bq_auth(use_oob = TRUE) # 方式2 library(bigrquery) bq_auth(use_oob = FALSE) # 方式3 library(bigrquery) bq_auth(path = "/gcp/creds.json") # 方式4 library(bigrquery) library(gargle) gargle_token <- gargle::credentials_service_account(path = "/gcp/creds.json", scopes = "https://www.googleapis.com/auth/cloud-platform") bq_auth(token = gargle_token) # 方式5 library(bigrquery) library(gargle) gargle_token <- gargle::credentials_external_account(path = Sys.getenv("GOOGLE_APPLICATION_CREDENTIALS"), scopes = "https://www.googleapis.com/auth/cloud-platform") bq_auth(token = gargle_token)
所有方式执行bq_project_datasets(${GCP_PROJECT})时均返回错误:
Error in `bq_auth()`: ! Can't get Google credentials. ℹ Try calling `bq_auth()` directly with necessary specifics.
原因分析与解决方案
核心原因
WIF生成的是外部账户凭证(External Account Credentials),而非传统的服务账户密钥文件:
- gcloud CLI针对WIF做了专门适配,能自动识别这种凭证格式;
- 旧版gargle/bigrquery可能对外部账户凭证支持不足,且
credentials_service_account仅适用于传统服务账户密钥,无法处理WIF凭证。
具体解决方案
1. 更新依赖包到最新版
确保bigrquery和gargle是最新版本,以支持WIF外部账户凭证:
install.packages(c("bigrquery", "gargle")) # 若需要最新特性,可安装开发版 # remotes::install_github("r-lib/gargle") # remotes::install_github("r-dbi/bigrquery")
2. 正确使用外部账户凭证认证
明确使用gargle::credentials_external_account加载WIF凭证,并指定BigQuery所需的权限范围:
Rscript -e 'library(bigrquery); library(gargle); # 加载WIF外部账户凭证 token <- gargle::credentials_external_account( path = Sys.getenv("GOOGLE_APPLICATION_CREDENTIALS"), scopes = "https://www.googleapis.com/auth/bigquery" ); bq_auth(token = token); print(bq_project_datasets(Sys.getenv("GCP_PROJECT")))'
3. 验证环境变量与文件权限
- 确认
GOOGLE_APPLICATION_CREDENTIALS和GCP_PROJECT环境变量在容器内已正确传递; - 挂载的凭证文件已设置为可读(
:ro参数已正确添加)。
4. 开启调试模式定位问题
若仍失败,开启gargle的调试模式查看详细日志:
Rscript -e 'library(gargle); gargle::gargle_debug_on(); library(bigrquery); token <- gargle::credentials_external_account( path = Sys.getenv("GOOGLE_APPLICATION_CREDENTIALS"), scopes = "https://www.googleapis.com/auth/bigquery" ); bq_auth(token = token); print(bq_project_datasets(Sys.getenv("GCP_PROJECT")))'
5. 替代方案:复用gcloud的访问令牌
利用gcloud已认证的状态,提取访问令牌直接给bigrquery使用:
修改Docker的sh -c脚本:
sh -c ' gcloud auth login --cred-file=/gcp/creds.json gcloud config set project $GCP_PROJECT bq ls --project_id=$GCP_PROJECT --format=prettyjson # 获取gcloud的访问令牌 ACCESS_TOKEN=$(gcloud auth print-access-token) # 传递令牌给R并认证 Rscript -e "library(bigrquery); bq_auth(token = Sys.getenv(\"ACCESS_TOKEN\")); print(bq_project_datasets(Sys.getenv(\"GCP_PROJECT\")))" '
同时在docker run命令中添加环境变量传递:-e ACCESS_TOKEN=$ACCESS_TOKEN
内容的提问来源于stack exchange,提问作者Jed Toner
相关产品推荐
相关产品推荐

