如何验证服务帐户以针对 GDrive Sheet 支持的 BigQuery Table 进行查询?

How do I Authenticate a Service Account to Make Queries against a GDrive Sheet Backed BigQuery Table?

我的情况如下:

Google 账户 A 在 BigQuery 中有一些数据。

Google账户 B 管理账户 A 的 BigQuery 数据,并且还被授予账户 A 的 Cloud Platform 项目的编辑权限。

帐户 B 在 Google 驱动器中有一个 Sheet,其中有一些很酷的参考数据。账户 B 登录到 BQ Web 控制台,并在账户 A 的 BQ 项目中创建一个 table 并以此 sheet.

为后盾

一切顺利。帐户 B 可以从网络 UI.

在帐户 A 的 BQ 数据中成功查询并加入此 table

问题:

Google 账户 A 还有一个服务账户,它是 Google 账户 A 的云平台项目的编辑者。此服务帐户使用 python google-云 API 管理和查询 BQ 中的数据。当此服务帐户尝试查询由帐户 B 的 GDrive Sheet 支持的引用 table 时,作业失败并出现此错误:

Encountered an error while globbing file pattern.  JobID: "testing_gdrivesheet_query_job1"

据我所知,这实际上是一个身份验证问题。我如何才能为帐户 A 的服务帐户授予对帐户 B 的 GDrive 的适当访问权限,以便它可以访问该引用 table?

奖励积分: GDrive Sheet 支持的 table 与原生 BQ table 之间是否存在任何性能差异?

您应该能够通过以下步骤进行操作:

首先将 sheet 分享给与服务帐户关联的电子邮件/"service account id"。

如果您使用 bigquery 和驱动器范围创建客户端,那么您将能够访问 sheet 支持的 table。 (您可能需要在服务帐户上启用全域委派)。

scopes = ['https://www.googleapis.com/auth/bigquery', 'https://www.googleapis.com/auth/drive']

credentials = ServiceAccountCredentials.from_json_keyfile_name(
'<path_to_json>', scopes=scopes)

# Instantiates a client
client = bigquery.Client(project = PROJECT, credentials = credentials)

bqQuery = client.run_sync_query(q)
bqQuery.run()
bqQuery.fetch_data()

虽然 Orbit 的回答帮助我找到了问题的解决方案,但您还需要考虑一些其他事项。因此,我想添加我对问题的详细解决方案。如果 Orbit 的基本解决方案不起作用,特别是如果您使用 G Suite 并且您的策略不允许与域外的帐户共享 sheets/docs,则需要此解决方案。在这种情况下,您不能直接与服务帐户共享 doc/sheet。

开始之前:

  1. 在您的项目中创建或select一个service account
  2. 启用Domain-wide委派(DwD) in the account settings。如果不存在,这将为服务帐户生成一个 OAuth 客户端 ID。
  3. 确保委派 user@company.com 可以访问 sheet。
  4. 将所需的范围添加到您服务帐户的 OAuth 客户端(您可能需要让 G Suite 管理员为您执行此操作):

    • https://www.googleapis.com/auth/bigquery
    • https://www.googleapis.com/auth/drive

如果委托用户可以在 BigQuery UI 中访问您的 drive-based table,您的服务帐户现在应该也可以代表委托用户访问它。

这是对我有用的完整代码片段:

#!/usr/bin/env python

import httplib2
from google.cloud import bigquery
from oauth2client.service_account import ServiceAccountCredentials

scopes = [
    "https://www.googleapis.com/auth/drive",
    "https://www.googleapis.com/auth/bigquery",
]

delegated_user = "user@example.com"
project        = 'project-name'
table          = 'dataset-name.table-name'
query          = 'SELECT count(*) FROM [%s:%s]' % (project, table)

creds = ServiceAccountCredentials.from_json_keyfile_name('secret.json', scopes=scopes)
creds = creds.create_delegated(delegated_user)

http = creds.authorize(httplib2.Http())
client = bigquery.Client(http=http)

bq = client.run_sync_query(query)
bq.run()
print bq.fetch_data()

请注意,我无法直接设置委托,需要使用 creds = creds.create_delegated(delegated_user)http = creds.authorize(httplib2.Http()) 创建一个 HTTP 客户端。然后可以将授权的 HTTP 客户端用作 BigQuery 客户端的 HTTP 客户端:client = bigquery.Client(http=http).

另请注意,服务帐户不需要在项目设置中分配任何预定义角色,即,您不必将其设置为 bigquery 用户甚至项目所有者。我想它主要通过授权获得访问权限。

对于那些尝试通过 Airflow 或 Google Cloud Composer 执行此操作的人,您需要执行两个主要步骤来完成此操作。

  1. 授予 project_name@developer.gserviceaccount.com 电子表格的查看权限。这应该是您用来访问 Google BigQuery 的同一个服务帐户。这可以在表格 GUI 中或以编程方式完成。

  2. 将以下范围添加到 Airflow 中的 Google 云连接:

然后您将能够查询引用 Google 个工作表的外部表。

只需要从 答案中添加步骤。您可以在 Airflow UI 菜单“管理”->“连接”-> 选择您的连接中找到气流连接。在我的例子中,我还需要在气流连接

中添加您的服务帐户的密钥文件路径或密钥文件JSON

基于此引用 https://cloud.google.com/composer/docs/how-to/managing/connections#creating_a_connection_to_another_project