Google Cloud: configuring workload identity federation with Azure

Miren Esnaola
Google Cloud - Community
8 min readFeb 17, 2022

The most straightforward way for workloads running outside of Google Cloud to call Google Cloud APIs is by using a downloaded service account key.

However, this approach has 2 major pain points:

  • A management hassle, keys need to be stored securely and rotated often.
  • A security risk, keys are long term credentials that could be compromised.

Workload identity federation enables applications running outside of Google Cloud to replace long-lived service account keys with short-lived access tokens. This is achieved by configuring Google Cloud to trust an external identity provider, so applications can use the credentials issued by the external identity provider to impersonate a service account.

Currently Google Cloud supports integration with the following IdPs:

  • AWS
  • OIDC-compliant IdPs
  • SAML compliant IdPs (In preview)

The following diagram illustrates how workload identity federation actually works behind the scenes:

  1. A workload running on-premises or in another cloud provider submits a request to authenticate against the IdP.
  2. The IdP authenticates the identity associated with that workload and returns account credentials.
  3. The workload makes a call to the Google Cloud Secure Token Service (STS) supplying the account credentials issued by the IdP.
  4. STS validates the supplied token and returns a short-lived token.
  5. The workload uses that token to impersonate a service account.
  6. Finally, the workload gets access to the protected resource on Google Cloud.

In this article I will explain how to configure workload identity federation with Azure (OIDC-compliant IdP) so workloads running on an Azure VM can impersonate a service account to perform operations on a Google Cloud resource.

Whenever we configure workload identity federation, there are 3 key steps to follow:

  1. Preparing the external IdP.
  2. Defining an attribute mapping and optionally an attribute condition to map IdP credentials to external identities.
  3. Preparing Google Cloud to establish trust with the external IdP.

Let’s go step by step through the whole process.

Preparing the external IdP

Before jumping into the details explaining what needs to be set up in Azure, it is important to understand how identity and access management (IAM) works on Azure.

Azure Active Directory (AAD) is Microsoft’s cloud-based IAM service, which helps an organization’s employees sign in and access resources in:

  • External resources, such as Microsoft 365, the Azure portal, and other SaaS applications.
  • Internal resources, such as apps on the corporate network and intranet, along with any cloud apps developed by the organization.

An AAD tenant is a dedicated instance of AAD that an organization receives at the beginning of a relationship with Microsoft. The relationship can start, for instance, signing up for Azure or Microsoft 365.

An application must be registered in a tenant to be able to delegate identity and access management to AAD. In the portal this is done on the App Registrations blade.

When an application is registered, one specifies whether it is single-tenant or multi-tenant. An application is defined by its one and only application object residing in the tenant where the application was registered. An application object is used as a template to create one or more service principal objects. A service principal is created in every tenant where the application is used, and they can be managed in the Enterprise Applications blade in the portal.

Managed identities (MI) provide an AAD identity to an Azure managed resource. Code running on those resources can use the MI to request access tokens for services supporting AAD authentication. There are 2 types of managed identities:

  • System-assigned — Some Azure services allow enabling a managed identity directly on a service instance. If enabled, an identity is created in AAD, that is tied to the lifecycle of the service instance.
  • User-assigned — Managed identities can also be created as a standalone Azure resource and then be assigned to one or more instances of an Azure service. In this case the identity is not tied to the lifecycle of the service instance.

Applications registered in an AAD tenant are, by default, available to identities of the tenant(s) who authenticate successfully. Application RBAC is a mechanism to enforce authorization for applications available to a tenant. The application developer defines roles. An administrator can then assign those roles to different identities (e.g. a VM’s managed identity).

The diagram below depicts the relationship between the different entities described so far:

Code running on a VM can use the managed identity associated with the VM to request an access token for a resource from the token endpoint in the Azure Instance Metadata Server (IMDS), that is accessible only from within the VM. More details on how to invoke that endpoint can be found here.

The sequence diagram describes the process of obtaining a token for a resource and using it to access the resource.

In the case of Azure App Service or Azure Functions, an app with an associated MI makes the endpoint to request access tokens available by defining 2 environment variables:

  • IDENTITY_ENDPOINT — URL to the local token service.
  • IDENTITY_HEADER — Header used to help mitigate SSRF attacks. The value is rotated by the platform.

For more details on how to invoke that endpoint check here.

Ok, so now that it is clear how IAM works in Azure, let’s see what needs to be set up in Azure to achieve the integration with Google Cloud for workload identity federation. You just need to follow these steps:

  1. Create a new AAD application that you will use exclusively to obtain Google Cloud credentials.
  2. Set an application ID URI, that uniquely identifies the application in your Azure Active Directory, and write it down, as it will be required when doing the configuration in Google Cloud.
  3. Assign role(s) to the application.
  4. Create a service principal for the application in the AAD tenant.

If you use Terraform for automation you can easily do this as follows:

resource “azuread_application” “app” {display_name = <APP_NAME>identifier_uris = [<APPLICATION_ID_URI>]app_role {
allowed_member_types = [“Application”]
description = <ROLE_DESCRIPTION>
display_name = <ROLE_DISPLAY_NAME>
enabled = true
id = <UUID>
value = <ROLE_VALUE>
}
}
resource “azuread_service_principal” “service_principal” {application_id = azuread_application.app.application_id
app_role_assignment_required = true
}

Defining an attribute mapping and an optional attribute condition

