Accessing resources from an OIDC identity provider

This document shows you how to use identity federation to access Google Cloud resources from an identity provider that supports OpenID Connect (OIDC).

Traditionally, applications running outside Google Cloud have used service account keys to access Google Cloud resources. Using identity federation, you can let an external identity impersonate a service account. This lets your workload access Google Cloud resources directly, using a short-lived access token, and eliminates the maintenance and security burden associated with service account keys.

Before you begin

  1. Ensure you have the Workload Identity Pool Admin role (roles/iam.workloadIdentityPoolAdmin).

    Alternatively, the IAM Owner (roles/owner) and Editor (roles/editor) basic roles also include permissions to configure identity federation. You should not grant basic roles in a production environment, but you can grant them in a development or test environment.

  2. Create a Google Cloud service account.

  3. Grant the service account access to call the Google Cloud APIs required by your workload.

Creating a workload identity pool

A workload identity pool is a container for a collection of external identities. Workload identity pools are isolated from each other, but a single pool can impersonate any number of service accounts. In general, we recommend creating a new pool for each of your environments, such as development, staging, or production.

To create a new workload identity pool, you'll need to provide an ID. You can also provide an optional description and display name.

gcloud

Execute the gcloud beta iam workload-identity-pools create command to create a workload identity pool:

gcloud beta iam workload-identity-pools create pool-id \
    --location="global" \
    --description="description" \
    --display-name="display-name"

The response looks like:

Created WorkloadIdentityPool [pool-id].

REST

The projects.locations.workloadIdentityPools.create method creates a workload identity pool.

HTTP method and URL:

POST https://iam.googleapis.com/v1beta/projects/project-id/locations/global/workloadIdentityPools?workloadIdentityPoolId=pool-id

Request JSON body:

{
  "description": "description",
  "display-name": "display-name"
}

To send your request, expand one of these options:

The method returns a long-running Operation similar to the following:

{
  "name": "projects/project-number/locations/global/workloadIdentityPools/pool-id/operations/operation-id"
}

Adding an OIDC identity provider

To configure an OIDC identity provider for your workload identity pool, supply at least the following:

  • An ID for the provider.

  • The workload identity pool ID from the previous section in this document.

  • The provider's issuer URI. This typically takes the form https://example.com. Consult your provider's documentation on OIDC integration to find the URI.

  • A list of attribute mappings that map the claims on an external token to the attributes on a Google token. Use assertion to refer to the external credential, google for Google attributes, and attribute for custom attributes.

    There are two Google attributes: google.subject and google.groups. You can reference these attributes in IAM role bindings. google.subject also appears in Cloud Logging log entries.

    You must provide a mapping for google.subject. In general, we recommend mapping it to assertion.sub, which should provide a stable identifier for use in IAM role bindings. The mapping looks like this:

    google.subject=assertion.sub
    

    For more complex assertions, you can use the Common Expression Language. For example, if your workload identity pool contains multiple identity providers, you can append a prefix to disambiguate between them:

    google.subject="provider-a::" + assertion.sub
    

    The google.subject field cannot exceed 127 characters.

    You can also specify custom attributes. For example, the following maps assertion.foo to attribute.bar:

    attribute.bar=assertion.foo
    

    Consult your provider's documentation on access tokens for a complete list of claims you can reference.

    To reference a specific part of a claim in an expression, use the CEL extract() function, which extracts a value from a claim based on a template you provide. To learn more about extract(), see Extracting values from attributes.

    To check if a credential contains an claim, use the has() function.

  • A list of allowed audiences specifying what values the aud field on the external credential can contain. You can configure a maximum of 10 audiences, each up to 256 characters. Consult your provider's documentation for information on their default values for aud.

    Alternatively, if your identity provider allows you to configure a custom value for aud, you can leave the allowed audiences parameter empty, and set the value of aud to the full resource name of your workload identity provider. The HTTP prefix is optional; for example:

    //iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id
    https://iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id
    

    In either case, any token exchange requests that don't contain one of the allowed values are rejected.

You can also provide several optional parameters:

  • A display name and description.

  • An attribute condition specifying attributes that the principal must present. The condition can apply to claims on the external credential, or attributes on the Google credential. Any request that does not meet the condition is rejected.

    Attribute conditions are formatted as a CEL expression that returns a boolean. For example, the following rejects requests from any identity that isn't a member of a specific group:

    group in assertion.groups
    

    Using attribute conditions is strongly recommended if the identity provider is available to the general public. To learn more about common use cases for attribute conditions, see the workload identity federation overview.

The following example demonstrates adding an identity provider:

gcloud

Execute the gcloud beta iam workload-identity-pools providers create-oidc command to add an identity provider:

gcloud beta iam workload-identity-pools providers create-oidc provider-id \
    --workload-identity-pool="pool-id" \
    --issuer-uri="issuer-uri" \
    --location="global" \
    --attribute-mapping="google.subject=assertion.sub"

The response looks like:

Created WorkloadIdentityPoolProvider [provider-id].

REST

The projects.locations.workloadIdentityPools.providers.create method adds an OIDC identity provider.

HTTP method and URL:

POST https://iam.googleapis.com/v1beta/projects/project-id/locations/global/workloadIdentityPools/pool-id/providers?workloadIdentityPoolProviderId=provider-id

Request JSON body:

{
  "issuerUrl": "issuer-uri"
}

To send your request, expand one of these options:

The method returns a long-running Operation similar to the following:

{
  "name": "projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id/operations/operation-id"
}

Giving permission to impersonate a service account

External identities can't access most Google Cloud resources directly. Instead, you let the identities impersonate a service account by granting them the Workload Identity User role (roles/iam.workloadIdentityUser).

To add this role binding for a specific identity, use the value you mapped to google.subject:

gcloud iam service-accounts add-iam-policy-binding service-account-email \
    --role roles/iam.workloadIdentityUser \
    --member "principal://iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/subject/subject"

To add this binding for all members of a group:

gcloud iam service-accounts add-iam-policy-binding service-account-email \
    --role roles/iam.workloadIdentityUser \
    --member "principalSet://iam.googleapis.com/project/project-number/workloadIdentityPools/pool-id/groups/group-name"

You can also grant access based on custom attributes. For example:

gcloud iam service-accounts add-iam-policy-binding service-account-email \
    --role="roles/iam.workloadIdentityUser" \
    --member="principalSet://iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/attribute.custom-attribute-name/custom-attribute-value"

To revoke access, replace add-iam-policy-binding with remove-iam-policy-binding.

You can also add or revoke bindings using the REST API or client libraries. To learn more, see Granting, changing, and revoking access to resources.

Exchanging an external token for a Google token

Once your external identity has the ability to impersonate a service account, you can exchange its credentials for Google credentials.

To exchange credentials:

  1. Obtain an OIDC ID token from your identity provider (consult your identity provider's documentation for detailed instructions).

  2. Pass the OIDC ID token to the Security Token Service token() method to get a federated access token:

    REST

    The token method exchanges a third-party token for a Google token.

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

    • project-number: Your Google Cloud project number.
    • pool-id: The ID of the workload identity pool you created earlier in this tutorial.
    • provider-id: The ID of the identity provider you configured earlier in this tutorial.

    HTTP method and URL:

    POST https://sts.googleapis.com/v1beta/token

    Request JSON body:

    {
      "audience": "//iam.googleapis.com/projects/project-number/locations/global/workloadIdentityPools/pool-id/providers/provider-id",
      "grantType": "urn:ietf:params:oauth:grant-type:token-exchange",
      "requestedTokenType": "urn:ietf:params:oauth:token-type:access_token",
      "scope": "https://www.googleapis.com/auth/cloud-platform",
      "subjectTokenType": "urn:ietf:params:oauth:token-type:jwt",
      "subjectToken": "oidc-id-token"
    }
    

    To send your request, expand one of these options:

     

    The method returns a federated token.

  3. Call generateAccessToken() to exchange the federated token for a service account access token. A limited number of Google Cloud APIs support federated tokens; all Google Cloud APIs support service account access tokens.

    REST

    The Service Account Credentials API's serviceAccounts.generateAccessToken method generates an OAuth 2.0 access token for a service account.

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

    • project-id: Your Google Cloud project ID.
    • sa-id: The ID of your service account. This can either be the service account's email address in the form sa-name@project-id.iam.gserviceaccount.com, or the service account's unique numeric ID.
    • token: The federated access token.

    HTTP method and URL:

    POST https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/sa-name@project-id.iam.gserviceaccount.com:generateAccessToken

    Request JSON body:

    {
      "scope": [
        "https://www.googleapis.com/auth/cloud-platform"
      ]
    }
    

    To send your request, expand one of these options:

    If the generateAccessToken request was successful, the response body contains an OAuth 2.0 access token and an expiration time. The accessToken can then be used to authenticate a request on behalf of the service account until the expireTime has been reached:

    {
      "accessToken": "eyJ0eXAi...NiJ9",
      "expireTime": "2020-04-07T15:01:23.045123456Z"
    }
    

Once you have an access token for a service account, you can use it to call Google Cloud APIs by including the token in the Authorization header of your requests:

Authorization: Bearer service-account-access-token

The request is authorized as the service account.

What's next