Google Cloud IAM Troubleshooting scripts intended to help identify access/permissions issues related to GCP IAM policies/permissions.
inspect/query
Use IAM Policy Troubleshooter API to determine if the user has IAM access to a resource.
Display if IAM Conditions are applicable.
Backtrack the IAM Resource Hierarchy from the resource to root and display all the IAM Roles present at each node. (TODO
: display subset of permissions at each node applicable to the target resource)
Use IAM Policy Analyzer to help determine if a given user has access to a resource through indirect capabilities:
map/
The other utility provided here is basically just a forward and reverse map and graph of IAM Roles->Permissions
and Permissions->Roles
. Mostly just fun stuff
Note that users can have access to resources through various mechanisms and restrictions:
Each of these scripts attempts to surface aspects of these access capabilities and restricts. The intent is to use them to surface the full access scope capability for a user.
You can find the source here
The following utilities require various levels of privleged access to run and are described in the corresponding section
Some scripts redirect the quota to a given project for consumption and is described in the appropriate setup scripts below. For more information see serviceUsageConsumer
Many of these scripts makes use of GCP Resource Names. For reference, see:
This script can be used in two modes:
For the first mode, no additional permissions are required since its a type of “self-check”
For the second, this necessarily requires the ability for the administrator to perform Domain Wide Delegation. This level of access basically allows you to impersonate any user and then see what permissions they have as that user. As far as GCP is concerned, the request for IAM permissions check comes as if it is from the end user.
Notably, this level of access is rare but is left here as an option.
Configuring the second mode requires a user to have domain-wide/administrator privileges and a service account enabled on the domain for Cloud Platform IAM Scope. See Configure Domain Wide Delegation
Assume the user currently configured for Application Default Credentials is the End User (user4@esodemoapp2.com
) and wants to “see” what permissions he/she has on GCS Bucket //storage.googleapis.com/projects/_/buckets/iam-deny-bucket
Running the following script as that user show
Note that the second set is initially empty since this user does NOT have any access
$ go run main.go \
--checkResource="//storage.googleapis.com/projects/_/buckets/iam-deny-bucket" \
--printPermissionsOnResource \
-v 20 -alsologtostderr
I0207 11:37:28.549307 456856 main.go:104] ================ QueryTestablePermissions with Resource ======================
I0207 11:37:28.723178 456856 main.go:127] ================ Getting Permissions
I0207 11:37:28.723209 456856 main.go:141] Testable permissions on resource:
I0207 11:37:28.723217 456856 main.go:143] resourcemanager.hierarchyNodes.createTagBinding
I0207 11:37:28.723224 456856 main.go:143] resourcemanager.hierarchyNodes.deleteTagBinding
I0207 11:37:28.723231 456856 main.go:143] resourcemanager.hierarchyNodes.listTagBindings
I0207 11:37:28.723237 456856 main.go:143] resourcemanager.resourceTagBindings.create
I0207 11:37:28.723251 456856 main.go:143] resourcemanager.resourceTagBindings.delete
I0207 11:37:28.723260 456856 main.go:143] resourcemanager.resourceTagBindings.list
I0207 11:37:28.723266 456856 main.go:143] storage.buckets.createTagBinding
I0207 11:37:28.723275 456856 main.go:143] storage.buckets.delete
I0207 11:37:28.723282 456856 main.go:143] storage.buckets.deleteTagBinding
I0207 11:37:28.723289 456856 main.go:143] storage.buckets.get
I0207 11:37:28.723299 456856 main.go:143] storage.buckets.getIamPolicy
I0207 11:37:28.723306 456856 main.go:143] storage.buckets.listTagBindings
I0207 11:37:28.723315 456856 main.go:143] storage.buckets.setIamPolicy
I0207 11:37:28.723323 456856 main.go:143] storage.buckets.update
I0207 11:37:28.723331 456856 main.go:143] storage.multipartUploads.abort
I0207 11:37:28.723337 456856 main.go:143] storage.multipartUploads.create
I0207 11:37:28.723352 456856 main.go:143] storage.multipartUploads.list
I0207 11:37:28.723361 456856 main.go:143] storage.multipartUploads.listParts
I0207 11:37:28.723369 456856 main.go:143] storage.objects.create
I0207 11:37:28.723377 456856 main.go:143] storage.objects.delete
I0207 11:37:28.723385 456856 main.go:143] storage.objects.get
I0207 11:37:28.723393 456856 main.go:143] storage.objects.getIamPolicy
I0207 11:37:28.723401 456856 main.go:143] storage.objects.list
I0207 11:37:28.723408 456856 main.go:143] storage.objects.setIamPolicy
I0207 11:37:28.723416 456856 main.go:143] storage.objects.update
I0207 11:37:28.723613 456856 main.go:1204] ==== TestIAMPermissions as GCS Bucket Resource ====
I0207 11:37:28.837305 456856 main.go:1238] User permission on resource:
Now add in an IAM the storageViewer
role
and run the script again
$ go run main.go \
--checkResource="//storage.googleapis.com/projects/_/buckets/iam-deny-bucket" \
--printPermissionsOnResource \
-v 20 -alsologtostderr
I0207 11:44:19.616210 457832 main.go:1204] ==== TestIAMPermissions as GCS Bucket Resource ====
I0207 11:44:19.970744 457832 main.go:1238] User permission on resource:
I0207 11:44:19.970790 457832 main.go:1240] storage.objects.get
I0207 11:44:19.970818 457832 main.go:1240] storage.objects.list
Note that now the user has TWO additional permissions show up. These are the permissions this user has from the field of potential permissions even applicable to this resource type.
You can run this script as an administrator but to do this requires extensive the administrator to impersonate an end user through domain delegation.
For example, if an admistrator securityadmin@esodemoapp2.com
has access to impersonate a service account adminapi@fabled-ray-104117.iam.gserviceaccount.com
which itself has domain-delegation permissions, the the securityadmin
can “see” the resource as the user:
gcloud config set account securityadmin@esodemoapp2.com
gcloud auth application-default login
## impersonate user:user4@esodemoapp2.com and check which permissions apply to resource as that user
go run main.go \
--checkResource="//storage.googleapis.com/projects/_/buckets/iam-deny-bucket" \
--identity=user:user4@esodemoapp2.com \
--checkEndUserPermissions --printPermissionsOnResource \
--impersonateServiceAccount=adminapi@fabled-ray-104117.iam.gserviceaccount.com \
-v 20 -alsologtostderr
I0207 12:09:10.051084 461691 main.go:1204] ==== TestIAMPermissions as GCS Bucket Resource ====
I0207 12:09:10.298606 461691 main.go:1238] User permission on resource:
I0207 12:09:10.298649 461691 main.go:1240] storage.objects.get
I0207 12:09:10.298708 461691 main.go:1240] storage.objects.list
The other resource types supported:
const bigqueryTablesRegex untyped string = "//bigquery.googleapis.com/projects/(.+)/datasets/(.+)/tables/(.+)"
const iamServiceAccountsRegex untyped string = "//iam.googleapis.com/projects/(.+)/serviceAccounts/(.+)"
const serviceAccountsKeysRegex untyped string = "//iam.googleapis.com/projects/(.+)/serviceAccounts/(.+)/keys/(.+)"
const iapAppEngineRegex untyped string = "//iap.googleapis.com/projects/(.+)/iap_web/appengine-(.+)/services/(.+)"
const iapGCERegex untyped string = "//iap.googleapis.com/projects/(.+)/iap_web/compute/services/(.+)"
const spannerInstances untyped string = "//spanner.googleapis.com/projects/(.+)/instances/(.+)"
const storageBucketsRegex untyped string = "//storage.googleapis.com/projects/_/buckets/(.+)"
const computeInstanceRegex untyped string = "//compute.googleapis.com/projects/(.+)/zones/(.+)/instances/(.+)$"
const computeSubNetworksRegex untyped string = "//compute.googleapis.com/projects/(.+)/regions/(.+)/subnetworks/(.+)"
const resourceManagerOrganizationRegex untyped string = "//cloudresourcemanager.googleapis.com/organizations/(.+)"
const resourceManagerProjectsRegex untyped string = "//cloudresourcemanager.googleapis.com/projects/(.+)"
Subscript that uses the IAM Policy Troubleshooter API to show if the user has access to a resource or not and how it got that access.
Once the user’s apparent access is displayed, this script will attempt to print all the IAM roles in the resource hierarchy back to the org node.
The reason to do this is to display the roles and (eventually; its still a TODO:), extract out all the IAM permissions contained in those roles and filter/display only those permissions that apply to this resource (as provided by the checkEndUserPermissions
subscript.)
Anyway, this requires the user who is running this script to have (preferably), have the following organizational level permissions:
Cloud Asset Viewer
, Security Reviewer
and the subset of these ready-only
permission at the org level:
orgpolicy.constraints.list
orgpolicy.policies.list
orgpolicy.policy.get
resourcemanager.folders.get
resourcemanager.folders.getIamPolicy
resourcemanager.folders.list
resourcemanager.organizations.get
resourcemanager.organizations.getIamPolicy
resourcemanager.projects.get
resourcemanager.projects.getIamPolicy
resourcemanager.projects.list
Note, the default role Organization Administrator
has the set IAMPolicy
permissions. The recommendation is to create a custom role with just the permissions set above:
To use this script, specify the appropriate resource name and permission to check.
for reference on the format for the checkResource
and permissions
, see
For example, if you want to check if an end-user user4@esodemoapp2.com
has the storage.objects.get
permission on a GCS Bucket iam-deny-bucket
and you know that the bucket is in project projects/cicp-oidc
, then issue the command switches:
$ go run main.go \
--checkResource="//storage.googleapis.com/projects/_/buckets/iam-deny-bucket" \
--permissionToCheck=storage.objects.get \
--identity="user:user4@esodemoapp2.com" \
--scope="projects/cicp-oidc" \
--usePolicyTroubleshooter \
--projectID=fabled-ray-104117 \
-v 10 -alsologtostderr
I0207 12:20:16.054049 464112 main.go:369] Getting PolicyTroubleshooter
I0207 12:20:17.082121 464112 main.go:403] User's AccessState GRANTED
I0207 12:20:17.082234 464112 main.go:407] User's AccessState granted at //storage.googleapis.com/projects/_/buckets/iam-deny-bucket
I0207 12:20:17.082283 464112 main.go:413] user has binding with permission via roles roles/storage.objectViewer
I0207 12:20:17.082327 464112 main.go:414] through membership map[user:user4@esodemoapp2.com:membership:MEMBERSHIP_INCLUDED relevance:HIGH]
I0207 12:20:17.082420 464112 main.go:424] ================ Determining Hierarchy for resource //storage.googleapis.com/projects/_/buckets/iam-deny-bucket
I0207 12:20:17.082437 464112 main.go:438] Getting ScopedPermission for resource [//storage.googleapis.com/projects/_/buckets/iam-deny-bucket] in scope [projects/cicp-oidc]
I0207 12:20:17.082697 464112 main.go:570] ==== Scoped Resource is GCS Bucket ==== iam-deny-bucket
I0207 12:20:17.572652 464112 main.go:593] Roles ==== roles/storage.legacyBucketOwner
I0207 12:20:17.572795 464112 main.go:593] Roles ==== roles/storage.legacyBucketReader
I0207 12:20:17.572873 464112 main.go:593] Roles ==== roles/storage.objectViewer
I0207 12:20:17.573197 464112 main.go:817] SearchingAssets of type [storage.googleapis.com/Bucket] with query [name:iam-deny-bucket]
I0207 12:20:18.111847 464112 main.go:875] Ancestor: [project/cicp-oidc]
I0207 12:20:18.111958 464112 main.go:879] Project: [cicp-oidc]
I0207 12:20:18.352594 464112 main.go:890] Policy Binding roles/cloudasset.viewer
I0207 12:20:18.352723 464112 main.go:890] Policy Binding roles/cloudfunctions.serviceAgent
I0207 12:20:18.352809 464112 main.go:890] Policy Binding roles/compute.serviceAgent
I0207 12:20:18.352892 464112 main.go:890] Policy Binding roles/editor
I0207 12:20:18.352972 464112 main.go:890] Policy Binding roles/firebase.managementServiceAgent
I0207 12:20:18.353055 464112 main.go:890] Policy Binding roles/firebase.sdkAdminServiceAgent
I0207 12:20:18.353135 464112 main.go:890] Policy Binding roles/firebaserules.system
I0207 12:20:18.353215 464112 main.go:890] Policy Binding roles/firestore.serviceAgent
I0207 12:20:18.353296 464112 main.go:890] Policy Binding roles/iam.securityAdmin
I0207 12:20:18.353377 464112 main.go:890] Policy Binding roles/iam.serviceAccountTokenCreator
I0207 12:20:18.353457 464112 main.go:890] Policy Binding roles/owner
I0207 12:20:18.353538 464112 main.go:890] Policy Binding roles/storage.objectViewer
I0207 12:20:18.353613 464112 main.go:875] Ancestor: [folder/750467892309]
I0207 12:20:18.353690 464112 main.go:895] Folder: [750467892309]
I0207 12:20:18.659502 464112 main.go:905] Policy Binding roles/resourcemanager.folderAdmin
I0207 12:20:18.659634 464112 main.go:905] Policy Binding roles/resourcemanager.folderEditor
I0207 12:20:18.659713 464112 main.go:875] Ancestor: [organization/673208786098]
I0207 12:20:18.659790 464112 main.go:911] Organization: [673208786098]
I0207 12:20:18.880545 464112 main.go:921] Policy Binding organizations/673208786098/roles/CustomOrganizationAdministrato
I0207 12:20:18.880680 464112 main.go:921] Policy Binding roles/accesscontextmanager.gcpAccessAdmin
I0207 12:20:18.880771 464112 main.go:921] Policy Binding roles/accesscontextmanager.policyAdmin
I0207 12:20:18.880852 464112 main.go:921] Policy Binding roles/accesscontextmanager.policyEditor
I0207 12:20:18.880933 464112 main.go:921] Policy Binding roles/bigquery.jobUser
I0207 12:20:18.881036 464112 main.go:921] Policy Binding roles/billing.admin
I0207 12:20:18.881117 464112 main.go:921] Policy Binding roles/cloudasset.viewer
I0207 12:20:18.881198 464112 main.go:921] Policy Binding roles/cloudfunctions.serviceAgent
I0207 12:20:18.881284 464112 main.go:921] Policy Binding roles/iam.denyAdmin
I0207 12:20:18.881365 464112 main.go:921] Policy Binding roles/iam.organizationRoleViewer
I0207 12:20:18.881444 464112 main.go:921] Policy Binding roles/iam.securityReviewer
I0207 12:20:18.881523 464112 main.go:921] Policy Binding roles/monitoring.viewer
I0207 12:20:18.881603 464112 main.go:921] Policy Binding roles/orgpolicy.policyAdmin
I0207 12:20:18.881681 464112 main.go:921] Policy Binding roles/orgpolicy.policyViewer
I0207 12:20:18.881761 464112 main.go:921] Policy Binding roles/owner
I0207 12:20:18.881840 464112 main.go:921] Policy Binding roles/resourcemanager.folderAdmin
I0207 12:20:18.881919 464112 main.go:921] Policy Binding roles/resourcemanager.folderCreator
I0207 12:20:18.882000 464112 main.go:921] Policy Binding roles/resourcemanager.folderEditor
I0207 12:20:18.882079 464112 main.go:921] Policy Binding roles/resourcemanager.folderMover
I0207 12:20:18.882172 464112 main.go:921] Policy Binding roles/resourcemanager.folderViewer
I0207 12:20:18.882242 464112 main.go:921] Policy Binding roles/resourcemanager.organizationAdmin
I0207 12:20:18.882310 464112 main.go:921] Policy Binding roles/resourcemanager.organizationViewer
I0207 12:20:18.882383 464112 main.go:921] Policy Binding roles/resourcemanager.projectCreator
I0207 12:20:18.882452 464112 main.go:921] Policy Binding roles/resourcemanager.projectIamAdmin
I0207 12:20:18.882520 464112 main.go:921] Policy Binding roles/securitycenter.serviceAgent
I0207 12:20:18.882590 464112 main.go:921] Policy Binding roles/serviceusage.serviceUsageAdmin
I0207 12:20:18.882659 464112 main.go:921] Policy Binding roles/serviceusage.serviceUsageConsumer
The output here shows that
I0207 12:20:17.082121 464112 main.go:403] User's AccessState GRANTED
I0207 12:20:17.082234 464112 main.go:407] User's AccessState granted at //storage.googleapis.com/projects/_/buckets/iam-deny-bucket
I0207 12:20:17.082283 464112 main.go:413] user has binding with permission via roles roles/storage.objectViewer
I0207 12:20:17.082327 464112 main.go:414] through membership map[user:user4@esodemoapp2.com:membership:MEMBERSHIP_INCLUDED relevance:HIGH]
while the rest of the script “walks back” the IAM tree to the root and displays the IAM role bindingsat each node. Again, a TODO for me is to print the subset of permissions applicable and any conditions that may exist in those role bindings
There are a few other resource types supported for this utility:
Organization
--checkResource="//cloudresourcemanager.googleapis.com/organizations/673208786098"
--permissionToCheck=storage.objects.get
Folder
--checkResource="//cloudresourcemanager.googleapis.com/folders/750467892309"
--permissionToCheck=storage.objects.get --identity="user:user4@esodemoapp2.com"
Project
--checkResource="//cloudresourcemanager.googleapis.com/projects/fabled-ray-104117"
--permissionToCheck=iam.roles.list
BigQuery
## Table
--checkResource="//bigquery.googleapis.com/projects/fabled-ray-104117/datasets/test/tables/person"
--permissionToCheck=bigquery.tables.get
## Dataset
--checkResource="//bigquery.googleapis.com/projects/fabled-ray-104117/datasets/test"
--permissionToCheck=bigquery.datasets.get
TODO: not working “message”: “Internal error encountered.”
ServiceAccount
--checkResource="//iam.googleapis.com/projects/fabled-ray-104117/serviceAccounts/schedulerunner@fabled-ray-104117.iam.gserviceaccount.com" --permissionToCheck=iam.serviceAccounts.get
IAP
## AppEngine
--checkResource="//iap.googleapis.com/projects/248066739582/iap_web/appengine-fabled-ray-104117/services/default"
--permissionToCheck=iap.webServiceVersions.accessViaIAP
## GCE Backend Service
--checkResource="//iap.googleapis.com/projects/248066739582/iap_web/compute/services/ngin-bs"
--permissionToCheck=iap.webServiceVersions.accessViaIAP
GCE Instance
--checkResource="//compute.googleapis.com/projects/fabled-ray-104117/zones/us-central1-a/instances/instance-1"
--permissionToCheck=compute.instances.get --identity="user:user4@esodemoapp2.com"
Script the IAM Policy API to fully explore the direct and indirect permissions that a given user has on a resource.
The way this script works is by issuing an IAM Analysis query with all the flags set to try an get a complete picture.
API call looks like this:
req := &assetpb.AnalyzeIamPolicyLongrunningRequest{
AnalysisQuery: &assetpb.IamPolicyAnalysisQuery{
Scope: *scope,
ResourceSelector: &assetpb.IamPolicyAnalysisQuery_ResourceSelector{
FullResourceName: *checkResource,
},
IdentitySelector: &assetpb.IamPolicyAnalysisQuery_IdentitySelector{
Identity: *identity,
},
Options: &assetpb.IamPolicyAnalysisQuery_Options{
ExpandGroups: true,
OutputGroupEdges: true,
ExpandResources: true,
ExpandRoles: true,
OutputResourceEdges: true,
AnalyzeServiceAccountImpersonation: *enableImpersonatedCheck,
},
},
OutputConfig: &assetpb.IamPolicyAnalysisOutputConfig{
Destination: &assetpb.IamPolicyAnalysisOutputConfig_GcsDestination_{
GcsDestination: &assetpb.IamPolicyAnalysisOutputConfig_GcsDestination{
Uri: fmt.Sprintf("%s/%s", *gcsDestinationForLongRunningAnalysis, fileName),
},
},
},
}
Note the OutputConfig
is a bit odd: it writes the output of the analysis to a GCS bucket. At the moment, this API only supports writing the output to a gcs file or to BQ. (Ideally, it should return the full set through a long-running operation result directly to the client). As a workaround, this script mimics the LRO response output by asking the API to write to a GCS file and then reading that file to parse out the response (i know, crappy but its the only way currently).
Since GCS access is now in the picture, it’ll help explain the bucket creation and permission steps below.
As for permission required to run this query: Cloud Asset Viewer
, Security Reviewer
and the subset of these ready-only
permission at the org level as described in the usePolicyTroubleshooter section is required
The user (securityadmin@
) running the script must have ServiceUsageConsumer on the project specified in the --projectID
parameter
The user (securityadmin@
) running the script must have read/write permission on a GCS
In the following, the bucket and service usage permissions are on quotaProject fabled-ray-104117
## Create bucket
gsutil mb gs://fabled-ray-104117-lro
# add permissions
gsutil iam ch user:securityadmin@esodemoapp2.com:objectAdmin gs://fabled-ray-104117-lro
## init user running script
gcloud config set account securityadmin@esodemoapp2.com
gcloud auth application-default login
gcloud config set project fabled-ray-104117
The following attempts to see if the user user4@esodemoapp2.com
has access to //storage.googleapis.com/projects/_/buckets/iam-deny-bucket
and where the query is scoped (either project, folder or organization level)
note, if you omit
enableImpersonatedCheck
, the output will not be written to the the GCS bucket and will NOT include information about any potential service-account impersonation based access.
You must specify the --scope=
variable which defines the search field (e.g Project: --scope="projects/cicp-oidc"
, Folders: --scope="folders/750467892309"
, Organization: --scope="organizations/673208786098"
).
You can specify any supported Full resource names.
(using project scoped)
$ go run main.go \
--checkResource="//storage.googleapis.com/projects/_/buckets/iam-deny-bucket" \
--identity="user:user4@esodemoapp2.com" \
--scope="projects/cicp-oidc" \
--useIAMPolicyRequest \
--projectID=fabled-ray-104117 \
--enableImpersonatedCheck \
--gcsDestinationForLongRunningAnalysis=gs://fabled-ray-104117-lro \
-v 20 -alsologtostderr
I0207 13:37:44.212252 477325 main.go:202] Getting AnalyzeIamPolicyRequest
I0207 13:37:45.595553 477325 main.go:317] Result written to gs://fabled-ray-104117-lro/20220207183744
user4
has an IAM binding directly on iam-deny-bucket
go run main.go --checkResource="//storage.googleapis.com/projects/_/buckets/iam-deny-bucket" \
--identity="user:user4@esodemoapp2.com" --scope="projects/cicp-oidc" \
--useIAMPolicyRequest \
--projectID=fabled-ray-104117 \
--enableImpersonatedCheck \
--gcsDestinationForLongRunningAnalysis=gs://fabled-ray-104117-bucket \
-v 20 -alsologtostderr
I0207 13:59:51.972794 481047 main.go:202] Getting AnalyzeIamPolicyRequest
I0207 13:59:53.659686 481047 main.go:316] Result written to gs://fabled-ray-104117-lro/20220207185951
I0207 13:59:54.048486 481047 main.go:357] Parsed AnalyzeIamPolicyResponse from gs://fabled-ray-104117-lro/20220207185951
I0207 13:59:54.048571 481047 main.go:362] user:user4@esodemoapp2.com has access to resource [full_resource_name:"//storage.googleapis.com/iam-deny-bucket"]
I0207 13:59:54.048671 481047 main.go:363] with capability [permission:"storage.objects.get" role:"roles/storage.objectViewer" permission:"storage.objects.list"]
I0207 13:59:54.048755 481047 main.go:364] from node [//storage.googleapis.com/iam-deny-bucket]
I0207 13:59:54.048803 481047 main.go:372] user is directly included in the role binding
user4
is member of group4_7@
group4_7@
has direct access to iam-deny-bucket
through binding at Project levelgo run main.go --checkResource="//storage.googleapis.com/projects/_/buckets/iam-deny-bucket" \
--identity="user:user4@esodemoapp2.com" --scope="projects/cicp-oidc" \
--useIAMPolicyRequest \
--projectID=fabled-ray-104117 \
--enableImpersonatedCheck \
--gcsDestinationForLongRunningAnalysis=gs://fabled-ray-104117-bucket \
-v 20 -alsologtostderr
I0207 15:08:38.056245 491577 main.go:202] Getting AnalyzeIamPolicyRequest
I0207 15:08:40.567676 491577 main.go:316] Result written to gs://fabled-ray-104117-bucket/20220207200838
I0207 15:08:40.743451 491577 main.go:357] Parsed AnalyzeIamPolicyResponse from gs://fabled-ray-104117-bucket/20220207200838
I0207 15:08:40.743522 491577 main.go:362] user:user4@esodemoapp2.com has access to resource [full_resource_name:"//storage.googleapis.com/iam-deny-bucket"]
I0207 15:08:40.743603 491577 main.go:363] with capability [permission:"storage.objects.get" role:"roles/storage.objectViewer" permission:"storage.objects.list"]
I0207 15:08:40.743668 491577 main.go:364] from node [//storage.googleapis.com/iam-deny-bucket]
I0207 15:08:40.743713 491577 main.go:374] user is included in the role binding through a group hierarchy: [user:user4@esodemoapp2.com --> group:group4_7@esodemoapp2.com ]
user4
is member of group4_7@
group4_7@
has direct access to iam-deny-bucket
through binding at Folder levelgo run main.go --checkResource="//storage.googleapis.com/projects/_/buckets/iam-deny-bucket" \
--identity="user:user4@esodemoapp2.com" --scope="folders/750467892309" \
--useIAMPolicyRequest \
--projectID=fabled-ray-104117 \
--enableImpersonatedCheck \
--gcsDestinationForLongRunningAnalysis=gs://fabled-ray-104117-bucket \
-v 20 -alsologtostderr
I0207 15:13:34.350153 492005 main.go:202] Getting AnalyzeIamPolicyRequest
I0207 15:13:35.656361 492005 main.go:316] Result written to gs://fabled-ray-104117-bucket/20220207201334
I0207 15:13:36.053829 492005 main.go:357] Parsed AnalyzeIamPolicyResponse from gs://fabled-ray-104117-bucket/20220207201334
I0207 15:13:36.053907 492005 main.go:362] user:user4@esodemoapp2.com has access to resource [full_resource_name:"//storage.googleapis.com/iam-deny-bucket"]
I0207 15:13:36.053994 492005 main.go:363] with capability [permission:"storage.objects.get" role:"roles/storage.objectViewer" permission:"storage.objects.list"]
I0207 15:13:36.054068 492005 main.go:364] from node [//cloudresourcemanager.googleapis.com/folders/750467892309]
I0207 15:13:36.054120 492005 main.go:374] user is included in the role binding through a group hierarchy: [user:user4@esodemoapp2.com --> group:group4_7@esodemoapp2.com ]
Note the differences between the command and results between the Folder and Project level binding.
--scope="folders/750467892309"
from node [//cloudresourcemanager.googleapis.com/folders/750467892309]
In the case for the folder, the binding is at that leveluser4
is member of group4_7@
group4_7@
is member of group8_10@
group8_10@
has direct access to iam-deny-bucket
go run main.go --checkResource="//storage.googleapis.com/projects/_/buckets/iam-deny-bucket" \
--identity="user:user4@esodemoapp2.com" --scope="folders/750467892309" \
--useIAMPolicyRequest \
--projectID=fabled-ray-104117 \
--enableImpersonatedCheck \
--gcsDestinationForLongRunningAnalysis=gs://fabled-ray-104117-bucket \
-v 20 -alsologtostderr
I0207 15:16:41.061359 492292 main.go:202] Getting AnalyzeIamPolicyRequest
I0207 15:16:43.546467 492292 main.go:316] Result written to gs://fabled-ray-104117-bucket/20220207201641
I0207 15:16:43.746936 492292 main.go:357] Parsed AnalyzeIamPolicyResponse from gs://fabled-ray-104117-bucket/20220207201641
I0207 15:16:43.747002 492292 main.go:362] user:user4@esodemoapp2.com has access to resource [full_resource_name:"//storage.googleapis.com/iam-deny-bucket"]
I0207 15:16:43.747074 492292 main.go:363] with capability [permission:"storage.objects.get" role:"roles/storage.objectViewer" permission:"storage.objects.list"]
I0207 15:16:43.747131 492292 main.go:364] from node [//storage.googleapis.com/iam-deny-bucket]
I0207 15:16:43.747172 492292 main.go:374] user is included in the role binding through a group hierarchy: [user:user4@esodemoapp2.com --> group:group4_7@esodemoapp2.com --> group:group8_10@esodemoapp2.com ]
Note the chained output:
user is included in the role binding through a group hierarchy: [user:user4@esodemoapp2.com --> group:group4_7@esodemoapp2.com --> group:group8_10@esodemoapp2.com ]
user4
can impersonate impersonate@
impersonate@
has direct access to iam-deny-bucket
go run main.go --checkResource="//storage.googleapis.com/projects/_/buckets/iam-deny-bucket" \
--identity="user:user4@esodemoapp2.com" --scope="projects/cicp-oidc" \
--useIAMPolicyRequest \
--projectID=fabled-ray-104117 \
--enableImpersonatedCheck \
--gcsDestinationForLongRunningAnalysis=gs://fabled-ray-104117-bucket \
-v 20 -alsologtostderr
I0207 14:53:34.848030 489225 main.go:202] Getting AnalyzeIamPolicyRequest
I0207 14:53:37.377074 489225 main.go:316] Result written to gs://fabled-ray-104117-bucket/20220207195334
I0207 14:53:37.769406 489225 main.go:357] Parsed AnalyzeIamPolicyResponse from gs://fabled-ray-104117-bucket/20220207195334
I0207 14:53:37.769459 489225 main.go:995] user:user4@esodemoapp2.com has iam permissions roles/iam.serviceAccountTokenCreator on [//iam.googleapis.com/projects/cicp-oidc/serviceAccounts/impersonate@cicp-oidc.iam.gserviceaccount.com]
I0207 14:53:37.769585 489225 main.go:1002] user:user4@esodemoapp2.com can impersonate impersonate@cicp-oidc.iam.gserviceaccount.com
I0207 14:53:37.769613 489225 main.go:995] serviceAccount:impersonate@cicp-oidc.iam.gserviceaccount.com has iam permissions roles/storage.objectViewer on [//storage.googleapis.com/iam-deny-bucket]
Note that the above describes the impersonation capability on a given service account and the fact that the specific account has access to a resource.
user4
can impersonate impersonate@
impersonate@
is a member of group4_7@
group4_7@
has direct access to iam-deny-bucket
go run main.go --checkResource="//storage.googleapis.com/projects/_/buckets/iam-deny-bucket" \
--identity="user:user4@esodemoapp2.com" --scope="projects/cicp-oidc" \
--useIAMPolicyRequest \
--projectID=fabled-ray-104117 \
--enableImpersonatedCheck \
--gcsDestinationForLongRunningAnalysis=gs://fabled-ray-104117-bucket \
-v 20 -alsologtostderr
I0207 15:02:28.835624 490310 main.go:202] Getting AnalyzeIamPolicyRequest
I0207 15:02:31.378812 490310 main.go:316] Result written to gs://fabled-ray-104117-bucket/20220207200228
I0207 15:02:31.669787 490310 main.go:357] Parsed AnalyzeIamPolicyResponse from gs://fabled-ray-104117-bucket/20220207200228
I0207 15:02:31.669825 490310 main.go:995] user:user4@esodemoapp2.com has iam permissions roles/iam.serviceAccountTokenCreator on [//iam.googleapis.com/projects/cicp-oidc/serviceAccounts/impersonate@cicp-oidc.iam.gserviceaccount.com]
I0207 15:02:31.669904 490310 main.go:1002] user:user4@esodemoapp2.com can impersonate impersonate@cicp-oidc.iam.gserviceaccount.com
I0207 15:02:31.669919 490310 main.go:995] serviceAccount:impersonate@cicp-oidc.iam.gserviceaccount.com has iam permissions roles/storage.objectViewer on [//storage.googleapis.com/iam-deny-bucket]
The mapping utility allows you to enumerate all Google Cloud Permissions->Roles
and Roles->Permissions
to JSON.
To use this, you must have Organization Role Viewer
and Organization Viewer
roles assigned to the current user or service account at the organization level.
or…if all you want is a map in a bigtable for the roles/permissions,see
First find the organization ID number:
$ gcloud organizations list
DISPLAY_NAME ID DIRECTORY_CUSTOMER_ID
esodemoapp2.com 673208786088 C023zw388
Then just specify that:
go run main.go -v 20 -alsologtostderr --organization 673208786088
The output will be a series of JSON files that list out the custom roles for at the project and organization level.
the files roles_default.json
and permissions_default.json
include all the roles/permissions in the organization.
$ cat roles_default.json | jq '.roles[] | select(.name=="projects/fabled-ray-104117/roles/SSHOSLoginRole")'
{
"name": "projects/fabled-ray-104117/roles/SSHOSLoginRole",
"role": {
"description": "Role to grant SSH OS Login",
"etag": "BwW6RP6hDqA=",
"name": "projects/fabled-ray-104117/roles/SSHOSLoginRole",
"title": "sshOSLoginRole"
},
"included_permissions": [
"compute.instances.osLogin",
"compute.instances.setMetadata",
"compute.instances.use"
]
}
$ cat permissions*.json | jq '.permissions[] | select(.name=="compute.instances.use")'
{
"name": "compute.instances.use",
"roles": [
"projects/fabled-ray-104117/roles/SSHRole",
"projects/fabled-ray-104117/roles/SSHOSLoginRole",
"roles/compute.instanceAdmin.v1",
"roles/dataproc.serviceAgent",
"roles/cloudtpu.serviceAgent",
"roles/compute.loadBalancerAdmin",
"roles/compute.networkAdmin",
"roles/composer.serviceAgent",
"roles/compute.admin",
"roles/compute.instanceAdmin",
"roles/container.serviceAgent",
"roles/appengineflex.serviceAgent",
"roles/dataflow.serviceAgent",
"roles/cloudmigration.inframanager",
"roles/editor",
"roles/genomics.serviceAgent",
"roles/lifesciences.serviceAgent",
"roles/notebooks.legacyAdmin",
"roles/notebooks.serviceAgent",
"roles/owner",
"roles/vpcaccess.serviceAgent"
]
}
{
"name": "compute.instances.use",
"roles": [
"projects/fabled-ray-104117/roles/SSHRole",
"projects/fabled-ray-104117/roles/SSHOSLoginRole"
]
}
This API uses google.golang.org/api/iam/v1
API which at currently does not enumerate Permissions but lists those permissions associated with a Role.
That is, if a Role has permissions [a,b,c], they will be listed in the output. If a permission is not associated with any role for any reason, it will not be included in the map.
Note, the PermissionService does not have an API to list all permissions by itself.
This script is equivalent to running an export of GCP Policy Export to and then unnesting the included permissions.
SELECT p, r.name
FROM `gcpdentity-asset-export-1.asset_inventory.iam_googleapis_com_Role` r,
UNNEST(r.resource.data.includedPermissions) p
WHERE DATE(timestamp) = "2021-02-12"
You can use the cloud console to map the roles-permissions:
If you want to iterate projects using asset-inventory API, assign the user Cloud Asset Viewer
role at org level and the serviceusage.services.use
permission on the project that is configured with gcloud config list
. Once that is done, specify --useAssetInventoryAPI
If you want to display the Roles
<-> Permissions
as a graph, run the map application with --generateGraphDB
option and redirect the output as such (remember to reduce the log level to 0)
eg
go run main.go -v 0 -alsologtostderr --organization 673208786098 --generateGraphDB > /tmp/graph.groovy
The output file will contain raw groovy command set which you can import into JanusGraph
If you just want to see the default graph/map for roles-permissions (not including custom roles, just load the static file into Cytoscape)
The --mode
switch in the command line will either
--mode=project
: iterate of project-level roles/permissions--mode=organization
: iterate over organization-level roles/permissionsexport JAVA_HOME=/path/to/jre1.8.0_211/
$ janusgraph-0.3.0-hadoop2/bin/janusgraph.sh start
Forking Cassandra...
Running `nodetool statusthrift`.. OK (returned exit status 0 and printed string "running").
Forking Elasticsearch...
Connecting to Elasticsearch (127.0.0.1:9200)..... OK (connected to 127.0.0.1:9200).
Forking Gremlin-Server...
Connecting to Gremlin-Server (127.0.0.1:8182)..... OK (connected to 127.0.0.1:8182).
Run gremlin.sh to connect.
$ janusgraph-0.3.0-hadoop2/bin/gremlin.sh
\,,,/
(o o)
-----oOOo-(3)-oOOo-----
SLF4J: Class path contains multiple SLF4J bindings.
plugin activated: janusgraph.imports
plugin activated: tinkerpop.server
plugin activated: tinkerpop.gephi
plugin activated: tinkerpop.utilities
gremlin>
:remote connect tinkerpop.server conf/remote.yaml session
:remote console
Run Exporter
go run main.go -v 0 -alsologtostderr --organization 673208786098 --generateGraphDB > /tmp/graph.groovy
Load output file
g.V().drop()
g.E().drop()
:load /tmp/graph.groovy
the load may take ~hr, right
TODO: make it parallel, the groovy file creates all the permission vertices first…the role permission map could be done in a parallel…
Once loaded into JanusGraph, use tinkerpop to query the graph or render it with an external tool like CytoScape
Outbound Edges from a Vertex:
Which Roles include this permission:
gremlin> g.V().hasLabel('permission').has('name', 'accessapproval.requests.list').outE()
==>e[1ozr6-102z4-6c5-1z0zk][1683472-in->3313856]
==>e[1abk2-102z4-6c5-1z7a8][1683472-in->3322016]
==>e[1g3cy-102z4-6c5-1zwkg][1683472-in->3354784]
==>e[u58i-102z4-6c5-202rs][1683472-in->3362824]
==>e[uarm-102z4-6c5-21noo][1683472-in->3436584]
==>e[1pwxu-102z4-6c5-235fc][1683472-in->3506232]
==>e[1vchu-102z4-6c5-24ahc][1683472-in->3559440]
gremlin> g.V().hasLabel('permission').has('name', 'accessapproval.requests.list').out().valueMap()
==>{deleted=[false], stage=[GA], name=[roles/iam.securityAdmin], description=[Security admin role, with permissions to get and set any IAM policy.], title=[Security Admin]}
==>{deleted=[false], stage=[GA], name=[roles/editor], description=[Edit access to all resources.], title=[Editor]}
==>{deleted=[false], stage=[GA], name=[roles/owner], description=[Full access to all resources.], title=[Owner]}
==>{deleted=[false], stage=[BETA], name=[roles/accessapproval.viewer], description=[Ability to view access approval requests and configuration], title=[Access Approval Viewer]}
==>{deleted=[false], stage=[BETA], name=[roles/accessapproval.approver], description=[Ability to view or act on access approval requests and view configuration], title=[Access Approval Approver]}
==>{deleted=[false], stage=[GA], name=[roles/iam.securityReviewer], description=[Security reviewer role, with permissions to get any IAM policy.], title=[Security Reviewer]}
==>{deleted=[false], stage=[GA], name=[roles/viewer], description=[Read access to all resources.], title=[Viewer]}
Which permission are included in a ROle
gremlin> i=g.V().outE().hasLabel('in').inV().has('name','roles/accessapproval.viewer')[0].id()
gremlin> g.V().hasLabel('permission').where(out().hasId(i)).valueMap()
==>{name=[resourcemanager.projects.list]}
==>{name=[resourcemanager.projects.get]}
==>{name=[accessapproval.requests.get]}
==>{name=[accessapproval.requests.list]}
==>{name=[accessapproval.settings.get]}
For Cytoscape, export graph to GraphML file:
gremlin> sg = g.V().outE().subgraph('sg').cap('sg').next()
==>tinkergraph[vertices:4703 edges:34216]
gremlin> sg.io(IoCore.graphml()).writeGraph("/tmp/mygraph.xml")
==>null
As file:
gsutil cp gs://iam-graph/graph_03102020.xml .
on Cytoscape, File->Import->Network->File
, Select GraphMLFile
the /tmp/mygraph.xml
As URL
on Cytoscape, File->Import->Network->URL
, Use URL
Upon import you should see the Cytoscape rendering:
then ofcourse if you want to graph waldo and his neighbors
yeah, thats the limit of how much useful stuff i know with cytoscape
If you want to export the janusgraph to grapSON
sg = g.V().outE().subgraph('sg').cap('sg').next()
file = new FileOutputStream("/tmp/graph.json")
mapper = GraphSONMapper.build().addCustomModule(org.janusgraph.graphdb.tinkerpop.io.graphson.JanusGraphSONModuleV2d0.getInstance()).create()
writer = GraphSONWriter.build().mapper(mapper).create()
writer.writeGraph(file, sg)
you can find example defautl roles/permissions under the map/example/
folder
Some scripts requires whoever is running the script to have the serviceusage.services.use
permission (included in roles/serviceusage.serviceUsageConsumer
) against the project defined in the --projectID=
. That is, if the user is running the script as securityadin@esodemoapp2.com
and you specify --projectID=project
, then that user should have the IAM role as shown here on that project only.
The following describes the steps to enable a Service Account for Domain-Wide Delegation.
A) Create Service Account
B) Assign client_id
for service Account Scope
Enable scope=https://www.googleapis.com/auth/cloud-platform
C) Allow user to impersonate SA
This site supports webmentions. Send me a mention via this form.