Why GCP’s Two IAM APIs Matter More Than You Think

5 mins to read

Intro

Permissions are a core building block of Identity and Access Management (IAM) in the cloud. Every major cloud service provider has a robust IAM implementation that controls the behaviour of identities – human or machine users – by granting or denying specific permissions. Google Cloud (GCP) is no exception, with over 12,000 individual permissions that can be granted.

The IAM service, like all services in GCP, is constantly evolving. New features are regularly added to make privilege management more flexible and secure. These changes, however, can add complexity to an already complicated system. In this article, we’ll look at the different versions of GCP’s IAM API as it relates to referencing permissions, and how subtle differences in these APIs can cause inconsistencies between the different types of IAM policies in Google Cloud.

Permission Usage

Before examining the differences in permissions between API versions, it’s first important to understand exactly what permissions are in the context of GCP, how they’re granted, and how they can be denied.

Granting Permissions

Permissions are not granted to principals directly; rather, they’re granted through roles and allow policies

Roles in GCP are effectively named collections of permissions, typically representing the set required to perform a specific job function. There are nearly 2,000 Google-managed pre-defined roles available for use, and users can also create their own custom roles – though some permissions cannot be included in custom roles.

Allow Policies are policies which match roles to identities via mappings called Role Bindings. Each role binding in an allow policy matches a role to a set of principals. A large number of elements in the GCP resource hierarchy – organizations, folders, projects, and even many individual resources – can be configured with allow policies. Permissions granted at one spot in the resource hierarchy are inherited within that scope. For example, a user assigned a role through a role binding in a folder’s allow policy will have access to that role’s permissions in any of that folder’s sub-folders or projects.

Restricting Permissions

Permissions can be removed from identities in a few ways: Deny Policies and Principal Access Boundary Policies

Deny Policies remove permissions directly from identities – no role abstraction required. These policies can be applied at the organization, folder, or project levels. In each deny policy, you define a set of identities and the permissions to be denied. These denials override the permission grants from any allow policy, making deny policies an effective way to enforce centralized security measures even as the management of distributed allow policies becomes unwieldy. Deny policies are inherited the same way allow policies are. A deny policy at an organization or folder level applies to all sub-folders or projects within.

Principal Access Boundary Policies consider the resource being affected, rather than the permissions themselves. They can be used to allow or deny a given principal access to specific resources without referencing any permissions directly.

Permission Versions

IAM V1 & IAM V2

Over the years, GCP has released different versions of the IAM API, and different pieces of the IAM service will use specific versions of the API. For example, the configuring of allow policies is done with IAM V1, while deny policies must be configured using IAM V2. Confusingly, permissions are represented differently in each of these API versions.

An IAM permission always consists of three components:

  • The Service
  • The Resource Type
  • The Action

In IAM V1 the format of these permissions is

<service>.<resource type>.<action>

So far in this article, we’ve been referring to permissions using this format.

In IAM V2, a fully qualified domain name (FQDN) is used rather than just the service prefix. The format of IAM V2 permissions becomes

<service>.googleapis.com/<resource type>.<action>

Coverage of V2 Permissions

As deny policies exclusively use IAM V2, permissions supported in deny policies take on this more verbose format. This does not however cover all permissions that are grantable. 

Currently, there are ~12k total permissions in GCP that can be granted, but only ~5k permissions that have an IAM V2 representation. This gap has slowly been closing in recent years as Google has been working to add deny policy coverage to additional services.

Since deny policies must reference V2 permissions, more than half of the permissions that can be granted through role bindings in allow policies cannot be denied centrally using deny policies.

V2 Permissions in Allow Policies

Allow policies and role definitions are configured using the IAM V1 API. There are, however, a handful of permissions that break convention and can be specified in role definitions using their V2 representations. 

Permissions targeting the following resource types are, as of October 2025, the only permissions to which this unusual scenario applies:

ResourcesSample Permission
BigQuery BI Engine Reservationsbigqueryreservation.googleapis.com/bireservations.update
BigQuery Capacity Commitmentsbigqueryreservation.googleapis.com/capacityCommitments.create
BigQuery Reservation Assignmentsbigqueryreservation.googleapis.com/reservationAssignments.create
BigQuery Reservation Groupsbigqueryreservation.googleapis.com/reservationGroups.create
BigQuery Reservationsbigqueryreservation.googleapis.com/reservations.create
IAM Deny Policiesiam.googleapis.com/denypolicies.create
IAM OAuth Client Credentialsiam.googleapis.com/oauthClientCredentials.create
IAM OAuth Clientsiam.googleapis.com/oauthClients.create
IAM Workforce Pool Provider Keysiam.googleapis.com/workforcePoolProviderKeys.create
IAM Workforce Pool Providersiam.googleapis.com/workforcePoolProviders.create
IAM Workforce Pool Subjectsiam.googleapis.com/workforcePoolSubjects.delete
IAM Workforce Poolsiam.googleapis.com/workforcePools.create
IAM Workload Identity Pool Provider Keysiam.googleapis.com/workloadIdentityPoolProviderKeys.create
IAM Workload Identity Pool Providersiam.googleapis.com/workloadIdentityPoolProviders.create
IAM Workload Identity Poolsiam.googleapis.com/workloadIdentityPools.create
IAM Workspace Poolsiam.googleapis.com/workloadIdentityPools.create
Logging Settingslogging.googleapis.com/settings.update
VMware Engine Servicesvmwareengine.googleapis.com/services.use

