GCP: Analyzing members of IAM role using gcloud filtering and jq

Although  the GCP console provides a nice interface for displaying which user/service account is in which IAM security role (IAM & Admin > IAM), it can be difficult to analyze using gcloud get-iam-policy because of the inner array of ‘members’ returned.

However, if you use the flattening ability of gcloud, it becomes much easier to parse. Here an example of pulling all the roles for a specific user or service account.

# get list of project id
gcloud projects list --format='value(project_id)'

# show roles for user
gcloud projects get-iam-policy <projectId> --flatten="bindings[].members" --filter="bindings.members=user:<userEmailId>" --format="value(bindings.role)"

# list all service accounts
gcloud iam service-accounts --project <projectId> list

# show roles for single service account
gcloud projects get-iam-policy <projectId> --flatten="bindings[].members" --filter="bindings.members=serviceAccount:<serviceAccountId>" --format="value(bindings.role)"

Here is another example, this time coming from the opposite perspective and listing all entities in the “logging.logWriter” role.

# given a role, show all entities bound to policy
gcloud projects get-iam-policy <projectId> --flatten="bindings[].members" --filter="bindings.role=roles/logging.logWriter" --format="value(bindings.members)"

If you find the gcloud flattening/filter/format combination too limiting, you could have get-iam-policy output all the json and instead use the jq utility to transform and filter it.

Here is an example of using jq to perform the same operation as the first gcloud example, where given a user/serviceAccount Id, you get a list of roles.

# grab all the IAM results for project
alljson=$(mktemp alljson-XXXXXXXX.json)
gcloud projects get-iam-policy <projectId> --format=json > $alljson

# choose one: either looking for user or service account
objectId="user:<userEmailId>"
objectId="serviceAccount:<serviceAccountId>"

# for single user/service account, find all roles it is a member of
cat $alljson | jq -r ".bindings[] | select ( .members | index(\"$objectId\") ) | .role"

We could make this selection even more flexible by using a regex to match the user or service account name.   With a regex like ‘myService1’, we do not have to specify the standard ‘serviceAccount:’ prefix, or the standard suffix  ‘<projectName>.iam.gserviceaccount.com’.

# regex match 
myentity="myService1"
cat $alljson | jq -r ".bindings[] | select ( .members[] | test(\"$myentity\") ) | .role"

Just beware that if your regex is wide ‘myService’, it could pull in more than one account, and pull the roles for both a ‘myService1’ and ‘myService2’ (which depending on the scenario may be what you want).

If you want to see the second gcloud example written using jq, showing all the entities in a certain role, see below.

# exact match
myregexrole="roles/logging.logWriter"
jq ".bindings[] | select ( .role | test(\"$myregexrole\") )"

# regex match for all compute based roles
myregexrole="roles/compute"
jq ".bindings[] | select ( .role | test(\"$myregexrole\") )"

REFERENCES

jq, reference 1.5

google, service-accounts list reference

baeldung, jq examples

stackoverflow, using jq to filter on inner arrays

statckoverflow, flattening bindings for better viewing

github Kielan, gcloud cheat sheet

stackexchange, using search-all-iam-policies to query roles

ncona.com, using gcloud to add/remove policy bindings