Creating Short-Lived Service Account Credentials

This page explains how to create short-lived credentials to assume the identity of a service account. These credentials can be used to authenticate calls to Google Cloud Platform APIs or other non-Google APIs.

Short-lived service account credentials have a limited lifetime; usually fewer than a few hours. Supported credential types include OAuth 2.0 access tokens, OpenID Connect ID tokens, self-signed JSON Web Tokens (JWTs), and self-signed binary objects (blobs).

Short-lived account credentials are useful for scenarios where you need to grant limited access to GCP resources for trusted users. Consider the following example scenario:

  • An application in a project is experiencing errors. The application's developer needs help from an operations engineer on a different team who doesn't have access to the project. The developer creates a limited-privilege service account that only grants access to resources that are necessary to troubleshoot the problem. Next, the developer creates short-lived service account credentials to allow the operations engineer to assume the identity of this restricted service account. Finally, the operations engineer authenticates to GCP on behalf of the service account and performs any required maintenance. Their access to the project is temporary, but can be easily extended as necessary to resolve the problem.

Short-lived service account credentials can also be used in identity federation scenarios to allow authentication with external identity providers. Federated identity is not covered in this topic.

Before you begin

Creating a limited-privilege service account

To create a new service account, see the Creating a service account section of the Creating and Managing Service Accounts topic.

Granting required permissions

There are two different flows that allow a caller to create short-lived credentials for a service account. Each flow requires the appropriate permissions:

  • Direct request: The caller is authenticated as either a Google account or a service account and makes a direct request to create short-lived credentials. Two identities are involved in this flow: the caller, and the service account to be impersonated.
  • Delegated request: Like the direct request flow, the caller is authenticated as either a Google account or a service account, but instead the request is delegated to one or more service accounts in a delegation chain. In this flow, multiple service accounts act as intermediaries between the original caller and the service account to be impersonated. Each service account in the delegation chain must have the required permissions to pass along the request.

    This flow is useful for scenarios where a project contains tiers of limited-privilege service accounts, each of which has been configured to perform a specific or limited function on certain resources. For example, one service account is only granted permissions for Cloud Storage resources, another is only granted permissions for Compute Engine resources, and so on. To successfully delegate a request across service accounts, each must be listed in the delegation chain.

Direct request permissions

As described above, a direct request involves only two identities: the caller, and the service account to be impersonated. In this flow, consider the following identities:

  • Service Account 1 (SA-1), the caller who issues a request for the short-lived credentials.
  • Service Account 2 (SA-2), the limited-privilege account that will be impersonated and for whom the credentials apply.

To grant SA-1 permissions to create short-lived credentials, assign it the roles/iam.serviceAccountTokenCreator role on SA-2. This is an example of a service account being treated like a resource as opposed to an identity: SA-1 must be granted the permission to issue credentials for SA-2. For more information about treating service accounts as an identity or a resource, see Service account permissions.

The following steps use the REST API to grant the required permissions, however you can also use the GCP Console or the gcloud command-line tool.

API

First, get the Cloud IAM policy for SA-2 (the service account to be impersonated). See the serviceAccounts.getIamPolicy() reference for more information.

In the code snippets below, SA-2@PROJECT- ID.iam.gserviceaccount.com represents SA-2, and SA-1@PROJECT-ID.iam.gserviceaccount.com represents SA-1, which is the caller that is requesting short-lived credentials.

Note that each request to this API uses a hyphen (.../projects/-/serviceAccounts...) as a wildcard for the project ID in the first portion of the URL.

Request:

POST https://iam.googleapis.com/v1/projects/-/serviceAccounts/SA-2@PROJECT-ID.iam.gserviceaccount.com:getIamPolicy

Response:

{
  "etag": "BwUqLaVeua8=",
  "bindings": [
    {
      "role": "roles/iam.serviceAccountUser",
      "members": [
          "user:alice@gmail.com"
      ]
    }
  ]
}

If you have not assigned a role to the service account, the response will contain only an etag value:

{
  "etag": "ACAB"
}

Update the policy to grant SA-1 the roles/iam.serviceAccountTokenCreator role:

{
    "policy":
    {
        "etag": "BwUqLaVeua8=",
        "bindings": [
        {
            "role": "roles/iam.serviceAccountUser",
            "members": [
                "user:alice@gmail.com"
            ]
        },
        {
            "role": "roles/iam.serviceAccountTokenCreator",
            "members": [
                "serviceAccount:SA-1@PROJECT-ID.iam.gserviceaccount.com"
            ]
        },
        ]
    },
}

Using the updated policy, execute a serviceAccounts.setIamPolicy() request:

POST https://iam.googleapis.com/v1/projects/-/serviceAccounts/SA-2@PROJECT-ID.iam.gserviceaccount.com:setIamPolicy

