Dec 02, 2021
In this post, we explore the world of Google Cloud Platform (GCP) IAM and how to navigate your way through it. Out of the three major cloud providers (AWS, Azure, and GCP), Google’s approach to Identity and Access Management is the most straightforward. However, its relative simplicity can lead to some pitfalls, which we explore here.
In contrast to AWS and Microsoft Azure, permissions in GCP aren’t assigned via a central service. Instead, permissions can be given at any “level” of the resource structure, and they apply to any resource lower down the hierarchy. So, first, let’s take a look at the hierarchical structure of resources in Google Cloud Platform.
At the top of the pyramid is the Organization — an entity that represents a company, for example, and under which all resources reside. An organization is closely related to your Google Workspace (previously known as G Suite) Account, allowing companies to manage projects centrally and to maintain ownership of projects even after the account of the user who created them is closed. Any permission that is given to an entity at the organization level will apply to any and all resources that exist under this organization.
Folders are a type of resource that allows you to divide your organization into logical units. Folders are the first method to create boundaries between different resources in the organization. For example, you can create different folders for your legal branch, development branch, and sales department. Each folder can then contain other folders, each representing different teams, for example. This allows you to define a type of super-user that has permissions across different teams but not branches.
One level below folders, we get to the base entity you may be familiar with as a private user of GCP — the Project. A project contains all compute, data, and storage services you would use on a day-to-day basis for your applications, such as your Google Kubernetes Engine applications, BigQuery databases, and Compute Virtual Machines. These individual resources and services are, then, at the bottom of the pyramid.
As you may already know, IAM policies are all about who can perform what actions on which resources. The previous section discussed “which resources,” so now let’s discuss the who.
Finally, let’s discuss how to grant permissions in GCP and what those permissions represent.
Each permission in GCP can generally be broken down into three parts: service, resource, and verb. For example, compute.instances.start represents the permission to start (i.e., turn on) instances (virtual machines) in GCP’s compute service.
In the vast majority of cases, IAM permissions correspond to an API endpoint. For our example, it would correspond to the endpoint:
Roles are simply a collection of permissions. In GCP, you cannot grant permissions directly to members. As most actions require multiple permissions, it’s simpler to group those permissions into Roles, and then grant (bind) those roles to the entity you want to grant permissions to.
Roles come in three different types: Basic (also known as Primitive), Predefined, and Custom.
Basic roles predate what we know as IAM in GCP today. They come in Owner, Editor, and Viewer flavors. As their names suggest, the Owner role has full control over the project. They are able to view, edit, and create all resources. The Editor role can view and modify all resources but not create any new ones. The Viewer role has read-only permissions. It is considered best practice to avoid using these Primitive roles. Their permissions are very broad, and they are not scoped to any services or resources, so they generally fall outside the principle of least privilege.
Predefined Roles, on the other hand, are a bit more granular. They are set up and maintained by GCP, and allow you to have better control over which services and functions a user is allowed to invoke. For example, the Cloud SQL Viewer role allows read-only access to your Cloud SQL instances. It contains the 20-odd permissions a user needs to retrieve data from a database, and no more.
If you find that you need even more control and finer granularity, you can always create your own Custom Role. You can pick and choose exactly which permissions are grouped into that role to tailor them for your specific needs.
Now that you have your Who, What, and Where, it’s time to put it all together into a Policy. Policies are simply a list of bindings of Roles and Members. They can be defined at almost all of the levels of the resource hierarchy we’ve discussed above. At whatever level you choose to define your policy, all of those descending will also inherit those policies.
Note that this means that you cannot revoke permissions given at a parent node in the hierarchy. For example, user Alice was given the Storage Object Editor role at the project level, granting her the ability to view and modify any objects in any storage bucket contained in this project. If we then grant her the Storage Object Viewer role for a specific bucket, it would not impede her ability to also modify any objects in that bucket. That is due to permission inheritance.
As you can see, the GCP approach to identity and access management is straightforward. Choose the scope for which you want permissions to apply, create a policy attaching different Roles to specific Members, and you’re done! The most important part, then, is that you choose the scope carefully, and apply the policy in the correct place, as all children of a node are always within their parent’s scope.
In a future post, we’ll talk about common Google Cloud Platform security mistakes and misconfigurations , best practices, and privilege escalation attacks that can lead to a simple user with minimal permissions becoming an Owner of a project. Stay tuned!