A small bonus for a use case we had in my project : all our CI is on GCP, using Cloud Build and I wanted to create Azure Resource along with Google resources with Terraform by exchanging my Cloud Build service account identity for an equivalent Azure identity.
If you don’t know what I am referring to with identity federation and multi-cloud token exchange, and to understand the prerequisite, make sure to catch up with the previous article of the links above.
Create Azure resources with Terraform from GCP
Remember the Part 3 of this series, we needed to exchange a Google identity token for an Azure access token and we used a curl
request to the AAD Authorization Server, let’s do the same with Terraform, using the http provider !
The http provider is a provider maintained by Hashicorp that cannot create resource, but only make HTTP request on the form of Terraform Data Sources.
1. Add Terraform providers
First let’s add the required providers : google
for creating GCP resources and get the ID token, http
to exchange the token and azurerm
to create Azure resource.
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "4.52.0"
}
http = {
source = "hashicorp/http"
version = "3.2.1"
}
azurerm = {
source = "hashicorp/azurerm"
version = "3.42.0"
}
}
}
# Simply configure the Google provider and use Application Default Credentials
provider "google" {
project = var.google_project_id
}
2. Generate the Google ID token (JWT token)
data "google_service_account_id_token" "oidc" {
# the GCP SA mapped to Azure App Registration
target_service_account = var.target_service_account
target_audience = "api://AzureADTokenExchange"
}
3. Call the Azure Authorization Server to Exchange the access token
Here we first build the payload in a local variable using the same parameters described in Part 3 of this series. We finally query the Authorization Server with the data "http" "azure_id_token"
Data Source.
locals {
azure_id_token_request_body_obj = {
client_id = var.client_id
scope = ".default"
client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
client_assertion = data.google_service_account_id_token.oidc.id_token
grant_type = "client_credentials"
}
azure_id_token_request_body = join("&", formatlist("%s=%s", keys(local.azure_id_token_request_body_obj), values(local.azure_id_token_request_body_obj)))
}
data "http" "azure_id_token" {
url = "${var.aad_authority}${var.azure_tenant_id}/oauth2/v2.0/token"
method = "GET"
request_headers = {
Content-Type = "application/x-www-form-urlencoded"
}
request_body = local.azure_id_token_request_body
}
4. C*onfigure Azure provider and create resource !*
You can now configure the azurerm
provider by using the oidc_token
with the resulting exchanged access_token. You are ready to go with Azure resource creation along with GCP resource creation ! Make sure to give the correct IAM role to the target App Registration depending of what resources you want to create.
Here we create a resource_group and an Azure Storage Account 💾
provider "azurerm" {
features {}
oidc_token = jsondecode(data.http.azure_id_token.body).access_token
}
resource "azurerm_resource_group" "example" {
name = "example-resources"
location = "West Europe"
}
resource "azurerm_storage_account" "example" {
name = "storageaccountname"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
account_tier = "Standard"
account_replication_type = "GRS"
tags = {
environment = "staging"
}
}
It’s the end of this multi-cloud service-to-service identity federation series of articles.
After this series of articles you know how to setup identity federation between GCP and Azure in a secure way. We saw what are access tokens and ID tokens and how they are used by Cloud providers. We saw the steps to exchange a Google ID token for an Azure access token and how to impersonate a GCP service account from an Azure App registration using Workload Identity Federation. Finally with Part 4 and Part 5 we detailed concret implementation in Python and Terraform for your production applications.
If you keep exposing service account keys or secrets after this, you have no excuse !
Thanks for reading! I'm Clement, Data Engineer at Stack Labs.
If you want to discover the Stack Labs Data Platform or join an enthusiast data engineering team and work on awesome technical subjects, please contact us.