Understanding policies

Access control for Google Cloud resources is managed by Cloud IAM policies. A Cloud IAM policy is attached to a resource. The policy manages access to the resource itself as well as any child resources through policy inheritance.

This topic provides JSON examples of Cloud IAM policies, although YAML is also supported.

Policy structure

A policy is a collection of bindings, audit configuration, and metadata. A binding specifies how access should be granted on resources. It associates (or binds) one or more members with a single role and any context-specific conditions that change how and when the role is granted. The AuditConfig field specifies the configuration data for how access attempts should be audited. The metadata includes additional information about the policy, such as an etag and version to facilitate policy management. Each part is described below:

  • A list of bindings. Each binding includes the following fields:
    • A member, also known as an identity or principal, can be a user account, service account, Google group, or domain.
    • A role is a named collection of permissions that grant access to perform actions on Google Cloud resources.
    • A condition is a logic expression that further constrains the role binding based on attributes about the request, such as its origin, the target resource, and so on. Conditions are typically used to control whether access is granted based on the context for a request.
  • An AuditConfig field, which is used to configure audit logging for the policy.
  • Metadata, which includes the following fields:
    • An etag field, which is used for concurrency control, and ensures that policies are updated consistently.
    • A version field, which specifies the schema version for a given policy. Usage of the version field is explained in more detail in policy versions section.

A role binding in a Cloud IAM policy is the combination of both the role and a list of members. If a role binding also contains a condition, it is referred to as a conditional role binding.

Using etags in a policy

When you have multiple systems trying to write to the same Cloud IAM policy at the same time, there is a risk that those systems might overwrite each other's changes. This risk arises because modifying an Cloud IAM policy involves three operations: retrieving the current policy, modifying its content as desired, and then setting the new policy in its entirety. If two systems are doing this at once, it is possible that one of those systems will set an updated policy not realizing that the policy had been changed between when it was initially retrieved and now.

To avoid such scenarios, Cloud IAM supports concurrency control through the use of an etag field in the policy. Whenever you retrieve a policy, be sure that you use the etag from the retrieved policy when you submit your modified policy. If the policy has been modified since you retrieved it, the etag will not match and your update will fail.

When this occurs, retry the entire operation: retrieve the policy again, apply your modifications, and submit the updated policy. We recommend that you perform this retry logic automatically in any code or scripts that you use to manage Cloud IAM policies.

To learn how to update policies using the read-modify-write pattern, see Granting, changing, and revoking access.

Example: Simple policy

Consider the following example policy that binds a member to a role:

{
  "bindings": [
    {
      "members": [
        "user:jie@example.com"
      ],
      "role": "roles/owner"
    }
  ],
  "etag": "BwUjMhCsNvY=",
  "version": 1
}

In the example above, jie@example.com is granted the Owner primitive role without any conditions. The binding to a primitive role is often overly permissive; in this case, the Owner role contains over 1,000 permissions. We recommend that you grant a predefined role or a custom role instead of a primitive role, as these role types are designed to be limited in scope and in the number of their permissions.

Example: Policy with multiple bindings

Consider the following example policy that contains more than one binding. Each binding grants a different role:

{
  "bindings": [
    {
      "members": [
        "user:jie@example.com"
      ],
      "role": "roles/resourcemanager.organizationAdmin"
    },
    {
      "members": [
        "user:divya@example.com",
        "user:jie@example.com"
      ],
      "role": "roles/resourcemanager.projectCreator"
    }
  ],
  "etag": "BwUjMhCsNvY=",
  "version": 1
}

In the example above, Jie (jie@example.com) is granted the Organization Admin predefined role (roles/resourcemanager.organizationAdmin) in the first role binding. This role contains permissions for organizations, folders, and limited projects operations. In the second role binding, both Jie and Divya (divya@example.com) are granted the ability to create projects via the Project Creator role (roles/resourcemanager.projectCreator). Together, these bindings grant fine- grained access to both Jie and Divya, where access granted to Divya is the subset of the access granted to Jie.

Example: Policy with conditional role binding

Consider the following Cloud IAM policy, which binds members to a predefined role and uses a condition expression to constrain the role binding:

{
  "bindings": [
    {
      "members": [
        "group:prod-dev@example.com",
        "serviceAccount:prod-dev-example@appspot.gserviceaccount.com"
      ],
      "role": "roles/appengine.Deployer",
      "condition": {
          "title": "Expires_July_1_2020",
          "description": "Expires on July 1, 2020",
          "expression":
            "request.time < timestamp('2020-07-01T00:00:00.000Z')"
      }
    }
  ],
  "etag": "BwWKmjvelug=",
  "version": 3
}

In this example, the version field is set to 3, because the policy contains a condition expression. The binding in the policy is a conditional role binding; it grants the role to the Google group prod-dev@example.com and the service account prod-dev-example@appspot.gserviceaccount.com, but only until July 1, 2020.

For details about the features that each policy version supports, see Policy versions on this page.

Policy limitations

The following limitations apply for Cloud IAM policies:

  • Every Google Cloud resource that supports a Cloud IAM policy at its level in the resource hierarchy can have a maximum of one policy. For example, organizations, folders, projects, or individual resources (such as Compute Engine disks, images, and more).
  • Each Cloud IAM policy can contain up to 1,500 members. Up to 250 of these members can be Google groups.

    Cloud IAM counts all of the members in each binding. It does not deduplicate members that appear in more than one binding. For example, if the member user:alice@example.com appears in 50 bindings, then you could add another 1450 members across all of the policy's bindings.

  • In general, any policy changes will take effect within 60 seconds after either calling setIamPolicy() or by updating a role binding in the Cloud Console. However, under certain circumstances, it may take up to 7 minutes for policy changes to fully propagate across the system.

  • Some Google Cloud services do not currently support conditional role bindings for resource-level policies, even if the resource's name, type, or Google Cloud can be used in a conditional role binding. For example, in some cases, a policy with a conditional role binding that constrains access to a service's resource can be set on the project, but not on the resource itself. For details, see the Cloud IAM Conditions attribute reference.

Policy inheritance and the resource hierarchy

Google Cloud resources are organized hierarchically, where the organization node is the root node in the hierarchy, then optionally folders, then projects. Most of other resources are created and managed under a project. Each resource has exactly one parent, except the root node in the hierarchy. See the Resource Hierarchy topic for more information.

The resource hierarchy is important to consider when setting a Cloud IAM policy. When setting a policy at a higher level in the hierarchy, such as at the organization level, folder level, or project level, the granted access scope includes the resource level where this policy is attached to and all resources under that level. For example, a policy set at the organization level applies to the organization and all resources under the organization. Similarly, a policy set at the project level applies to the project and all resources in the project.

Policy inheritance is the term that describes how policies apply to resources beneath their level in the resource hierarchy. Effective policy is the term that describes how all parent policies in the resource hierarchy are inherited for a resource. It is the union of the following:

  • The policy set on the resource
  • The policies set on all of resource's ancestry resource levels in the hierarchy

Each new role binding (inherited from parent resources) that affect the resource's effective policy are evaluated independently. A specific access request to the resource is granted if any of the higher-level role bindings grant access to the request.

If a new role binding is introduced to any level of resource's inherited policy, the access grant scope increases.

Example: Policy inheritance

To understand policy inheritance, consider the following example policy that is set at the organization level:

Organization-level policy

{
  "bindings": [
    {
      "members": [
        "user:divya@example.com"
      ],
      "role": "roles/storage.objectViewer"
    }
  ],
  "etag": "BwUjMhCsNvY=",
  "version": 1
}

The Storage Object Viewer role (roles/storage.objectViewer) contains get and list permissions for projects and Cloud Storage objects. When set at the organization level, this role binding is applied to levels under the organization, including all projects and all Cloud Storage objects under those projects.

To further demonstrate policy inheritance, consider what happens when a policy is further set at myproject-123:

Project-level policy

{
  "bindings": [
    {
      "members": [
        "user:divya@example.com"
      ],
      "role": "roles/storage.objectCreator"
    }
  ],
  "etag": "BwUjMhCsNvY=",
  "version": 1
}

In the example above, the Storage Object Creator role (roles/storage.objectCreator) grants Divya the ability to create Cloud Storage objects, under myproject-123. Now that there are two role bindings that grant Divya access to the target Cloud Storage objects under myproject-123.

  • A policy at the organization level grants the ability to list and get all Cloud Storage objects under this organization
  • A policy at myproject-123 grants the ability to create objects, under myproject-123, where the policy is attached.

The table below summarizes Divya's effective policy:

Permissions granted via "storage.objectViewer" role at organization level Permissions granted via "storage.objectCreator" role at "myproject-123" Effective grant scope for Divya under "myproject-123"
resourcemanager.projects.get
resourcemanager.projects.list
storage.objects.get
storage.objects.list
resourcemanager.projects.get
resourcemanager.projects.list
storage.objects.create
resourcemanager.projects.get
resourcemanager.projects.list
storage.objects.get
storage.objects.list
storage.objects.create

Policy versions

Over time, Cloud IAM may add new features that significantly add or change fields in the policy schema. To avoid breaking your existing integrations that rely on consistency in the policy structure, such changes are introduced in new policy schema versions.

If you are integrating with Cloud IAM for the first time, we recommend using the most recent policy schema version available at that time. Below, we'll discuss the different versions available and how to use each. We'll also describe how to specify your desired version and walk you through some troubleshooting scenarios.

Every existing Cloud IAM policy specifies a version field as part of the policy's metadata. Consider the highlighted portion below:

{
  "bindings": [
    {
      "members": [
        "user:jie@example.com"
      ],
      "role": "roles/owner"
    }
  ],
  "etag": "BwUjMhCsNvY=",
  "version": 1
}

This field specifies the syntax schema version of the policy. Each version of the policy contains a specific syntax schema that can be used by bindings. The newer version may contain role bindings with the newer syntax schema that is unsupported by earlier versions. This field is not intended to be used for any purposes other than policy syntax schema control.

Valid policy versions

Cloud IAM policies can use the following policy versions:

Version Description
1 The first version of the Cloud IAM syntax schema for policies. Supports binding one role to one or more members. Does not support conditional role bindings.
2 Reserved for internal use.
3 Introduces the condition field in the role binding, which constrains the role binding via context-based and attribute-based rules. For more information, see the overview of Cloud IAM Conditions.

Specifying a policy version when getting a policy

For the REST API and client libraries, when you get a Cloud IAM policy, we recommend that you specify a policy version in the request. When a request specifies a policy version, Cloud IAM assumes that the caller is aware of the features in that policy version and can handle them correctly.

If the request does not specify a policy version, Cloud IAM assumes that the caller wants a version 1 policy.

When you get a policy, Cloud IAM checks the policy version in the request, or the default version if the request did not specify a version. Cloud IAM also checks the policy for fields that are not supported in a version 1 policy. It uses this information to decide what type of response to send:

  • If the policy does not contain any conditions, then Cloud IAM always returns a version 1 policy, regardless of the version number in the request.
  • If the policy contains conditions, and the caller requested a version 3 policy, then Cloud IAM returns a version 3 policy that includes the conditions. For an example, see scenario 1 on this page.
  • If the policy contains conditions, and the caller requested a version 1 policy or did not specify a version, then Cloud IAM returns a version 1 policy.

    For role bindings that include a condition, Cloud IAM appends the string _withcond_ to the role name, followed by a hash value; for example, roles/iam.serviceAccountAdmin_withcond_2b17cc25d2cd9e2c54d8. The condition itself is not present. For an example, see scenario 2 on this page.

This behavior prevents issues with older client libraries that are not aware of conditional role bindings. For details, see Client library support for policy versions on this page.

Scenario 1: Policy version that fully supports Cloud IAM Conditions

Suppose you call the following REST API method to get the Cloud IAM policy for a project:

POST https://cloudresourcemanager.googleapis.com/v1/projects/project-id:getIamPolicy

The request body contains the following text:

{
  "options": {
    "requestedPolicyVersion": 3
  }
}

The response contains the project's Cloud IAM policy. If the policy contains at least one conditional role binding, its version field is set to 3:

{
  "bindings": [
    {
      "members": [
        "user:user@example.com"
      ],
      "role": "roles/iam.securityReviewer",
      "condition": {
          "title": "Expires_July_1_2020",
          "description": "Expires on July 1, 2020",
          "expression": "request.time < timestamp('2020-07-01T00:00:00.000Z')"
      }
    }
  ],
  "etag": "BwWKmjvelug=",
  "version": 3
}

If the policy does not contain conditional role bindings, its version field is set to 1, even though the request specified version 3:

{
  "bindings": [
    {
      "members": [
        "user:user@example.com"
      ],
      "role": "roles/iam.securityReviewer",
    }
  ],
  "etag": "BwWKmjvelug=",
  "version": 1
}

Scenario 2: Policy version with limited support for Cloud IAM Conditions

Suppose you call the following REST API method to get the Cloud IAM policy for a project:

POST https://cloudresourcemanager.googleapis.com/v1/projects/project-id:getIamPolicy

The request body is empty; it does not specify a version number. As a result, Cloud IAM uses the default policy version, 1.

The policy contains a conditional role binding. Because the policy version is 1, the condition does not appear in the response. To indicate that the role binding uses a condition, Cloud IAM appends the string _withcond_ to the role name, followed by a hash value:

{
  "bindings": [
    {
      "members": [
        "user:user@example.com"
      ],
      "role": "roles/iam.securityReviewer_withcond_58e135cabb940ad9346c"
    }
  ],
  "etag": "BwWKmjvelug=",
  "version": 1
}

Specifying a policy version when setting a policy

When you set a Cloud IAM policy, we recommend that you specify a policy version in the request. When a request specifies a policy version, Cloud IAM assumes that the caller is aware of the features in that policy version and can handle them correctly.

If the request does not specify a policy version, Cloud IAM allows only the fields that can appear in a version 1 policy. As a best practice, do not change conditional role bindings in a version 1 policy; because the policy does not show the condition for each binding, you do not know when or where the binding is actually granted. Instead, get the version 3 representation of the policy, which shows the condition for each binding, and use that representation to update the bindings.

Scenario: Policy versions in requests and responses

Suppose you use the REST API to get a Cloud IAM policy, and you specify version 3 in the request. The response contains the following policy, which uses version 3:

{
  "bindings": [
    {
      "members": [
        "user:divya@example.com"
      ],
      "role": "roles/storage.admin",
      "condition": {
          "title": "Weekday_access",
          "description": "Monday thru Friday access only in America/Chicago",
          "expression": "request.time.getDayOfWeek('America/Chicago') >= 1 && request.time.getDayOfWeek('America/Chicago') <= 5"
      }
    }
  ],
  "etag": "BwUjMhCsNvY=",
  "version": 3
}

You decide that divya@example.com should have the Storage Admin role (roles/storage.admin) throughout the week, not just on weekdays. You remove the condition from the role binding and send a REST API request to set the policy; once again, you specify version 3 in the request:

{
  "bindings": [
    {
      "members": [
        "user:divya@example.com"
      ],
      "role": "roles/storage.admin"
    }
  ],
  "etag": "BwUjMhCsNvY=",
  "version": 3
}

The response contains the updated policy:

{
  "bindings": [
    {
      "members": [
        "user:divya@example.com"
      ],
      "role": "roles/storage.admin"
    }
  ],
  "etag": "BwWd8I+ZUAQ=",
  "version": 1
}

The policy in the response uses version 1, even though the request specified version 3, because the policy uses only fields that are supported in a version 1 policy.

Client library support for policy versions

Some client libraries for Google Cloud support only version 1 policies. If your client library does not support later policy versions, you cannot use features that are available only in later versions. For example, Cloud IAM Conditions requires support for policy version 3.

If you use Cloud IAM features that are not available in version 1 policies, such as Cloud IAM Conditions, use a client library that supports that policy version and sets it correctly in the request.

The following Google APIs Client Libraries for Cloud IAM support policy version 3:

Language Versions that support policy version 3
C# Google.Apis >=v1.41.1
Go google-api-go-client >=v0.10.0
Java
Node.js googleapis >=v43.0.0
PHP google/apiclient >=v2.4.0
Python google-api-python-client >=v1.7.11
Ruby google-api-client >=v0.31.0

You can use these client libraries to manage version 3 Cloud IAM policies on resources for the following services:

  • Cloud IAM
  • Cloud KMS
  • Cloud Storage
  • Compute Engine
  • Resource Manager

Other client libraries, including the Google Cloud Client Libraries, support only version 1 policies.

gcloud support for policy versions

If the gcloud tool to manage Cloud IAM policies, ensure that you are using version 263.0.0 or later. Earlier versions support only version 1 policies.

To check the version number of the gcloud tool, run gcloud version. To update to the latest version, run gcloud components update.

Policy best practices

The following best practices apply to organizations with many Google Cloud users:

  • When managing multiple user accounts with the same access configurations, use Google groups instead. Put each individual user account into the group, and grant the intended roles to the group instead of individual user accounts.

  • Permissions granted at the organization level: Carefully consider which members are granted access permissions at the organization level. For most organizations, only a few specific teams (such as Security and Network teams) should be granted access at this level of the resource hierarchy.

  • Permissions granted at the folder levels: Consider reflecting your organization's operation structure by using tiers of folders, where each parent/child folder can be configured with different sets of access grants that are aligned with business and operation needs. For example, a parent folder might reflect a department, one of its child folder might reflect resource access and operation by a group, and another child folder might reflect a small team. Both of these two folders may contain projects for their team's operation needs. Using folders in this way can ensure proper access separation, while respecting policies inherited from parent folder(s) and organization. This practice requires less policy maintenance when creating and managing Google Cloud resources.

  • Permissions granted at the project level: Grant role bindings at the project level only as required for specific groups or for individual granular permissions. For easier manageability, especially with many projects, we highly recommend setting policies at a folder level when possible.

What's next