使用 GitHub Actions 向 Google Workload Identity Federation 进行身份验证,以获得在 Python 脚本中使用的凭据

问题描述 投票:0回答:1

TL;DR 如何获取并使用凭证在 Python 脚本中与 Google 产品交互(使用 Workload Identity Federation 和 GitHub Actions)。代码在文章最后

我的手指上长满了老茧,在网上搜索了超过 8 个小时,并想在这里发布相关的搜索词来帮助下一个可怜的灵魂。

这受到了这个拯救了我生命的答案的启发:https://stackoverflow.com/a/72370925/15187444

具体用例:

  • 我想在 cron 作业中运行 Python 脚本。该脚本调用 Google API 向电子表格添加行
  • Google 现在建议使用工作负载身份联合进行身份验证。这是有道理的。密钥仅为作业创建,然后删除,这意味着不会长期存储敏感 API 密钥

问题:

  • 这些文档令人困惑,并且根据上面链接的答案,看起来很多人正在观看似乎已经过时的教程

解决方案:

  • 要创建作业,您需要启用 GitHub Actions,并编写一个协调您的作业的 YAML 文件
  • 此 YAML 文件将向 Google 进行身份验证,运行您的脚本,然后执行任何关闭操作

需要采取一些步骤(设置服务帐户、下载适当的库等),这些步骤相当简单且易于实施。我会让您阅读文档来自己完成所有设置。

关键步骤:

如果您的提供商没有正确的属性映射,Google 将无法识别您的服务帐户。设置提供程序是工作负载身份联合设置文档的一部分。

您可能见过这样的错误:

"error": {
    "code": 403,
    "message": "Permission 'iam.serviceAccounts.getAccessToken' denied on resource (or it may not exist).",
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "IAM_PERMISSION_DENIED",
        "domain": "iam.googleapis.com",
        "metadata": {
          "permission": "iam.serviceAccounts.getAccessToken"
        }
      }
    ]
  }
}

或者这个:

google.auth.exceptions.RefreshError: ('Unable to acquire impersonated credentials', '{\n  "error": {\n    "code": 403,\n    "message": "Permission \'iam.serviceAccounts.getAccessToken\' denied on resource (or it may not exist).",\n    "status": "PERMISSION_DENIED",\n    "details": [\n      {\n        "@type": "type.googleapis.com/google.rpc.ErrorInfo",\n        "reason": "IAM_PERMISSION_DENIED",\n        "domain": "iam.googleapis.com",\n        "metadata": {\n          "permission": "iam.serviceAccounts.getAccessToken"\n        }\n      }\n    ]\n  }\n}\n')

要设置正确的属性,请按照以下屏幕截图操作:

编辑您的提供商

Click Workplace Identity Federation Tab, then click here to edit your provider

编辑页面如下所示。映射属性,如第二个屏幕截图所示

First screenshot Second screenshot

另一件事需要注意的是,为了连接,您需要使用

identity_pool
库中的
google-auth
类,而不是
service_account
类。您可以在 Python 脚本中看到这一点,我们在导入
credentials = Credentials.from_info(key)
 后使用 
from google.auth.identity_pool import Credentials

如果您使用

credentials = service_account.Credentials.from_service_account_info(key)
,您将收到此错误,因为通常的服务帐户密钥具有与工作负载身份联合生成的凭据不同的形状/架构:

raise exceptions.MalformedError(
google.auth.exceptions.MalformedError: Service account info was not in the expected format, missing fields token_uri, client_email.

代码:

将数据附加到 Google 电子表格的 Python 脚本:

#!/usr/bin/env python

import json
import os
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from google.auth.identity_pool import Credentials

SCOPES = ["https://www.googleapis.com/auth/spreadsheets.readonly"]

SPREADSHEET_ID = 'YOUR_SPREADSHEET_ID'
RANGE = 'YOUR_RANGE'

f = open(os.environ["GOOGLE_APPLICATION_CREDENTIALS"])
key = json.load(f)

def append_to_spreadsheet(values, value_input_option="USER_ENTERED"):
    credentials = Credentials.from_info(key)
    append_body = {
        "values": values,
        "range": RANGE,
        "majorDimension": "ROWS",
        }
    try:
        service = build("sheets", "v4", credentials=credentials)

        service.spreadsheets().values().append(
            spreadsheetId=SPREADSHEET_ID,
            range=RANGE,
            body=append_body,
            valueInputOption=value_input_option,
        ).execute()

    except HttpError as error:
        print(error)

append_to_spreadsheet([['value1', 'value2']])

用于 GitHub Actions 运行作业的 YAML 文件:

name: name_of_your_job

on:
  workflow_dispatch:

jobs:
  build:
    permissions:
      contents: 'read'
      id-token: 'write'
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - id: 'auth'
      name: 'Authenticate to Google Cloud'
      uses: 'google-github-actions/auth@v2'
      with:
        workload_identity_provider: "projects/<PROJECT_ID>/locations/global/workloadIdentityPools/<POOL_NAME>/providers/<PROVIDER_NAME>"
        service_account: "<enter your service account email>"
        token_format: 'access_token'
    - name: Setup python
      uses: actions/setup-python@v5
      with: 
        python-version: '3.11'
    - name: install python packages
      run:
        python -m pip install --upgrade pip
        pip install requests google-api-python-client google-auth-httplib2 google-auth-oauthlib google-auth
    - name: call google api
      run: python google.py

这是一篇信息性帖子。我希望能够帮助其他人避免痛苦:)

