Creating and applying access levels

This page explains how to create access levels using Access Context Manager and apply them on Identity-Aware Proxy (IAP)-secured resources.

Overview

An access level is a set of attributes assigned to requests based on their origin. Using information such as device type, IP address, and user identity, you can designate what level of access to grant. For example, you might assign a "High_Trust" level to connections from within your corporate network and "Medium_Trust" trust to external devices running approved operating systems.

Device information is gathered and referenced by access levels once you set up Endpoint Verification. Endpoint Verification creates an inventory of all the corporate and personal devices accessing your corporate resources.

An access level is enforced by adding it as an Identity and Access Management (IAM) condition on your IAP-secured resource. IAP lets you apply a fine-grained, resource-level access control model instead of using network-level firewalls. For example, you might specify that while many resources are available to "Medium_Trust," certain more sensitive resources require the "High_Trust" level.

For more information, see the Access Context Manager overview.

Before you begin

Before you begin, you need to do the following:

  • Secure a resource with IAP.
  • Set up Endpoint Verification. Note that this is only needed if you want to limit access to your resources based on user device information like storage encryption status.
  • Ensure that you have one of the following roles granted on your project.

    • Access Context Manager Admin
    • Access Context Manager Editor

Creating an access level

The following process creates an access level.

For this example, assume you want to create an access level that allows a group of internal auditors to access Google Cloud's operations suite for a project. All of the devices for the auditors are assigned IPs on a subnet ranging between 203.0.113.0 and 203.0.113.127. You also want to ensure their devices are encrypted. You know there won't be any devices assigned to that subnet other than those used by the auditors.

Console

  1. Got to the Access Context Manager page in the Cloud Console.

    Go to the Access Context Manager page

  2. If you are prompted, select your organization.

  3. At the top of the Access Context Manager page, click New.

  4. In the New Access Level pane, in the Conditions section, click Add attribute and then click Device Policy.

  5. Click the Storage encryption drop-down and select Encrypted. Note that this rule only works once you set up Endpoint Verification on your employees' devices.

  6. Click Add attribute again and select IP Subnetworks.

  7. In the IP Subnetworks box, enter one or more IPv4 or IPv6 ranges formatted as CIDR blocks.

    In this example, to limit access to only the auditors, you would enter 203.0.113.0/25 in the IP Subnetworks box.

  8. Click Save.

gcloud

  1. Create a .yaml file for an access level that includes one or more IPv4 or IPv6 ranges formatted as CIDR blocks.

    In this example, to limit access to only the auditors, you would enter the following into the .yaml file:

    - ipSubnetworks:
        - 203.0.113.0/25
    - devicePolicy:
        allowedEncryptionStatuses
          - ENCRYPTED
    

    For a list of access level attributes and their YAML format, see Access level attributes. See this example access level YAML file for a comprehensive YAML file of all possible attributes.

    Note that the devicePolicy rule only works once you set up Endpoint Verification on your employees' devices.

  2. Save the file. In this example, the file is named CONDITIONS.yaml.

  3. Create the access level.

    gcloud access-context-manager levels create NAME \
       --title TITLE \
       --basic-level-spec CONDITIONS.yaml \
       --policy=POLICY_NAME
    

    Where:

    • NAME is the unique name for the access level. It must begin with a letter and include only letters, numbers, and underscores.

    • TITLE is a human-readable title. It must be unique to the policy.

    • POLICY_NAME is the name of your organization's access policy.

    You should see output similar to:

    Create request issued for: NAME
    Waiting for operation [accessPolicies/POLICY_NAME/accessLevels/NAME/create/1521594488380943] to complete...done.
    Created level NAME.
    

API

  1. Craft a request body to create an AccessLevel resource that includes one or more IPv4 or IPv6 ranges formatted as CIDR blocks and a device policy that requires encrypted storage.

    In this example, to limit access to only the auditors, you would enter the following into the request body:

    {
     "name": "NAME",
     "title": "TITLE",
     "basic": {
       "conditions": [
         {
           "ipSubnetworks": [
             "203.0.113.0/25"
           ]
         },
         {
         "devicePolicy": [
           "allowedEncryptionStatuses": [
             "ENCRYPTED"
           ]
         ]
         }
       ]
     }
    }
    

    Where:

    • NAME is the unique name for the access level. It must begin with a letter and include only letters, numbers, and underscores.

    • TITLE is a human-readable title. It must be unique to the policy.

  2. Create the access level by calling accessLevels.create.

    POST https://accesscontextmanager.googleapis.com/v1/accessPolicies/POLICY_NAME/accessLevels
    

    Where:

    • POLICY_NAME is the name of your organization's access policy.