Mapping Permission Versions

For the most part, determining the V2 representation of a permission from its V1 representation is relatively simple. Provided the V2 permission exists, you replace the first dot of the V1 permissions with `.googleapis.com/` and you’re good to go. 

For example, if an allow policy grants `iam.roles.create` and you want to deny that permission, you need to create a deny policy targeting `iam.googleapis.com/roles.create`.

There are some exceptions to this rule. A handful of permissions use a different IAM namespace in the fully qualified domain name of its V2 permission representation compared to the service name in its V1 representation. These are few and far between, but can cause confusion when trying to figure out how to deny specific permissions. These inconsistencies are  sometimes service-wide, and other times only apply to specific permissions within a service.

The following table details known inconsistencies of this nature between GCP IAM versions as tracked by Sonrai Security:

V1 ServiceV2 ServiceScope of DiscrepancyExample Mapping
serviceusageapikeysAll deny-supported `serviceusage.apiKeys.*` permissions are referenced in V2 as `apikeys.googleapis.com/apiKeys.*`V1: serviceusage.apiKeys.regenerate
V2: apikeys.googleapis.com/apiKeys.regenerate
bigquerybigqueryconnectionAll deny-supported `bigquery.connections.*` permissions are referenced in V2 as `bigqueryconnection.googleapis.com/connections.*`V1: bigquery.connections.create
V2: bigqueryconnection.googleapis.com/connections.create
bigquerybigquerydatapolicyAll deny-supported `bigquery.transfers.*` permissions are referenced in V2 as `bigquerydatatransfer.googleapis.com/dataPolicies.*`V1: bigquery.dataPolicies.create
V2: bigquerydatapolicy.googleapis.com/dataPolicies.create
bigquerybigquerydatatransferAll deny-supported `bigquery.transfers.*` permissions are referenced in V2 as `bigquerytransfers.googleapis.com/transfers.*`V1: Bigquery.transfers.get
V2: bigquerydatatransfer.googleapis.com/transfers.get
resourcemanagercloudresourcemanagerAffects all resource manager permissionsV1: resourcemanager.folders.create
V2: cloudresourcemanager.googleapis.com/folders.create
lookerstudiodatastudioApplies to a single permission (see right)V1: lookerstudio.pro.manage
V2: datastudio.googleapis.com/pro.manage
datastorefirestoreApplies to a single permission (see right)V1: datastore.locations.get
V2: firestore.googleapis.com/locations.get

Why this Matters

Audit Logging

Logs indicating permission errors use IAM V1 permission representations, regardless of whether the source of the error is a missing permission grant or the presence of a deny policy. It’s critical to be able to determine which deny policies are causing permissions errors for developers and cloud ops personnel, but this becomes much harder when the permission in the error log doesn’t match the offending entry in the deny policy. Understanding the differences in permission versions (and the exceptions) therefore becomes crucial. 

This is the authorization error received when a compute resource policy creation was denied by a deny policy targeting `compute.googleapis.com/resourcePolicies.create`. Note the V1 permission:

authorizationInfo: [
  0: {
    granted: false
    permission: "compute.resourcePolicies.create"
    permissionType: "ADMIN_WRITE"
    resource: "projects/<PROJECT_ID>/regions/us-east1/resourcePolicies/test-resource-policy"
    resourceAttributes: { 3 }
  }
]

Conclusion

The differences between IAM V1 and IAM V2 can be summarized as follows:

IAM V1 PermissionsIAM V2 Permissions
Format`<service>.<resource type>.<action>``<service>.googleapis.com/<resource type>.<action>`
Used InRole DefinitionsAudit LogsDeny Policies
Coverage~12k permissions ~5k permissions

GCP customers using deny policies in their cloud environment will be forced to deal with both versions. When permissions are granted using V1 and denied using V2, users need to have a good understanding of both implementations in order to be able to make sense of the policy evaluation decisions GCP makes when a user tries to perform an action in the cloud.

secure sensitive permissions