The response contains the updated policy:

{
    "etag": "BwUqMqbViM8=",
    "bindings": [
      {
        "role": "roles/iam.serviceAccountUser",
        "members": [
            "user:alice@gmail.com"
        ]
      },
      {
        "role": "roles/iam.serviceAccountTokenCreator",
        "members": [
            "serviceAccount:SA-1@PROJECT-ID.iam.gserviceaccount.com"
        ]
      }
    ]
}

Delegated request permissions

As described above, a delegated request involves more than two identities: the caller, one or more service accounts in a delegation chain, and finally the service account to be impersonated. In this flow, consider the following identities:

  • Service Account 1 (SA-1), the caller who issues a request for the short-lived credentials.
  • Service Account 2 (SA-2), an intermediary service account that will delegate the initial request to SA-3.
  • Service Account 3 (SA-3), the limited-privilege account that will be impersonated and for whom the credentials apply.

To allow delegation, SA-1 must be granted the roles/iam.serviceAccountTokenCreator role on SA-2. This is an example of a service account being treated like a resource as opposed to an identity: SA-1 must be granted the permission to delegate access for SA-2. For more information about treating service accounts as an identity or a resource, see Service account permissions.

In this example flow, there is only one intermediary service account. To delegate access through more than one service account, you must also assign this role to any other service account in the chain.

Next, SA-2 must also be granted the roles/iam.serviceAccountTokenCreator role on SA-3. This allows SA-2 to create short-lived credentials for SA-3.

The following steps use the REST API to grant the required permissions, however you can also use the GCP Console or the gcloud command-line tool.

API

First, get the Cloud IAM policy for SA-2 (the intermediary service account). See the serviceAccounts.getIamPolicy() reference for more information.

In the code snippets below, SA-2@PROJECT- ID.iam.gserviceaccount.com represents SA-2, and SA-1@PROJECT-ID.iam.gserviceaccount.com represents SA-1, which is the caller that is requesting short-lived credentials.

Note that each request to this API uses a hyphen (.../projects/-/serviceAccounts...) as a wildcard for the project ID in the first portion of the URL.

Request:

POST https://iam.googleapis.com/v1/projects/-/serviceAccounts/SA-2@PROJECT-ID.iam.gserviceaccount.com:getIamPolicy

Response:

{
  "etag": "BwUqLaVeua8=",
  "bindings": [
    {
      "role": "roles/iam.serviceAccountUser",
      "members": [
          "user:alice@gmail.com"
      ]
    }
  ]
}

If you have not assigned a role to the service account, the response will contain only an etag value:

{
  "etag": "ACAB"
}

Update the policy to grant SA-1 the roles/iam.serviceAccountTokenCreator role:

{
    "policy":
    {
        "etag": "BwUqLaVeua8=",
        "bindings": [
          {
            "role": "roles/iam.serviceAccountUser",
            "members": [
                "user:alice@gmail.com"
            ]
          },
          {
            "role": "roles/iam.serviceAccountTokenCreator",
            "members": [
                "serviceAccount:SA-1@PROJECT-ID.iam.gserviceaccount.com"
            ]
        },
        ]
    },
}

Using the updated policy, execute a serviceAccounts.setIamPolicy() request:

POST https://iam.googleapis.com/v1/projects/-/serviceAccounts/SA-2@PROJECT-ID.iam.gserviceaccount.com:setIamPolicy

The response contains the updated policy:

{
    "etag": "BwUqMqbViM8=",
    "bindings": [
    {
        "role": "roles/iam.serviceAccountUser",
        "members": [
            "user:alice@gmail.com"
        ]
    },
    {
        "role": "roles/iam.serviceAccountTokenCreator",
        "members": [
            "serviceAccount:SA-1@PROJECT-ID.iam.gserviceaccount.com"
        ]
    }
    ]
}

Next, get the Cloud IAM policy for SA-3 (the service account to be impersonated).

Request:

POST https://iam.googleapis.com/v1/projects/-/serviceAccounts/SA-3@PROJECT-ID.iam.gserviceaccount.com:getIamPolicy

Response:

{
    "etag": "BwUqLaVeua8=",
    "bindings": [
    {
        "role": "roles/iam.serviceAccountUser",
        "members": [
            "user:alice@gmail.com"
        ]
    }
    ]
}

If you have not assigned a role to the service account, the response will contain only an etag value:

{
  "etag": "ACAB"
}

Update the policy to grant SA-2 the roles/iam.serviceAccountTokenCreator role:

{
    "policy":
    {
        "etag": "BwUqLaVeua8=",
        "bindings": [
        {
            "role": "roles/iam.serviceAccountUser",
            "members": [
                "user:alice@gmail.com"
            ]
        },
        {
            "role": "roles/iam.serviceAccountTokenCreator",
            "members": [
                "serviceAccount:SA-2@PROJECT-ID.iam.gserviceaccount.com"
            ]
        },
        ]
    },
}