In the context of workload identity federation claims present in the IdP credential (in our case the JWT token issued by AAD) are referred to as assertion attributes and represented as assertion.[NAME].

An attribute mapping is required to map assertion attributes to predefined target attributes recognized by workload identity federation, which are listed below:

  • google.sub — A unique identifier for the external identity. For OIDC providers, such as the one we are working with, it is required to provide a mapping for this target attribute.
  • google.groups — A set of groups that the identity belongs to.
  • attribute.[NAME] — Up to 50 custom attributes.

We will later see how this target attributes are used when creating the IAM bindings in the IAM policy associated with the service account that we will try to impersonate.

The attribute mapping takes the following form:

TARGET_ATTRIBUTE=SOURCE_EXPRESSION

CEL (Common Expression Language) can be used to define source expressions operating on assertion attributes.

A suitable mapping for our use case would be the one below:

google.subject=assertion.sub

Optionally, we could also add an attribute condition to establish the circumstances under which external credentials are accepted. Conditions are written as CEL expressions that can check assertion attributes and target attributes. If the condition evaluates to true, the credential is accepted. Otherwise, the credential is rejected. To keep things simple, we will not specify a condition.

Preparing Google Cloud to establish trust with the external IdP

We are almost done. The last step is to proceed with the configuration on Google Cloud. For that purpose we will need to create a workload identity pool and provider in a Google Cloud project. The provider will be configured to trust tokens issued by our AAD tenant for the application created previously.

The Google Cloud project will need to have the following APIs enabled:

  • cloudresourcemanager.googleapis.com
  • iam.googleapis.com
  • iamcredentials.googleapis.com
  • sts.googleapis.com

To create the workload identity pool and provider one of the following roles would need to be granted on that project:

  • Workload Identity Pool Admin
  • Owner (not recommended for production)

The creation of these two resources can be done on Terraform using this code:

resource "google_iam_workload_identity_pool" "pool" {  provider                  = google-beta
project = <PROJECT_ID>
workload_identity_pool_id = <POOL_ID>
}resource "google_iam_workload_identity_pool_provider" "provider" { provider = google-beta
project = <PROJECT_ID>
workload_identity_pool_id = google_iam_workload_identity_pool.pool.workload_identity_pool_id
workload_identity_pool_provider_id = <PROVIDER_ID>
attribute_mapping = { "google.subject" = "assertion.sub" } oidc { allowed_audiences = [<APPLICATION_ID_URI>]
issuer_uri = "https://sts.windows.net/<AAD_TENANT_ID>"
}}

Testing our set up

Ok, so all the configuration is done. Let’s now confirm that it actually works. How do we do this?

1. Let’s begin by creating a Linux VM in Azure with a system-assigned MI and installing the gcloud CLI on it.

2. Once the VM is ready, create an app role assignment in Azure so the MI associated with the VM can request access tokens for the AAD application. Using Terraform this is done as follows:

resource “google_service_account_iam_binding” “admin-account-iam” {service_account_id = <SERVICE_ACCOUNT_EMAIL>
role = “roles/iam.workloadIdentityUser”
members = [ "principalSet://iam.googleapis.com/projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/<POOL_ID>/*" ]
}

3. In Google Cloud, grant the external identity the Workload Identity User role on a service account with the role grants required to perform desired operation on a resource.

Members in the IAM binding can be referenced as follows:

  • A specific external identity
principal://iam.googleapis.com/projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/<POOL_ID>/subject/<SUBJECT>
  • A group of external identities
principal://iam.googleapis.com/projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/<POOL_ID>/group/<GROUP>
  • A group of external identities identified by having a certain value in a custom attribute.
principalSet://iam.googleapis.com/projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/<POOL_ID>/attribute.<ATTRIBUTE_NAME>/<ATTRIBUTE_VALUE>
  • All external identities in the workload identity pool.
principalSet://iam.googleapis.com/projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/<POOL_ID>/*

In this particular case, we granted all the identities in the pool permission to impersonate the service account.

4. Using gcloud CLI, generate a credentials file.

gcloud iam workload-identity-pools create-cred-config \
projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/<POOL_ID>/providers/<PROVIDER_ID> \
--service-account=<SERVICE_ACCOUNT_EMAIL> \
--azure \
--app-id-uri <APPLICATION_ID_URI> \
--output-file=<FILEPATH>.json

A note of warning here. The credential file generated in this case it is suitable for workload running in a VM. If you inspect the file you will see that the Azure IMDS url is referenced as the IdP token endpoint. However, this endpoint is not suitable for an app on Azure App Service or Azure Functions. In that case, the token endpoint will be given by the environment variable INDETITY_ENDPOINT and a X-IDENTITY-HEADER HTTP header with the value of the environment variable IDENTIT_HEADER will need to be added.

5. Log in to Google Cloud using the generated credential file.

gcloud auth login –cred-file <FILEPATH>.json

6. Run the specific gcloud command to execute the operation on the resource.

I hope this article has helped you to better understand how workload identity federation for Azure works and is set up. Please, have a look at code associated with this example that is available for you to check in the Cloud Foundations fabric repository.

I intend to do a follow-up article on how to set up workload identity federation for AD FS. See you all back once that article is ready.

--

--

Miren Esnaola
Google Cloud - Community

I’m a Cloud Consultant in the Google Cloud Professional Services team