Applying an access level

An IAP-secured resource has an IAM policy that binds the IAP role to the resource.

By adding an IAM conditional binding to the IAM policy, access to your resources are further restricted based on request attributes. These request attributes include:

  • Access levels
  • URL Host/Path
  • Date/Time

Note that request values being compared to request.host and request.path specified in an IAM conditional binding must be exact. For example, if you restrict access to paths starting with /internal admin, one can bypass the restriction by going to /internal%20admin. See Using hostname and path conditions for more information.

The following steps show how to add your access level to a IAP-secured resource by updating its IAM policy.

Console

  1. Go to the IAP admin page.

    Go to the IAP admin page

  2. Select the checkbox next to the resources that you want to update IAM permissions for.

  3. On the right side Info panel, click Add member.

  4. In the New member box, enter the members that you want to assign a role to.

  5. In the Select a role drop-down list, select the IAP-secured Web App User role.

  6. To specify existing access levels, select them from the Access levels drop-down list. You need to select the IAP-secured Web App User role and have organization level permissions to view existing access levels.

  7. If you want to add more roles to the members, click Add another role.

  8. When you're finished adding roles, click Save.

gcloud

Currently, you can only use the gcloud tool to set project-level conditional bindings.

To set conditional bindings, edit your project's policy.yaml file by following the process below:

  1. Open the IAM policy for the app using the following gcloud command:

    gcloud projects get-iam-policy PROJECT_ID > policy.yaml
    
  2. Edit the policy.yaml file to specify the following:

    • The users and groups you want to apply the IAM condition to.
    • The iap.httpsResourceAccessor role to grant them access to the resources.
    • The IAM condition with your access level.

    The following condition grants access to the user and group if the ACCESS_LEVEL_NAME access level requirements are met and the resource URL path starts with /.

    ...
    - members:
    - group:EXAMPLE_GROUP@GOOGLE.COM
    - user:EXAMPLE_USER@GOOGLE.COM
    role: roles/iap.httpsResourceAccessor
    condition:
        expression: "accessPolicies/ORGANIZATION_NUMBER/accessLevels/ACCESS_LEVEL_NAME" in request.auth.access_levels && request.path.startsWith("/")
        title: CONDITION_TITLE
    ...
    
  3. Bind the policy to the app using the set-iam-policy command. gcloud projects set-iam-policy PROJECT_ID policy.yaml

API

To edit your app's policy.json file, follow the process below for your app type. See Managing access to IAP-secured resources for more information about using the IAM API to manage access policies.

Before doing the app-specific API steps below:

  1. In the project where your app is deployed create a service account.
  2. Authenticate your new service account by using gcloud auth activate-service-account.
  3. Download your new service account's JSON credential file.

    1. Go to the Service accounts page.
      Go to the service accounts page

    2. Click the email address of your service account.

    3. Click Edit.

    4. Click Create key.

    5. Select JSON as your key type.

    6. Create you new key by clicking Create and closing the confirmation window that appears.

  4. Export the following variables.

    export PROJECT_NUM=PROJECT_NUMBER
    export IAP_BASE_URL=https://iap.googleapis.com/v1beta1/projects/${PROJECT_NUMBER}/iap_web
    # Replace with the path to your local service account's downloaded JSON file
    export JSON_CREDS=EXAMPLE.IAM.GSERVICEACCOUNT.COM.JSON
    # Replace POLICY_FILE.JSON with the name of JSON file to use for
    setIamPolicy export JSON_NEW_POLICY=POLICY_FILE.JSON
    

  5. Convert your service account credentials JSON file into an OAuth access token using Oauth2l by running the following command.

    oauth2l header --json ${JSON_CREDS} cloud-platform

  6. If this is your first time running the above command, when prompted:

    1. Get the verification code by clicking the displayed link and copying the code.
    2. Paste the verification code into your app prompt.
    3. Copy the returned bearer token.
    4. Export a variable that's assigned your returned bearer token.
      export CLOUD_OAUTH_TOKEN=AUTHORIZATION_BEARER_TOKEN
  7. If you've run this command before, export the following variable.

    export CLOUD_OAUTH_TOKEN ="$(oauth2l header --json ${JSON_CREDS} cloud-platform)"

