Created
February 10, 2026 20:48
-
-
Save simongottschlag/946515cdaf01f2ce6271aa116f557aed to your computer and use it in GitHub Desktop.
Terraform example for accessing a separate Entra tenant using an UAMI and Multi Tenant app
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| resource "azapi_resource" "resource_group_cae" { | |
| type = "Microsoft.Resources/resourceGroups@2025-04-01" | |
| name = "rg-${var.environment}-${var.location_short}-cae" | |
| location = var.location | |
| response_export_values = {} | |
| } | |
| resource "azapi_resource" "container_app_environment" { | |
| type = "Microsoft.App/managedEnvironments@2025-10-02-preview" | |
| name = "cae-${var.environment}-${var.location_short}" | |
| parent_id = azapi_resource.resource_group_cae.id | |
| location = var.location | |
| body = { | |
| properties = { | |
| publicNetworkAccess = "Enabled" | |
| workloadProfiles = [ | |
| { | |
| workloadProfileType = "Consumption" | |
| name = "Consumption" | |
| } | |
| ] | |
| } | |
| } | |
| response_export_values = {} | |
| } | |
| resource "azapi_resource" "user_assigned_identity_container_app_azure_cli" { | |
| type = "Microsoft.ManagedIdentity/userAssignedIdentities@2025-01-31-preview" | |
| name = "uami-ca-${var.environment}-${var.location_short}-azure-cli" | |
| parent_id = azapi_resource.resource_group_cae.id | |
| location = var.location | |
| response_export_values = { | |
| client_id = "properties.clientId" | |
| principal_id = "properties.principalId" | |
| } | |
| } | |
| resource "azapi_resource" "container_app_azure_cli" { | |
| type = "Microsoft.App/containerApps@2025-10-02-preview" | |
| parent_id = azapi_resource.resource_group_cae.id | |
| name = "ca-${var.environment}-${var.location_short}-azure-cli" | |
| location = azapi_resource.container_app_environment.location | |
| identity { | |
| type = "UserAssigned" | |
| identity_ids = [azapi_resource.user_assigned_identity_container_app_azure_cli.id] | |
| } | |
| body = { | |
| properties = { | |
| configuration = { | |
| activeRevisionsMode = "Single" | |
| } | |
| managedEnvironmentId = azapi_resource.container_app_environment.id | |
| template = { | |
| containers = [ | |
| { | |
| name = "azure-cli" | |
| image = "mcr.microsoft.com/azure-cli:2.83.0-azurelinux3.0" | |
| command = [ | |
| "sleep", | |
| ] | |
| args = [ | |
| "infinity", | |
| ] | |
| env = [ | |
| { | |
| name = "AZURE_CLIENT_ID" | |
| value = azapi_resource.user_assigned_identity_container_app_azure_cli.output.client_id | |
| }, | |
| ] | |
| resources = { | |
| cpu = 0.25 | |
| memory = "0.5Gi" | |
| } | |
| }, | |
| ] | |
| scale = { | |
| minReplicas = 1 | |
| maxReplicas = 1 | |
| } | |
| } | |
| } | |
| } | |
| response_export_values = {} | |
| } | |
| output "container_app_azure_cli" { | |
| value = <<EOT | |
| az login --identity --allow-no-subscriptions --client-id $AZURE_CLIENT_ID | |
| UAMI_ACCESS_TOKEN=$(az account get-access-token --scope api://AzureADTokenExchange/.default --output tsv --query accessToken) | |
| CUSTOMER_ACCESS_TOKEN=$(curl -sS -X POST "https://login.microsoftonline.com/${var.customer_tenant_id}/oauth2/v2.0/token" \ | |
| -H "Content-Type: application/x-www-form-urlencoded" \ | |
| --data-urlencode "client_id=${azuread_application.provider_app.client_id}" \ | |
| --data-urlencode "scope=https://graph.microsoft.com/.default" \ | |
| --data-urlencode "grant_type=client_credentials" \ | |
| --data-urlencode "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \ | |
| --data-urlencode "client_assertion=$${UAMI_ACCESS_TOKEN}" | jq -r '.access_token') | |
| curl -sS https://graph.microsoft.com/v1.0/applications \ | |
| -H "Authorization: Bearer $${CUSTOMER_ACCESS_TOKEN}" \ | |
| -H "Accept: application/json" | jq | |
| EOT | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| resource "azuread_service_principal" "customer_provider_app" { | |
| provider = azuread.customer_entra | |
| client_id = azuread_application.provider_app.client_id | |
| } | |
| data "azuread_application_published_app_ids" "customer_well_known" { | |
| provider = azuread.customer_entra | |
| } | |
| data "azuread_service_principal" "msgraph" { | |
| provider = azuread.customer_entra | |
| client_id = data.azuread_application_published_app_ids.customer_well_known.result.MicrosoftGraph | |
| } | |
| resource "azuread_app_role_assignment" "customer_provider_app_msgraph_directory_read_all" { | |
| provider = azuread.customer_entra | |
| app_role_id = data.azuread_service_principal.msgraph.app_role_ids["Directory.Read.All"] | |
| principal_object_id = azuread_service_principal.customer_provider_app.object_id | |
| resource_object_id = data.azuread_service_principal.msgraph.object_id | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| terraform { | |
| required_providers { | |
| azapi = { | |
| source = "Azure/azapi" | |
| version = "2.8.0" | |
| } | |
| azuread = { | |
| source = "hashicorp/azuread" | |
| version = "3.7.0" | |
| } | |
| } | |
| } | |
| provider "azapi" {} | |
| provider "azuread" { | |
| alias = "provider_entra" | |
| tenant_id = var.provider_tenant_id | |
| } | |
| provider "azuread" { | |
| alias = "customer_entra" | |
| tenant_id = var.customer_tenant_id | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| resource "azuread_application" "provider_app" { | |
| provider = azuread.provider_entra | |
| display_name = "provider-app" | |
| identifier_uris = ["api://provider-app"] | |
| sign_in_audience = "AzureADMultipleOrgs" | |
| api { | |
| requested_access_token_version = 2 | |
| } | |
| } | |
| resource "azuread_application_federated_identity_credential" "container_app_azure_cli" { | |
| provider = azuread.provider_entra | |
| application_id = azuread_application.provider_app.id | |
| display_name = "azure-cli" | |
| audiences = ["api://AzureADTokenExchange"] | |
| issuer = "https://login.microsoftonline.com/${var.provider_tenant_id}/v2.0" | |
| subject = azapi_resource.user_assigned_identity_container_app_azure_cli.output.principal_id | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| variable "provider_tenant_id" { | |
| description = "The tenant ID of the provider subscription." | |
| type = string | |
| } | |
| variable "provider_subscription_id" { | |
| description = "The subscription ID of the provider subscription." | |
| type = string | |
| } | |
| variable "customer_tenant_id" { | |
| description = "The tenant ID of the customer subscription." | |
| type = string | |
| } | |
| variable "environment" { | |
| description = "The environment to deploy to. This can be used to differentiate between different environments such as dev, test, and prod." | |
| type = string | |
| } | |
| variable "location" { | |
| description = "The Azure region to deploy resources to." | |
| type = string | |
| } | |
| variable "location_short" { | |
| description = "The short name of the Azure region to deploy resources to. This is used for naming resources that have a length limit." | |
| type = string | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment