Imagine a scenario where a user, in order to accompalish a task in GCP, needs a set of IAM permissions P1 on a project, as well as a complementary set of permissions P2 on a resource R within that project. For example, to create a VM, the user needs compute.instances.create permission on the project, but also needs the iam.serviceaccounts.actas permission on the service account that is associated with the VM . This tool helps you find principals who have permission P1 on a given set of projects but are missing the permission P2 on resources within those projects. The inputs are: project ids, permissions set P1, permissions set P2, resource R. The outputs are: projects ids, resource names and principals who have permissions set P1 but not permissions set P2.
The tool has two parts:
- First, we find principals who have permission set P1 on a project but are missing a complementary set of permission P2 on a resource R within the project.
- Then, we assign those principals the permission P2 on resource R.
It is done by
- First get all projects that have the desired resource R. This is done by
using policy analyzer api --
asset_v1p1beta1.AssetServiceClient.search_all_resources
. - Then find the set of principals who have a desired set of permissions on the
project. This is done by using policy analyzer api --
asset_v1p4beta1.AssetServiceClient.analyze_iam_policy
. - Then find the set of principals who have the desired complementary set of
permissions on the resource. This is done again by using policy analyzer api
asset_v1p4beta1.AssetServiceClient.analyze_iam_policy
. Note that currently not all resources are supported by cloud asset analyzer. Please see the list of supported resources here. - Finally taking the set diff of the principals found in step-2 to principals found in step-3 to find the principals who don't the complementary set of permissions to use the resource properly.
This script calls the above apis using a service account. It requires the scope
https://www.googleapis.com/auth/cloud-platform
on the service account.
Before running this script, you need to take the following actions.
- Create or re-use a service account and download it's key.
- Grant the service account following roles at the organization node.
- Enable cloudsasset API for the project under which you created the service account.
This tool can be used as a standalone script. It accepts a few simple parameters:
-
--organization:
the GCP organization id for which to fetch the project ids. -
--resource:
the query for the resource. For example to find the principals who do not have a set of permissions on compute default service account, you can use a regex "*-compute@developer.gserviceaccount.com*" for the compute default service account. Please see here about how to construct a query for a resource. https://cloud.google.com/asset-inventory/docs/query-syntax credentials: client credentials. -
--project_permissions:
A comma-separated list of the permissions that principals should have on projects. -
--resource_permissions:
A comma-separated list of complementary permissions that principals should have on resources. -
--project_ids_location:
[OPTIONAL] Location of json file path with the following schema containing the project ids.{ "project_ids": [ "project-id1", "project-id2" ] }
This flag is optional and will enforce the script to do the analysis only for the given project ids.
-
--service_account_file_path:
The location of the service account key that would be used to generate credentials for api calls. -
--log:
[OPTIONAL] The granularity of the log level. The supported values are: DEBUG, INFO, WARNING, ERROR, CRITICAL. -
--to_json:
The json file path to store the output.
Standalone usage requires a few prerequisite packages, listed in the
requirement.txt
file. The simplest way to install them is to set up a
virtualenv:
virtualenv -p=python3 venv
. venv/bin/activate
pip install -r requirement.txt
The script can then be called directly.
python permission_discrepancy_finder.py \
--organization="organizations/[YOUR-ORGANIZATION-ID]" \
--resource="[RESOURCE-QUERY]" \
--project_permissions="[COMMA-SEPARATED-LIST-OF-PERMISSIONS-OF-PROJECT]" \
--resource_permission="[COMMA-SEPARATED-LIST-OF-PERMISSIONS-OF-RESOURCE]" \
--project_ids_location="[LOCATION-OF-JSON-FILE-WITH-INTERESTING-PROJECT-IDS (OPTIONAL)]" \
--service_account_file_path="[FILE-PATH-TO-SERVICE-ACCOUNT]" \
--log="[LOG-SEVERITY-LEVEL] (OPTIONAL)" \
--to_json="[LOCATION-OF-OUTPUT-JSON-FILE]"
A json file at the location [LOCATION-OF-OUTPUT-JSON-FILE]
with the following
content.
{
"projects": [
{
"project_id": "project-id1",
"resource": "resource-1",
"principals_with_missing_permissions": [
"group:abc@xyz.com",
"user:def@xyz.com",
"user:ghi@xyz.com"
]
},
{
"project_id": "project-id2",
"resource": "resource-2",
"principals_with_missing_permissions": [
"user:def@xyz.com"
]
}
]
}
This part grants the given role to principals with missing permissions at the resource level. Currently, we only support the resource to be a service account.
We achieve this with the help of iam_v1.projects.serviceAccounts.setIamPolicy
api that sets the iam policy on a service account.
This script calls the above apis using a service account. It requires the scope
https://www.googleapis.com/auth/cloud-platform
on the service account.
To run this section, you MUST assign the following role to the service account that you used in the previous step on the organization node.
You can use this tool as a standalone script. This tool uses a file that has the same format as the output of the previous script and grants the given role to the the principals that have missing permission at the resource.
-
--role:
The role that should be granted to the principals with missing permissions. -
--projects_location:
Location to json file having the same format as the output of the previous script.{ "projects": [ { "project_id": "project-id1", "resource": "resource-1", "principals_with_missing_permissions": [ "group:abc@xyz.com", "user:def@xyz.com", "user:ghi@xyz.com" ] }, { "project_id": "project-id2", "resource": "resource-2", "principals_with_missing_permissions": [ "user:def@xyz.com" ] } ] }
-
---to_json:
the json file path to store the location of the output.
The standalone usage requires a few prerequisite packages, listed in the
requirement.txt
file. The simplest way to install them is to set up a
virtualenv as below:
virtualenv -p=python3 venv
. venv/bin/activate
pip install -r requirement.txt
The script can then be called directly.
python grant_role.py \
--role="[ROLE-TO-BE-GRANTED-TO-USERS]" \
--projects_location="[LOCATION-OF-PROJECT-DATA-CONTAING-USER-AND-RESOURCE-INFORMATION]" \
--service_account_file_path="[FILE-PATH-TO-SERVICE-ACCOUNT]" \
--to_json="[LOCATION-OF-OUTPUT-JSON-FILE]"
A JSON file at the location containing the content similar as below.
{
"new policy on resource": [
{
"new_policy": {
"bindings": [
{
"members": [
"user:member-1",
"user:member-2",
],
"role": "ROLE-TO-BE-GRANTED-TO-USERS"
}
],
},
"resource": "project-id-1-resource"
},
{
"new_policy": {
"bindings": [
{
"members": [
"user:member-3"
],
"role": "ROLE-TO-BE-GRANTED-TO-USERS"
}
],
},
"resource": "project-id-2-resource"
}
]
}
Problem: You might not have virtualenv
installed.
Solution: If you are using Mac or Ubuntu, you can install virtualenv
command using the command pip install virtualenv
For windows 10 user, please
see a possible solution here.
You can also use Google Cloud Shell that does
not require any installation and come up with virtualenv preinstalled.
Problem: You might not have python-3 installed in your system. The possible
error that you can get is while executing the command virtualenv -p=python3 venv
is that the python3 path not found.
Solution:
Install python3 on ubuntu,
Install python3 on Mac,
Install python3 on Windows
Problem: You get permission denied error.
Solution: Please make sure that you assign the role that is recommended
above to the service account.
Problem: You get some json decoding error like
json.decoder.JSONDecodeError: Expecting ',' delimiter:
.
Solution: One possible cause is that your service account key can be
malformed. Please use a different key or correct any obvious formatting issue.
Problem: You don't have cloud asset
and resourcemanager api
enabled.
Solution: Please make sure that you follow the instruction in the readme for
enabling the appropriate apis.