

Identity and Access Management (IAM) is the sine qua non of cloud security. The fanciest of firewalls or the sexiest of SIEMs can be undone by bad IAM in a matter of seconds.
My blog — Get real-time notifications on IAM privilege grants in Google Cloud — shows how to get alerted of any incremental access to your cloud resources.
Sometimes, though, you may need point-in-time visibility of who all have what permissions to which resources across your cloud. Obtaining this comprehensive view through the console means hopping around different resource pages — like IAM, KMS, GCS, etc.— and stitching them together.
It gets further complicated when you adopt IAM best-practices for groups.
Google Cloud IAM groups are best used to model job functions and grant access to resources based on roles, rather than assigning permissions directly to individual users. This approach simplifies access management, promotes least privilege, and reduces administrative overhead.
In such cases, IAM policy bindings reflect groups; and group memberships can only be enumerated from the Google Admin console or through the Google Cloud console at the Organization level — adding complexity.
This blog shows how Cloud Asset Inventory coupled with the Directory API can bring clarity to access grants across your Google Cloud resource hierarchy down to the individual level. This is particularly useful when you want to detect conflicting/overlapping roles to ensure Separation of Duties.
First, let’s try and obtain a comprehensive list of users and their group memberships in our Google domain.
Permissions Required
You must be signed in as a super administrator for this task.
We will fetch User and Group information using the Admin SDK: Directory API. The full list of admin permissions available is listed here. Of these, our code needs Read-only permissions to the Users and Groups API.
So we create a custom role with these read-only API permissions. Console access is not required since we are going to run these reports programmatically.
Finally, we assign this custom role to a user or service account that will execute our code.
Code Setup
We will now create a Python script which calls the Directory API to obtain the list of users and group memberships and stores the results in a CSV file.
requirements.txt
google-api-python-client
main.py
import os
import csv
import json
import googleapiclient.discoverydef group_memberships():
# Get the list of users and their respective group memberships.
customer_id = os.environ.get('CUSTOMER_ID', 'Specified environment variable is not set.')
# Get the list of users.
users = get_users(customer_id)
# Process the list of users.
if not users:
print('No users found!')
else:
df = open('group_memberships.csv', 'w')
cw = csv.writer(df)
# Fetch the list of groups for each user.
for user in users:
group_membership = [user['name']['fullName'], user['primaryEmail']]
groups = get_groups(user['primaryEmail'])
for group in groups:
group_membership.append(f"group:{group['email']}")
cw.writerow(group_membership)
df.close()
def get_users(customer_id):
# Make the API call to get the list of users.
users = service.users().list(customer=customer_id).execute()
# Return the list of users.
return users.get('users', [])
def get_groups(user_email):
# Make the API call to get the list of groups.
groups = service.groups().list(userKey=user_email).execute()
# Return the list of groups.
return groups.get('groups', [])
# Create the Admin SDK Directory service object.
service = googleapiclient.discovery.build('admin', 'directory_v1')
group_memberships()
Executing Locally with User Credentials
I will run the Python script locally on my terminal with my user account which has the necessary permissions (the custom role) assigned to it.
gcloud auth application-default login \
--scopes=https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/admin.directory.group.readonlyexport CUSTOMER_ID=YOUR_CUSTOMER_ID
pip install -r requirements.txt
python3 main.py
You could also run this code in Cloud Run Functions using a service account and dump the CSV results to a Google Cloud Storage bucket.
Take note of thegroup_memberships.csv
file generated as output.
The next step is to obtain the list of IAM bindings we are interested in. We will use the Cloud Asset Inventory API to fetch this information.
Cloud Asset Inventory allows us to scope the request to a specific Project, Folder or an entire Organization. To view these bindings, you need the following IAM roles on the organization, folder, or project:
I further refine my query to only list bindings which have at least one of its members as a Google group. Providing a query is optional and omitting this will list all of the IAM bindings under the selected scope.
nano iam-bindings.sh
#!/bin/bashPROJECT_ID=PROJECT_NUMBER
gcloud asset search-all-iam-policies --scope='projects/$PROJECT_ID' --query='memberTypes:group' --format='json(assetType,resource,policy.bindings)' | jq -r '
.[] | . as $resource_data |
$resource_data.policy.bindings[] | . as $binding_data |
[
$resource_data.assetType,
$resource_data.resource,
$binding_data.role,
$binding_data.members[]|tostring
] | @csv
' > iam_policies.csv
chmod +x iam-bindings.sh
./iam_bindings.sh
Take note of the iam_policies.csv
file generated as output.
As the final step, we use data from the 2 CSV files,group_memberships.csv
and iam_policies.csv
, put them in our favorite spreadsheet and use simple formulas to visualize the data as per our needs.
With my limited expertise, I use a MATCH function and some conditional formatting to figure out which users are part of which policy bindings.
Source Credit: https://medium.com/google-cloud/uncovering-iam-blindspots-in-google-cloud-cd584d5f7785?source=rss—-e52cf94d98af—4