Setting limits on granting roles

In large organizations, it can be helpful to let teams independently manage the Identity and Access Management (IAM) policies for their resources. However, letting a member grant or revoke all IAM roles can greatly increase your security risk.

You can set limits on the roles that a member can grant and revoke with IAM Conditions and the iam.googleapis.com/modifiedGrantsByRole API attribute. These limits let you create limited IAM admins who can manage their own team's IAM policies, but only within the boundaries that you have set.

Before you begin

Required permissions

To set limits on the roles that a member can grant or revoke, you need a role that includes the following permissions:

  • resourcemanager.resource-type.getIamPolicy
  • resourcemanager.resource-type.setIamPolicy

Replace resource-type with one of the following:

  • If you want to create a limited IAM admin for an organization, use organizations.
  • If you want to create a limited IAM admin for a folder, use folders.
  • If you want to create a limited IAM admin for a project, use projects.

To gain these permissions while following the principle of least privilege, ask your administrator to grant you the Security Admin role (roles/iam.securityAdmin).

Alternatively, your administrator can grant you a different role with the required permissions, such as a custom role or a more permissive predefined role.

Common use cases

The following sections describe how you can use limited role granting to enable self-service policy management.

Creating limited IAM admins

Consider a scenario where you want to let a user, Finn (finn@example.com), act as a limited IAM admin for your project. You want Finn to be able to grant and revoke only the Billing Account Administrator (roles/billing.admin) and Billing Account User (roles/billing.user) roles for your project.

To grant this limited ability, you conditionally grant Finn the Project IAM Admin role (roles/resourcemanager.projectIamAdmin). The Project IAM Admin role allows Finn to grant and revoke IAM roles, and the condition limits which roles Finn can grant and revoke:

{
  "version": 3,
  "etag": "BwWKmjvelug=",
  "bindings": [
    {
      "members": [
        "user:owner@example.com"
      ],
      "role": "roles/owner"
    },
    {
      "members": [
        "finn@example.com"
      ],
      "role": "roles/resourcemanager.projectIamAdmin",
      "condition": {
        "title": "only_billing_roles",
        "description": "Only allows changes to role bindings for billing accounts",
        "expression":
          "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/billing.admin', 'roles/billing.user'])"
      }
    }
  ]
}

This conditional role binding lets Finn do the following:

  • Grant the Billing Account Administrator and Billing Account User roles for the project.
  • Revoke the Billing Account Administrator and Billing Account User roles for the project.
  • Add, remove, or modify conditions for project-level role bindings that grant the Billing Account Administrator and Billing Account User roles.
  • Perform other actions allowed by the Project IAM Admin role that do not modify the project's IAM policy. For example, Finn could use the projects.getIamPolicy method to get the project's policy.

This conditional role binding does not let Finn do any of the following:

  • Modify IAM policies for resources other than the project.
  • Grant roles other than the Billing Account Administrator or Billing Account User roles.
  • Revoke roles other than the Billing Account Administrator or Billing Account User roles.
  • Add, remove, or modify conditions for role bindings that do not grant the Billing Account Administrator or Billing Account User roles.

Allowing users to manage limited IAM admins

Consider a scenario where you want to make a user, Lila, a limited IAM admin for her team. You want Lila to be able to grant and revoke only the Compute Admin role (roles/compute.admin) for her project. However, you also want to let Lila select other users to act as limited IAM admins. In other words, you want to let Lila allow other users to grant and revoke only the Compute Admin role.

You might think that the solution is to grant Lila the Project IAM Admin role (roles/resourcemanager.projectIamAdmin), and then give her the ability to grant or revoke that role for others. However, if you grant Lila the Project IAM Admin role, she could remove the condition from her own role and give herself the ability to grant or revoke any IAM role.

To help prevent this privilege escalation, you instead create a Google group, iam-compute-admins@example.com, for the project's limited IAM admins. Then, you add Lila to the group and make her a group manager.

After you create the group, you conditionally grant the group the Project IAM Admin role (roles/resourcemanager.projectIamAdmin). The Project IAM Admin role allows group members to grant and revoke IAM roles, and the condition limits which roles they can grant and revoke:

{
  "version": 3,
  "etag": "BwWKmjvelug=",
  "bindings": [
    {
      "members": [
        "user:owner@example.com"
      ],
      "role": "roles/owner"
    },
    {
      "members": [
        "iam-compute-admins@example.com"
      ],
      "role": "roles/resourcemanager.projectIamAdmin",
      "condition": {
        "title": "only_compute_admin_role",
        "description": "Only allows changes to role bindings for the Compute Admin role",
        "expression":
          "api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/compute.admin'])"
      }
    }
  ]
}

As a member of the iam-compute-admins@example.com group, Lila can do the following:

  • Grant the Compute Admin role for the project by adding a new binding for the role, or by adding a member to an existing binding for the role.
  • Revoke the Compute Admin role by removing an existing binding for the role, or by removing a member from an existing binding for the role.
  • Modify grants for the Compute Admin role by adding, removing, or modifying conditions attached to bindings for the role.
  • Perform other actions allowed by the Project IAM Admin role that do not modify the project's IAM policy. For example, she could use the projects.getIamPolicy method to get the project's policy.

As a manager of the iam-compute-admins@example.com group, Lila can allow other users to grant or revoke the Compute Admin role by adding them to the iam-compute-admins@example.com group.

Lila cannot do the following:

  • Give herself the ability to grant or revoke other roles.
  • Modify IAM policies for resources other than the project.
  • Grant roles other than the Compute Admin role.
  • Revoke roles other than the Compute Admin role.
  • Add, remove, or modify conditions for role bindings that do not grant the Compute Admin role.

Limiting role granting

The following sections explain how to let members grant or revoke only certain roles.

Writing a condition expression to limit role granting

To limit a member's ability to grant roles, write a condition expression that specifies the roles a member can grant or revoke.

Use the following format for your condition expression:

api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(roles)

This expression does the following:

  • Gets the API attribute iam.googleapis.com/modifiedGrantsByRole using the api.getAttribute() function.

    For a request to set the IAM policy of a resource, this attribute contains the role names from the bindings that the request modifies. For other types of requests, the attribute is not defined. In these cases, the function returns the default value ([]).

  • Uses the hasOnly() Common Expression Language (CEL) function to define and enforce the roles that the member is allowed to grant or revoke.

    The input for the hasOnly() function is a list of the roles that the member is allowed to grant or revoke. If the roles in the iam.googleapis.com/modifiedGrantsByRole attribute are included in this list, the function returns true. If they are not, the function returns false.

    If the iam.googleapis.com/modifiedGrantsByRole attribute contains the default value ([]), the function returns true, because [] does not contain any roles not included in the list.

To customize this expression, replace roles with a list of the roles that the member is allowed to grant or revoke. For example, to let the member grant or revoke only the Pub/Sub Editor (roles/pubsub.editor) and Pub/Sub Publisher (roles/pubsub.publisher) roles, use the value ['roles/pubsub.editor', 'roles/pubsub.publisher'].

You can include up to 10 values in the list of allowed roles. All of these values must be string constants.

Limiting role granting with conditional role bindings

To allow a member to grant or revoke only certain roles, use the condition expression from the preceding section to create a conditional role binding. Then, add the conditional role binding to a resource's IAM policy.

  1. Select a resource that represents the scope that you want to let a member grant and revoke roles for:

    • If you want to let a member grant and revoke certain roles for all resources within an organization, select an organization.
    • If you want to let a member grant and revoke certain roles for all resources within an folder, select a folder.
    • If you want to let a member grant and revoke certain roles for all resources within a project, select a project.
  2. Select a role that allows a member to set the IAM policy for the resource type you selected (project, folder, or organization). To follow the principle of least privilege, choose one of the following predefined roles:

    • Projects: Project IAM Admin (roles/resourcemanager.projectIamAdmin)
    • Folders: Folder IAM Admin (roles/resourcemanager.folderIamAdmin)
    • Organizations: Organization Admin (roles/resourcemanager.organizationAdmin).

    Alternatively, choose a custom role that includes the resourcemanager.resource-type.setIamPolicy and resourcemanager.resource-type.getIamPolicy permissions, where resource-type is project, folder, or organization.

  3. Conditionally grant a member your chosen role on the project, folder, or organization you selected.

    The new policy is applied, and your member can modify bindings for only the roles you have allowed.

    Console

    1. In the Cloud Console, go to the IAM page.

      Go to the IAM page

    2. Make sure the name of your project, folder, or organization appears in the resource selector at the top of the page. The resource selector tells you what project, folder, or organization you are currently working in.

      If you don't see the name of your resource, click the resource selector, then select your resource.

    3. In the list of members, locate the member that will grant and revoke roles, and click the button.

    4. In the Edit permissions panel, select the role you chose previously. Then under Condition, click Add condition.

    5. In the Edit condition panel, enter a title and optional description for the condition.

    6. Click the Condition Editor tab and enter the expression you wrote in Writing a condition expression to limit role granting. This expression limits which roles the member can grant or revoke.

      For example, the following condition expression limits the member to granting and revoking the Pub/Sub Editor (roles/pubsub.editor) and Pub/Sub Publisher (roles/pubsub.publisher) roles:

      api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/pubsub.editor', 'roles/pubsub.publisher'])
      

      Warning: Do not include the following types of roles in the list of allowed roles:

      • Roles with permissions to grant and revoke IAM roles (that is, roles with permission names that end in setIamPolicy).
      • Custom roles that the limited IAM admin can modify. For example, if the limited IAM admin also has the Role Administrator role (roles/iam.roleAdmin) on a project, don't allow them to grant or revoke project-level custom roles.

      Limited IAM admins who can grant and revoke these types of roles can give themselves permission to grant and revoke all IAM roles. See Writing a condition expression to limit role granting for more information.

    7. Click Save to apply the condition.

    8. After the Edit condition panel is closed, click Save in the Edit permissions panel to update your IAM policy.

    gcloud

    IAM policies are set using the read-modify-write pattern.

    First, read the IAM policy for the resource:

    Execute the get-iam-policy command. This command gets the current IAM policy for the resource.

    Command:

    gcloud resource-type get-iam-policy resource-id --format=json > path
    

    Replace the following values:

    • resource-type: The resource type that you want to let a member grant or revoke roles for. Use one of the following: projects, folders, or organizations.
    • resource-id: Your Google Cloud project, folder, or organization ID.
    • path: The path of the file to download the IAM policy to.

    The IAM policy is saved in JSON format, for example:

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

    Next, modify the policy.

    To let a member only modify bindings for certain roles, add the highlighted conditional role binding:

    {
      "bindings": [
        {
          "members": [
            "user:owner@example.com"
          ],
          "role": "roles/owner"
        },
        {
          "members": [
            "member"
          ],
          "role": "role",
          "condition": {
            "title": "title",
            "description": "description",
            "expression":
              "expression"
          }
        }
      ],
      "etag": "BwWKmjvelug=",
      "version": 3
    }

    Replace the following values:

    • member: The member that will let grant or revoke certain roles. For example, user:my-user@example.com. To see the formats of each member type, see the Binding reference.
    • role: The role you chose in the preceding steps. This role must include the setIamPolicy permission for the resource type you chose.
    • title: A string briefly describing the condition. For example, only_pubsub_roles.
    • description: Optional. An additional description for the condition. For example, Only allows granting/revoking the Pub/Sub editor and publisher roles.
    • expression: The expression you wrote in Writing a condition expression to limit role granting. This expression limits which roles that the member can grant or revoke.

      For example, the following condition expression limits the member to granting and revoking the Pub/Sub Editor (roles/pubsub.editor) and Pub/Sub Publisher (roles/pubsub.publisher) roles:

      api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/pubsub.editor', 'roles/pubsub.publisher'])
      

      Warning: Do not include the following types of roles in the list of allowed roles:

      • Roles with permissions to grant and revoke IAM roles (that is, roles with permission names that end in setIamPolicy).
      • Custom roles that the limited IAM admin can modify. For example, if the limited IAM admin also has the Role Administrator role (roles/iam.roleAdmin) on a project, don't allow them to grant or revoke project-level custom roles.

      Limited IAM admins who can grant and revoke these types of roles can give themselves permission to grant and revoke all IAM roles. See Writing a condition expression to limit role granting for more information.

    Finally, write the updated policy:

    Set the new policy by executing the set-iam-policy command for the resource:

    gcloud resource-type set-iam-policy resource-id path
    

    Replace the following values:

    • resource-type: The resource type that you want to let a member grant or revoke roles for. Use one of the following: projects, folders, or organizations.
    • resource-id: Your Google Cloud project, folder, or organization ID.
    • path: A path to the file containing the updated policy.

    The new policy is applied, and the member will be able to modify bindings for only the roles you have allowed.

    REST

    IAM policies are set using the read-modify-write pattern.

    First, read the IAM policy for the resource:

    The Resource Manager API's getIamPolicy method gets a project, folder, or organization's IAM policy.

    Before using any of the request data below, make the following replacements:

    • API_VERSION: The API version to use. For projects and organizations, use v1. For folders, use v2.
    • RESOURCE_TYPE: The resource type whose policy you want to manage. Use the value projects, folders, or organizations.
    • RESOURCE_ID: Your Google Cloud project, organization, or folder ID. Project IDs are alphanumeric strings, like my-project. Folder and organization IDs are numeric, like 123456789012.
    • POLICY_VERSION: The policy version to be returned. Requests should specify the most recent policy version, which is policy version 3. See Specifying a policy version when getting a policy for details.

    HTTP method and URL:

    POST https://cloudresourcemanager.googleapis.com/API_VERSION/RESOURCE_TYPE/RESOURCE_ID:getIamPolicy

    Request JSON body:

    {
      "options": {
        "requestedPolicyVersion": POLICY_VERSION
      }
    }
    

    To send your request, expand one of these options:

    You should receive a JSON response similar to the following:

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

    Next, modify the policy.

    Add a conditional role binding that lets a member grant and revoke only certain roles. Make sure to change the version field to the value 3:

    {
      "version": 3,
      "etag": "BwWKmjvelug=",
      "bindings": [
        {
          "members": [
            "user:owner@example.com"
          ],
          "role": "roles/owner"
        },
        {
          "members": [
            "MEMBER"
          ],
          "role": "ROLE",
          "condition": {
            "title": "TITLE",
            "description": "DESCRIPTION",
            "expression":
              "EXPRESSION"
          }
        }
      ]
    }
    • MEMBER: The member that will let grant or revoke certain roles. For example, user:my-user@example.com. To see the formats of each member type, see the Binding reference.
    • ROLE: The role you chose in the preceding steps. This role must include the setIamPolicy permission for the resource type you chose.
    • TITLE: A string briefly describing the condition. For example, only_pubsub_roles.
    • DESCRIPTION: Optional. An additional description for the condition. For example, Only allows granting/revoking the Pub/Sub editor and publisher roles.
    • EXPRESSION: The expression you wrote in Writing a condition expression to limit role granting. This expression limits which roles that the member can grant or revoke.

      For example, the following condition expression limits the member to granting and revoking the Pub/Sub Editor (roles/pubsub.editor) and Pub/Sub Publisher (roles/pubsub.publisher) roles:

      api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly(['roles/pubsub.editor', 'roles/pubsub.publisher'])
      

      Warning: Do not include the following types of roles in the list of allowed roles:

      • Roles with permissions to grant and revoke IAM roles (that is, roles with permission names that end in setIamPolicy).
      • Custom roles that the limited IAM admin can modify. For example, if the limited IAM admin also has the Role Administrator role (roles/iam.roleAdmin) on a project, don't allow them to grant or revoke project-level custom roles.

      Limited IAM admins who can grant and revoke these types of roles can give themselves permission to grant and revoke all IAM roles. See Writing a condition expression to limit role granting for more information.

    Finally, write the updated policy:

    The Resource Manager API's setIamPolicy method sets the policy in the request as the new IAM policy for the project, folder, or organization.

    Before using any of the request data below, make the following replacements:

    • API_VERSION: The API version to use. For projects and organizations, use v1. For folders, use v2.
    • RESOURCE_TYPE: The resource type whose policy you want to manage. Use the value projects, folders, or organizations.
    • RESOURCE_ID: Your Google Cloud project, organization, or folder ID. Project IDs are alphanumeric strings, like my-project. Folder and organization IDs are numeric, like 123456789012.
    • POLICY: A JSON representation of the policy that you want to set. For more information about the format of a policy, see the Policy reference.

      For example, to set the policy shown in the previous step, replace POLICY with the following:

      {
        "version": 3,
        "etag": "BwWKmjvelug=",
        "bindings": [
          {
            "members": [
              "user:owner@example.com"
            ],
            "role": "roles/owner"
          },
          {
            "members": [
              "member"
            ],
            "role": "role",
            "condition": {
              "title": "title",
              "description": "description",
              "expression":
                "expression"
            }
          }
        ]
      }
      

    HTTP method and URL:

    POST https://iam.googleapis.com/API_VERSION/RESOURCE_TYPE/RESOURCE_ID:setIamPolicy

    Request JSON body:

    {
      "policy": POLICY
    }
    

    To send your request, expand one of these options:

    The response contains the updated policy.

What's next