google-cloud-platform google-oauth google-auth-library
1个回答
0
投票

使用 GitHub Actions 的 Google Drive API 身份验证问题

我根据 Google GitHub Actions Auth 文档 创建了我的工作负载身份池,没有任何服务帐户。然后我尝试连接到 Google Drive,这需要 OAuth 2.0 访问令牌。我使用了以下配置:

- name: Authenticate with Google Cloud
    uses: 'google-github-actions/auth@v2'
    with:
        project_id: 'my-project'
        workload_identity_provider: 'projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider'

- name: Upload files to Google Drive
    uses: 'Burak-Atak/drive-upload@master'
    with:
      google_credentials_file_path: ${{ env.GOOGLE_APPLICATION_CREDENTIALS }}
      files_to_create: "app.spec"
      drive_folder_id: "242fgdfg345345"
      files_to_update: "requirements.txt"
      file_ids_to_update: "asdas3534fdgg"

但是,我使用以下代码收到以下错误:

def authenticate_google(self):
    credentials, project_id = load_credentials_from_file(
        os.environ["GOOGLE_APPLICATION_CREDENTIALS"],
        scopes=[
            'https://www.googleapis.com/auth/drive.file',
            'https://www.googleapis.com/auth/drive',
            'https://www.googleapis.com/auth/drive.metadata'
        ]
    )

    return build("drive", "v3", credentials=credentials)
googleapiclient.errors.HttpError: <HttpError 401 when requesting https://www.googleapis.com/upload/drive/v3/files?fields=id&alt=json&uploadType=multipart returned "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.". Details: "[{'message': 'Invalid Credentials', 'domain': 'global', 'reason': 'authError', 'location': 'Authorization', 'locationType': 'header'}]">

我意识到我应该为 Google Drive API 使用 OAuth 2.0。然后我将配置更改为:

- name: Authenticate with Google Cloud
  uses: google-github-actions/auth@v2
  with:
    workload_identity_provider: 'projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider'
    project_id: '<PROJECT_ID>'
    service_account: '<PROJECT_ID>@<PROJECT_ID>.iam.gserviceaccount.com'
    token_format: 'access_token'
    access_token_lifetime: '60s'
    access_token_scopes: 'https://www.googleapis.com/auth/drive.file,https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/drive.metadata'

- name: Upload files to Google Drive
    uses: 'Burak-Atak/drive-upload@master'
    with:
      google_credentials_file_path: ${{ env.GOOGLE_APPLICATION_CREDENTIALS }}
      files_to_create: "app.spec"
      drive_folder_id: "242fgdfg345345"
      files_to_update: "requirements.txt"
      file_ids_to_update: "asdas3534fdgg"

进行此更改后,即使我的服务帐户中具有 Service Account Token CreatorOwner 角色,我也开始收到以下错误:

google-github-actions/auth failed with: failed to generate Google Cloud OAuth 2.0 Access Token for <PROJECT_ID>@<PROJECT_ID>.iam.gserviceaccount.com: {
  "error": {
    "code": 403,
    "message": "Permission 'iam.serviceAccounts.getAccessToken' denied on resource (or it may not exist).",
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "IAM_PERMISSION_DENIED",
        "domain": "iam.googleapis.com",
        "metadata": {
          "permission": "iam.serviceAccounts.getAccessToken"
        }
      }
    ]
  }
}

解决方案

我发现我应该向我的工作负载池添加一个服务帐户。检查 Google Cloud Console 中的“连接的服务帐户”部分。如果没有连接的服务帐户,您应该添加一个。

Cloud Console Workload Identity Pool

© www.soinside.com 2019 - 2024. All rights reserved.