App Engine

  1. Export the following App Engine variables:

    # The APP_ID is usually the project ID
    export GAE_APP_ID=APP_ID
    export GAE_BASE_URL=${IAP_BASE_URL}/appengine-${GAE_APP_ID}

  2. Get the IAM policy for the App Engine app using the getIamPolicy method. The empty data bit at the end turns the curl request into POST instead of GET.

    curl -i -H "${CLOUD_OAUTH_TOKEN}" ${GAE_BASE_URL}/:getIamPolicy \
         -d ''
    

  3. Add your IAM conditional binding to the IAM policy JSON file. The following is an example of an edited policy.json file that binds the iap.httpsResourceAccessor role to two users, granting them access to the Context-Aware Access- secured resources. An IAM condition has been added to grant them access to the resources only if the ACCESS_LEVEL_NAME access level requirement is met and the resource URL path starts with /. There can be only one condition per binding.

    Example policy.json file

    {
    "policy": {
      "bindings": [
            {
              "role": "roles/iap.httpsResourceAccessor",
              "members": [
                  "group:EXAMPLE_GROUP@GOOGLE.COM",
                  "user:EXAMPLE_USER@GOOGLE.COM"
              ],
              "condition": {
                "expression": ""accessPolicies/ORGANIZATION_NUMBER/accessLevels/ACCESS_LEVEL_NAME" in request.auth.access_levels && request.path.startsWith("/")",
                "title": "CONDITION_NAME"
              }
            }
        ]
      }
    }
    

  4. Set your new policy.json file using the setIamPolicy method.

    curl -i -H "${CLOUD_OAUTH_TOKEN}" ${GAE_BASE_URL}:setIamPolicy \
         -d @${JSON_NEW_POLICY}

App Engine services and versions

You can also update the IAM policy of a App Engine service, all versions, or a specific version of a service. To do this for a specific version of a service:

  1. Export the following additional variables.
    export GAE_SERVICE=SERVICE_NAME
    export GAE_VERSION=VERSION_NAME
    
  2. Update the exported GAE_BASE_URL variable.
    export GAE_BASE_URL=${IAP_BASE_URL}/appengine-${GAE_APP_ID}/services/${GAE_SERVICE}/versions/${GAE_VERSION}
  3. Get and set the IAM policy for the version using the getIamPolicy and setIamPolicy commands shown above.

GKE and Compute Engine

  1. Export the project ID of your backend service.

    export BACKEND_SERVICE_NAME=BACKEND_SERVICE_NAME

  2. Get the IAM policy for the Compute Engine app using the getIamPolicy method. The empty data bit at the end turns the curl request into POST instead of GET.

    curl -i -H "${CLOUD_OAUTH_TOKEN}" ${IAP_BASE_URL}/compute/services/${BACKEND_SERVICE_NAME}:getIamPolicy \
         -d ''

  3. Add your IAM conditional binding to the IAM policy JSON file. The following is an example of an edited policy.json file that binds the iap.httpsResourceAccessor role to two users, granting them access to the Context-Aware Access- secured resources. An IAM condition has been added to grant them access to the resources only if the ACCESS_LEVEL_NAME access level requirement is met and the resource URL path starts with /. There can be only one condition per binding.


    Example policy.json file

    {
      "policy": {
        "bindings": [
          {
            "role": "roles/iap.httpsResourceAccessor",
            "members": [
              "group":EXAMPLE_GROUP@GOOGLE.COM,
              "user:EXAMPLE_USER@GOOGLE.COM"
            ],
            "condition": {
              "expression": ""accessPolicies/ORGANIZATION_NUMBER/accessLevels/ACCESS_LEVEL_NAME" in request.auth.access_levels && request.path.startsWith("/")",
              "title": "CONDITION_NAME"
            }
          }
        ]
      }
    }
    

  4. Set your new policy.json file using the setIamPolicy method.

    curl -i -H "Content-Type:application/json" \
         -H "$(oauth2l header --json ${JSON_CREDS} cloud-platform)" \
         ${IAP_BASE_URL}/compute/services/${BACKEND_SERVICE_NAME}:setIamPolicy \
         -d @${JSON_NEW_POLICY}