Skip to content
Advertisement

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?

A brief summary: I have a PHP web application which uses the Google Cloud PHP Client SDK to integrate with Dialogflow. That’s working no problem. I have a need now to let my users access the GCP Dialogflow dashboard directly, and part of that means that they need to be able to add/remove the Dialogflow permissions to users from within my application. (For obvious reasons I don’t want to give them full project IAM permissions and access).

Apparently, permissions are handled by a separate “Google APIs Client Library for PHP”.

This appears to be the API for listing the existing project user policies: https://cloud.google.com/resource-manager/reference/rest/v1/projects/listOrgPolicies

I believe that this is the API for the add/remove users part, but it’s not that obvious: https://cloud.google.com/resource-manager/reference/rest/v1/projects/setIamPolicy

===

The problem:

However, when I run the example code provided in the above referenced listOrgPolicies API, I get this error:

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

I tried both composer require google/apiclient-services and composer require google/apiclient-services:dev-master. And got the same result.

===

My questions are:

Are these even the correct APIs for the task?

Where can I find the SDK libraries for these actions? (or alternatively, if anyone has suggestions on how to perform these tasks directly to the API using PHP cURL without the SDK)

I’d prefer if all the action happens in PHP, but if you have a working solution using some other method or language or console command line, as long as it can be executed by my application I can work with that.

Thanks in advance!

Advertisement

Answer

Before getting to the answer, please make sure the Resource Manager API is enabled. This is necessary for the REST approach and the programmatic one.

To modify the IAM bindings for a user in a given project there are two endpoints that need to be called, which are documented here. Those would be:

  1. To get the current IAM configuration: https://cloud.google.com/resource-manager/reference/rest/v1/projects/getIamPolicy
  2. To set the new IAM policy: https://cloud.google.com/resource-manager/reference/rest/v1/projects/setIamPolicy

In between steps 1 and 2 it would be needed to modify the json returned by the first endpoint either adding the user with the role of your choice or removing the user entry from it. To see what’s the json structure required to add/remove users I would suggest examining the link shared above as well as examining the payload returned by the first command.

While directly calling the REST api is one option at your disposal you may also use the gcloud CLI to perform such operations. As it seems users are going to be added/removed one by one the command line would be a simple choice and it’s the one requiring less setup. The commands for both actions would be:

/ 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

The third option would be to do it programmatically. Although I would like to provide a PHP sample I don’t have enough experience with the language, nonetheless below is a Python script that allows to add/remove roles. It has been bootstrapped from the Quickstart with just some minor changes and from the tests I ran it should work fine.

# 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)

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement