如何使用 Google 云 API(直接或使用 GCP PHP 客户端 SDK)以编程方式从 GCP 项目中列出、添加和删除用户?

How do I use the Google Cloud APIs (directly or using the GCP PHP Client SDK) to List, Add, and Remove Users from a GCP project programmatically?

简要总结:我有一个 PHP 网络应用程序,它使用 Google 云 PHP 客户端 SDK 与 Dialogflow 集成。那没问题。我现在需要让我的用户直接访问 GCP Dialogflow 仪表板,这部分意味着他们需要能够 add/remove 从我的应用程序中向用户授予 Dialogflow 权限。 (出于显而易见的原因,我不想给他们完整的项目 IAM 权限和访问权限)。

显然,权限由单独的“Google APIs PHP 的客户端库”处理。

这似乎是用于列出现有项目用户策略的 API:https://cloud.google.com/resource-manager/reference/rest/v1/projects/listOrgPolicies

我认为这是 add/remove 用户部分的 API,但不是那么明显:https://cloud.google.com/resource-manager/reference/rest/v1/projects/setIamPolicy

===

问题:

但是,当我 运行 上面引用的 listOrgPolicies API 中提供的示例代码时,我得到这个错误:

PHP Fatal error:  Uncaught Error: Class 'Google_Service_CloudResourceManager_ListOrgPoliciesRequest' not found

composer require google/apiclient-servicescomposer require google/apiclient-services:dev-master 我都试过了。得到了相同的结果。

===

我的问题是:

这些甚至是正确的 API 任务吗?

在哪里可以找到这些操作的 SDK 库? (或者,如果有人对如何在不使用 SDK 的情况下使用 PHP cURL 直接向 API 执行这些任务提出了建议)

我希望所有操作都发生在 PHP 中,但如果您有使用其他方法或语言或控制台命令行的有效解决方案,只要它可以由我的应用程序执行我可以使用它。

提前致谢!

在获得答案之前,请确保 Resource Manager API 已启用。这对于 REST 方法和程序化方法是必需的。

要修改给定项目中用户的 IAM 绑定,需要调用两个端点,这两个端点已记录在案 here。那些将是:

  1. 获取当前 IAM 配置:https://cloud.google.com/resource-manager/reference/rest/v1/projects/getIamPolicy
  2. 要设置新的 IAM 策略:https://cloud.google.com/resource-manager/reference/rest/v1/projects/setIamPolicy

在第 1 步和第 2 步之间,需要修改第一个端点返回的 json,或者添加具有您选择的角色的用户,或者从中删除用户条目。要查看 add/remove 用户所需的 json 结构是什么,我建议检查上面共享的 link 以及检查第一个命令返回的有效负载。

虽然直接调用 REST api 是您的一种选择,但您也可以使用 gcloud CLI 来执行此类操作。由于用户似乎将 added/removed 一个接一个地使用命令行,因此命令行将是一个简单的选择,而且它需要较少的设置。这两个操作的命令是:

/ To add user role
gcloud projects add-iam-policy-binding PROJECT_ID --member=user:somebody@example.com --role=roles/viewer

/ To remove user role
gcloud projects remove-iam-policy-binding PROJECT_ID --member=user:somebody@example.com --role=roles/viewer

第三种选择是以编程方式进行。虽然我想提供一个 PHP 示例,但我没有足够的语言经验,但下面是一个允许 add/remove 角色的 Python 脚本。它是从 Quickstart 引导而来的,只做了一些小的改动,从我 运行 的测试来看,它应该可以正常工作。

# TODO: Install required libraries
# pip3 install --upgrade google-api-python-client google-auth google-auth-httplib2

import os

from google.oauth2 import service_account
import googleapiclient.discovery

def get_policy(crm_service, project_id, version=3):
    """Gets IAM policy for a project."""
    policy = (
        crm_service.projects()
        .getIamPolicy(
            resource=project_id,
            body={"options": {"requestedPolicyVersion": version}},
        )
        .execute()
    )
    print(policy)
    return policy


def set_policy(crm_service, project_id, policy):
    """Sets IAM policy for a project."""
    policy = (
        crm_service.projects()
        .setIamPolicy(resource=project_id, body={"policy": policy})
        .execute()
    )
    return policy


def initialize_service():
    """
    Initializes a Cloud Resource Manager service.
    The Environemnt variable GOOGLE_APPLICATION_CREDENTIALS must point to the service account key.json file
    """
    
    credentials = service_account.Credentials.from_service_account_file(
        filename=os.environ["GOOGLE_APPLICATION_CREDENTIALS"],
        scopes=["https://www.googleapis.com/auth/cloud-platform"],
    )
    
    crm_service = googleapiclient.discovery.build(
        "cloudresourcemanager", "v1", credentials=credentials
    )
    return crm_service


def modify_policy_add_role(crm_service, project_id, role, member):
    """Adds a new role binding to a policy."""

    policy = get_policy(crm_service, project_id)

    binding = None
    for b in policy["bindings"]:
        if b["role"] == role:
            binding = b
            break
    if binding is not None and member not in binding["members"]:
        binding["members"].append(member)
    else:
        binding = {"role": role, "members": [member]}
        policy["bindings"].append(binding)

    policy = set_policy(crm_service, project_id, policy)


def modify_policy_remove_member(crm_service, project_id, role, member):
    """Removes a  member from a role binding."""

    policy = get_policy(crm_service, project_id)

    # The try-except below handles the case where the role isn't in the IAM policy
    try:
        binding = next(b for b in policy["bindings"] if b["role"] == role)
    except StopIteration:
        print("The role is not included in the IAM policy. Can't remove user")
        raise KeyError

    if "members" in binding and member in binding["members"]:
        binding["members"].remove(member)

    set_policy(crm_service, project_id, policy)


if __name__ == '__main__':

    # TODO: Replace with your project ID
    project_id = "projectID"
    # TODO: Replace with the ID of your member in the form 'user:member@example.com'.
    member = "user:somebody@example.com"
    # TODO: Replace the role with the role you want to grant/remove
    role = "roles/logging.logWriter"

    # Initializes the client.
    crm_service = initialize_service()

    # Call modify_policy_add_role or modify_policy_remove_member as required
    modify_policy_add_role(crm_service, project_id, role, member)
    modify_policy_remove_member(crm_service, project_id, role, member)