This guide describes how to configure Explain for Forseti Security.
Explain helps you understand the Cloud Identity and Access Management (Cloud IAM) policies that affect your Google Cloud Platform (GCP) resources. It can enumerate access by resource or member, answer why a principal has access to a certain resource, or offer possible strategies for how to grant access to a specific resource.
To run Explain, you’ll need the following:
Before you start using Explain, you’ll first create and select the data model you want to use.
To review the hierarchy of commands and explore Explain functionality, use
–help
.
Get the inventory_index_id
and use it to create the data model by running
the following command:
forseti model create --inventory_index_id <INVENTORY_INDEX_ID> <MODEL_NAME>
Select the data model you created by running the following command:
forseti model use <MODEL_NAME>
Following are some example commands you can run to query the data model.
forseti explainer list_resources
You can also filter the results and list resources only in a folder:
forseti explainer list_resources --prefix organization/1234567890/folder/folder-name
forseti explainer list_members
You can also filter the results and list members with a prefix match:
forseti explainer list_members --prefix test
forseti explainer list_roles
You can also filter the results by prefix:
forseti explainer list_roles --prefix roles/
Returned results will contain only predefined roles.
Common filters include the following:
--prefix 'roles/iam'
returns results that only contain predefined roles related to Cloud IAM.
--prefix 'organizations'
returns results that only contain custom roles defined on the
organization level.
The following command lists the permissions contained by roles in the data model:
forseti explainer list_permissions --roles <ROLE1> <ROLE2>
For example, the following query lists permissions contained in roles/iam.roleAdmin
and
roles/resourcemanager.projectMover
:
forseti explainer list_permissions --roles roles/iam.roleAdmin roles/resourcemanager.projectMover
The following query lists individual permissions in each predefined Cloud IAM role:
forseti explainer list_permissions --role_prefixes roles/iam
forseti explainer get_policy <RESOURCE_NAME>
Example values for <RESOURCE_NAME>
are the project/<PROJECT_ID>
and
organization/<ORGANIZATION_ID>
.
forseti explainer check_policy <RESOURCE_NAME> <PERMISSION_NAME> <MEMEBER_NAME>
For example, the following query returns True or False to indicate if the member has permissions on the resource:
forseti explainer check_policy organizations/1234567890 iam.roles.get user/user1@gmail.com
The following command lists all resources that can be accessed by a member by a direct binding:
forseti explainer access_by_member user/<USER_NAME>
By default, resource_expansion is not performed. For example, user/foo
has roles/owner
on the
organization/1234567890
and no other policies. The above command will only show
organization/1234567890
.
To enable resource expansion, pass in the argument --expand_resource
. Forseti will perform
resource expansion and list all resources that can be accessed by user/<USER_NAME>
through a
direct or indirect binding.
forseti explainer access_by_member user/<USER_NAME> --expand_resource
With resource expansion enabled, the example above will return organizations/1234567890
and all
folders, projects, VMs, and other resources in it.
To constrain the result to a certain type of permission, use the following command:
forseti explainer access_by_member user/<USER_NAME> iam.roles.get
The above query will list all resources that can be accessed by the member with a binding of
iam.roles.get
.
The following command lists all members that can access a resource by a direct binding:
forseti explainer access_by_resource <RESOURCE_NAME>
Similar to the access_by_member
command, group expansion is not performed by default. For
example, group/bar
has roles/owner
on the organization/1234567890
and no other policies.
Without group expansion, the following example will only return group/bar
:
forseti explainer access_by_resource organizations/1234567890
To enable group expansion, pass in the --expand_groups
argument. Forseti will perform group
expansion and list all members that can access the resource, even if the access is granted because a member is in a group.
forseti explainer access_by_resource <RESOURCE_NAME> --expand_groups
With group expansion enabled, the example above will list group/bar
and user/foo
if user/foo
is a member in group/bar
.
To constrain the result to a certain type of permission, pass in the permission:
forseti explainer access_by_resource <RESOURCE_NAME> <PERMISSION>
You can specify a permission, such as iam.serviceAccounts.get
, and list all the
<members, resource, role>
that have a relation.
The tuple <members, resource, role>
contains the members with a role that contains permission
iam.serviceAccounts.get
on the resource.
forseti explainer access_by_authz --permission iam.serviceAccounts.get
...
Member member1
Member member2
Resource resource1
Role roles/owner
...
These results mean that resource resource1
has a policy to grant roles/owner
to member1
and member2
With access_by_authz
you can also specify a role instead of a permission:
# With G Suite Group expansion
forseti explainer access_by_authz --permission iam.serviceAccounts.get --expand_group
# With resource expansion.
forseti explainer access_by_authz --permission iam.serviceAccounts.get --expand_resource
Understand why a member has a permission to a resource:
forseti explainer why_granted <MEMBER_NAME> <RESOURCE_NAME> --permission <PERMISSION_NAME>
Example values for <MEMBER_NAME>
are user/user1@gmail.com
or serviceAccount/service1@domain.com
The result displays all bindings that grant the permission you specified.
For each binding <resource, role, [member1, member2]>
, Forseti returns
how the resource hierarchy links to your target resource, and how a group
in the binding links to your target member.
In the following example, user user/abc@gmail.com
has permission
iam.serviceAccounts.get
on resource my-project-123
because the user
has the role roles/iam.securityReviewer
on resource
organization/1234567890
. Member user/abc@gmail.com
also has a
membership in group group/my-group-123@gmail.com
.
forseti explainer why_granted user/abc@gmail.com project/my-project-123 --permission iam.serviceAccounts.get
bindings {
member: "user/abc@gmail.com"
resource: "organization/1234567890"
role: "roles/iam.securityReviewer"
}
memberships {
member: "user/abc@gmail.com"
parents: "group/my-group-123@gmail.com"
}
resource_ancestors: "project/my-project-123"
resource_ancestors: "organization/1234567890"
forseti explainer why_denied <MEMBER_NAME> <RESOURCE_NAME> --permission <PERMISSION_NAME>
The result will list any potential bindings you can add to grant the required permission. The
following example result shows that to access resource resource_bar
, user member_foo
needs
role roles/baz_role
on the resource or its parent. The result also shows that the user gets the
role if you add them to the group group_foo_parent
, which already has the required permission.
strategies {
bindings {
member: "member_foo "
resource: "resource_bar_parent"
role: "roles/baz_role"
}
overgranting: 1
}
strategies {
bindings {
member: "group_foo_parent "
resource: "resource_bar"
role: "roles/baz_role"
}
overgranting: 1
}
strategies {
bindings {
member: "member_foo"
resource: "resource_bar"
role: "roles/baz_role"
}
}
...
In the example above, overgranting equals 1 to indicate a binding that could grant unnecessary privileges. This means that the binding doesn’t work directly on the target member and resource. Instead, the binding applies to groups that contain the target member, or resources that contain the target resource.