Using the updated policy, execute a serviceAccounts.setIamPolicy() request:

POST https://iam.googleapis.com/v1/projects/-/serviceAccounts/SA-3@PROJECT-ID.iam.gserviceaccount.com:setIamPolicy

The response contains the updated policy:

{
    "etag": "BwUqMqbViM8=",
    "bindings": [
    {
        "role": "roles/iam.serviceAccountUser",
        "members": [
            "user:alice@gmail.com"
        ]
    },
    {
        "role": "roles/iam.serviceAccountTokenCreator",
        "members": [
            "serviceAccount:SA-2@PROJECT-ID.iam.gserviceaccount.com"
        ]
    }
    ]
}

Requesting short-lived credentials

After you have granted the appropriate permissions for each identity, you can request short-lived credentials to assume the identity of the desired service account. The following credential types are supported:

To understand how to specify a delegation chain for these requests, see the Specifying a delegation chain section below.

Generating an OAuth 2.0 access token

OAuth 2.0 access tokens are valid for 1 hour, or 3600 seconds. To generate an OAuth 2.0 access token on behalf of a service account:

API

Execute a generateAccessToken request in the following way, where SA-4@PROJECT-ID.iam.gserviceaccount.com is the name of the service account to be impersonated:

POST https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SA-4@PROJECT-ID.iam.gserviceaccount.com:generateAccessToken

The request must be authenticated by including an access token in the Authorization header of the request. For more information on how to obtain an access token to call Google APIs, see the OAuth 2.0 Overview and OAuth 2.0 for Service Accounts topics.

Specify the following fields in the request body:

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

Each of these fields and their example values are described below:

  • delegates[]: If you are using a delegated request flow, see the Specifying a delegation chain section below. If you are using a direct request flow with no delegation, omit the delegates[] field in the request body.
  • scope: The OAuth 2.0 scope for the request. The following scopes are valid when calling the generateAccessToken API:
    • https://www.googleapis.com/auth/iam
    • https://www.googleapis.com/auth/cloud-platform
    Consider the following example scope field:
      ...
      "scope": [
          "https://www.googleapis.com/auth/cloud-platform"
      ]
      ...
      
  • lifetime: The duration of the access token in seconds, after which the token expires. The maximum token lifetime is 1 hour, or 3600 seconds.

    Consider the following example lifetime field that sets the token's duration to 5 minutes:
      ...
      "duration": "300"
      ...
      

If the generateAccessToken request was successful, the response body contains an OAuth 2.0 access token and an expiration time:

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

The accessToken can then be used to authenticate a request on behalf of the service account until the expireTime has been reached.

Generating OpenID Connect ID tokens

OpenID Connect ID tokens are valid for 1 hour, or 3600 seconds. To generate an ID token on behalf of a service account:

API

Execute a generateIdToken request in the following way, where SA-4@PROJECT-ID.iam.gserviceaccount.com is the name of the service account to be impersonated:

POST https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SA-4@PROJECT-ID.iam.gserviceaccount.com:generateIdToken

The request must be authenticated by including an access token in the Authorization header of the request. For more information on how to obtain an access token to call Google APIs, see the OAuth 2.0 Overview and OAuth 2.0 for Service Accounts topics.

Specify the following fields in the request body:

{
  "delegates": [],
  "audience": "SA-4@PROJECT-ID.iam.gserviceaccount.com",
  "includeEmail": "true"
}

Each of these fields and their example values are described below:

  • delegates[]: If you are using a delegated request flow, see the Specifying a delegation chain section below. If you are using a direct request flow with no delegation, omit the delegates[] field in the request body.
  • audience: The URL of a service or the email address of the service account to be impersonated. For example:
      ...
      "audience": "SA-4@PROJECT-ID.iam.gserviceaccount.com"
      ...
      
  • includeEmail: If set to true, the email claim in the ID token will include the service account's email. Additionally, an email_verified claim will be set to true and will also be included in the ID token. For example:
      ...
      "includeEmail": "true"
      ...
      

If the generateIdToken request was successful, the response body contains an ID token that is valid for 1 hour:

{
   "token": "eyJ0eXAi...NiJ9"
}

The token can then be used to authenticate a request on behalf of the service account.

Creating a self-signed JSON Web Token (JWT)

Self-signed JWTs are useful in a variety of scenarios, such as:

  • Authenticating a call to a Google API as described in Google's Authentication Guide.
  • Securely communicating between GCP or non-Google services, such as App Engine applications. In this scenario, one application can sign a token that can be verified by the another application for authentication purposes.
  • Treating a service account as an identity provider by signing a JWT that contains arbitrary claims about a user, account, or device.

