如何从Google凭据中获取projectId?

3

我想使用Python获取Google Cloud上所有Dataproc集群的列表。

我有存储在JSON密钥文件中的服务帐户凭据,其位置由环境变量GOOGLE_APPLICATION_CREDENTIALS引用。这是我目前的代码:

import os
import googleapiclient.discovery
from oauth2client.client import GoogleCredentials


def build_dataproc_service(credentials):
    return googleapiclient.discovery.build("dataproc", "v1", credentials=credentials)


def list_clusters():
    credentials = GoogleCredentials.get_application_default()
    dataproc = build_dataproc_service(credentials)
    clusters = dataproc.projects().regions().clusters().list(projectId="my-project", region="REGION").execute()
    return clusters


if __name__ == "__main__":
    list_clusters()

如您所见,我已硬编码了projectId(“my-project”)。鉴于projectId存在于JSON密钥文件中,我希望我可以通过询问credentials对象的属性来获取它,但没有这样的属性。 projectId确实存在于 credentials._service_account_email 字符串属性中,但从那里提取它很笨重且感觉不对。我假定必须有更好的方法。如何获取服务帐户所在项目的projectId?请注意,最初我打算在Google Compute Engine实例上的docker容器中运行此代码,但将来可能想要在GKE上运行。不确定这是否会影响答案。
5个回答

4
一种正式的思考方式是,虽然projectId有时是“服务帐号”的属性,但projectId通常不是长期存在的“凭据”的属性。例如,想想你离线安装的个人凭据,与你的Google账户/电子邮件地址关联,如果有的话,那个电子邮件身份并不驻留在任何云项目中,但可以用来推导出一个GoogleCredential对象。
从技术上讲,如果要做到“正确”,您需要一个主服务帐号,该帐号具有权限获取所有持有您计划使用的实际服务帐号的项目中的服务帐号描述的权限,然后在服务帐号电子邮件地址而不是“凭据”对象上调用IAM API的projects.serviceAccounts.get。响应中可以确定服务帐号所在的项目ID。这相当于gcloud命令:
gcloud iam service-accounts describe my-service-account@projectid.iam.gserviceaccount.com

然而,正如Dagang所说,假设服务帐号仅用于其所在项目的操作往往会在长期内产生反效果。特别是,虽然服务帐号资源本身位于项目中,但它们经常以跨项目的方式使用。一种常见的操作模式是使用单个GCP项目来管理大量服务帐号,然后向其他GCP项目授予这些帐号对资源的各种细粒度访问权限。

所以听起来,我最好的选择是从计算引擎元数据服务器获取projectId。这假设我的代码正在运行在与Dataproc集群所在的同一个项目中,对我来说这是一个安全的假设。 - undefined
1
听起来是一个合理的方法。 - undefined

3

我认为客户端代码不应该从GoogleCredentials中提取项目ID。请参考API文档中的此代码片段。

from googleapiclient.discovery import build
from oauth2client.client import GoogleCredentials

credentials = GoogleCredentials.get_application_default()
service = build('compute', 'v1', credentials=credentials)

PROJECT = 'bamboo-machine-422'
ZONE = 'us-central1-a'
request = service.instances().list(project=PROJECT, zone=ZONE)
response = request.execute()

print(response)

您可能可以从credentials._service_account_email中推断出项目ID,但这并不可靠。此外,项目A中的服务帐号未绑定到该项目,也可能具有其他项目的权限。


2

在C#中

var credentials = GoogleCredential.GetApplicationDefault();
var projectId = (credentials.UnderlyingCredential as dynamic).ProjectId as string;

1
我不确定为什么你要将其转换为dynamic,而不是ServiceAccountCredential? - undefined
1
@StuartQ - 他这样做是因为ServiceAccountCredential类不包含ProjectId属性。这也是在.NET中对我有效的唯一答案。 - undefined

2
从UnderlyingCredential中获取ProjectId
var credential = GoogleCredential.FromFile(googleCredentialPath);
var projectId = ((Google.Apis.Auth.OAuth2.ServiceAccountCredential)credential.UnderlyingCredential).ProjectId;

这是什么语言? - undefined

2
服务账号凭据 .json 包含项目 ID,因此您可以执行以下操作:
# If this is running in a cloud function, then GCP_PROJECT should be defined
if 'GCP_PROJECT' in os.environ:
    project_id = os.environ['GCP_PROJECT']

# else if this is running locally then GOOGLE_APPLICATION_CREDENTIALS should be defined
elif 'GOOGLE_APPLICATION_CREDENTIALS' in os.environ:
    with open(os.environ['GOOGLE_APPLICATION_CREDENTIALS'], 'r') as fp:
        credentials = json.load(fp)
    project_id = credentials['project_id']
else:
    raise Exception('Failed to determine project_id')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接