Part 5. Provision Azure resources with Terraform from GCP with token exchange
Tags: googlecloud, multicloud, terraform, azure
Published: 2023-02-14 13:28:18

---
series: Multi-Cloud identity federation explained
---

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.

![Provision Azure resources with Terraform from GCP with token exchange](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/avx5g7v3swb11eozd8ph.png)

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](https://dev.to/stack-labs/multi-cloud-identity-federation-explained-part-3-token-exchange-from-gcp-to-azure-4o8e), 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](https://registry.terraform.io/providers/hashicorp/http/latest/docs) ! 

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.

```python
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)**

```python
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](https://dev.to/stack-labs/multi-cloud-identity-federation-explained-part-3-token-exchange-from-gcp-to-azure-4o8e). We finally query the Authorization Server with the `data "http" "azure_id_token"` Data Source.

```python
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 💾

```bash
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](https://dev.to/stack-labs/multi-cloud-identity-federation-explained-part-4-implement-token-exchange-between-azure-and-gcp-in-python-1gop) 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](https://stack-labs.com/).

If you want to discover the [Stack Labs Data Platform](https://cloud.stack-labs.com/cloud-data-platform) or join an enthusiast [data engineering team](https://www.welcometothejungle.com/fr/companies/stack-labs) and work on awesome technical subjects, please contact us.