To generate a self-signed JSON Web Token (JWT) on behalf of a service account:

API

Execute a signJwt request in the following way, where SA-4@PROJECT-ID.iam.gserviceaccount.com is the name of the service account to be impersonated:

POST https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SA-4@PROJECT-ID.iam.gserviceaccount.com:signJwt

The request must be authenticated by including an access token in the Authorization header of the request. For more information on how to obtain an access token to call Google APIs, see the OAuth 2.0 Overview and OAuth 2.0 for Service Accounts topics.

Specify the following fields in the request body:

{
  "delegates": [],
  "payload": "{ \"iss\": \"SA-4@PROJECT-ID.iam.gserviceaccount.com\", \"sub\": \"SA-4@PROJECT-ID.iam.gserviceaccount.com\", \"aud\": \"https://firestore.googleapis.com/google.firestore.v1beta1.Firestore\", \"iat\": 1529350000, \"exp\": 1529353600 }"
}

Each of these fields and their example values are described below:

  • delegates[]: If you are using a delegated request flow, see the Specifying a delegation chain section below. If you are using a direct request flow with no delegation, omit the delegates[] field in the request body.
  • payload: The JWT payload to sign, which is a JSON object that contains a JWT Claims Set. Include the claims that are necessary for your desired use case and to meet the validation requirements by the downstream service. If you are calling a Google API, see the Google's Authentication Guide for claim requirements.

    The exp (expiration time) claim must be set to no longer than 12 hours in the future, otherwise it will fail to validate.

    Note: Ensure that the claims set is properly formatted to escape quotations or punctuation marks.

    The following example claims set contains example claims to call a Google API with a maximum lifetime of 1 hour (3600):
      ...
      "payload": "payload": "{ \"iss\": \"SA-4@PROJECT-ID.iam.gserviceaccount.com\", \"sub\": \"SA-4@PROJECT-ID.iam.gserviceaccount.com\", \"aud\": \"https://firestore.googleapis.com/google.firestore.v1beta1.Firestore\", \"iat\": 1529350000, \"exp\": 1529353600 }"
      ...
      

If the signJwt request was successful, the response body contains a signed JWT and the signing key ID that was used to sign the JWT. The token is valid up to the expiration time specified in the request:

{
   "keyId": "42ba1e...fc0a"
   "signedJwt": "eyJ0eXAi...NiJ9"
}

The signedJwt value can then be used as a bearer token to directly authenticate a request on behalf of the service account.

Creating a self-signed blob

Self-signed blobs are useful in scenarios when you need to securely transmit arbitrary binary data, usually for authentication purposes. For example, if you want to use a custom protocol/token type (not JWT), you can include that data in a signed blob for use by a downstream service.

To generate a self-signed blob on behalf of a service account:

API

Execute a signBlob request in the following way, where SA-4@PROJECT-ID.iam.gserviceaccount.com is the name of the service account to be impersonated:

POST https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SA-4@PROJECT-ID.iam.gserviceaccount.com:signBlob

The request must be authenticated by including an access token in the Authorization header of the request. For more information on how to obtain an access token to call Google APIs, see the OAuth 2.0 Overview and OAuth 2.0 for Service Accounts topics.

Specify the following fields in the request body:

{
  "delegates": [],
  "payload": "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2cu"
}

Each of these fields and their example values are described below:

  • delegates[]: If you are using a delegated request flow, see the Specifying a delegation chain section below. If you are using a direct request flow with no delegation, omit the delegates[] field in the request body.
  • payload: A Base64-encoded string of bytes. For example:
      ...
      "payload": "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2cu"
      ...
      

If the signBlob request was successful, the response body contains a signed blob and the signing key ID that was used to sign the blob. The token is valid up to the expiration time specified in the request:

{
   "keyId": "42ba1e...fc0a"
   "signedBlob": "eyJ0eXAi...NiJ9"
}

Specifying a delegation chain

When using a delegated request flow to create short-lived service account credentials, the request body for each API must specify the service account delegation chain in the correct order and in the following format:

projects/-/serviceAccounts/ACCOUNT-EMAIL-OR-UNIQUEID

For example, in a delegation chain that flows from SA-1 (caller) to SA-2 (delegated) to SA-3 (delegated) to SA-4 (the impersonated account), the delegates[] field would contain SA-2 and SA-3 in the following order:

...
"delegates": [
    "projects/-/serviceAccounts/SA-2@PROJECT-ID.iam.gserviceaccount.com",
    "projects/-/serviceAccounts/SA-3@PROJECT-ID.iam.gserviceaccount.com"
],
...

Note that the caller and the impersonated service account are not included in the delegation chain.

Was this page helpful? Let us know how we did:

Send feedback about...

Cloud Identity and Access Management Documentation