Azure VNet Peering across Azure Active Directory tenants using Service Principal authentication

Arsen Vladimirskiy
Nov 20, 2018 · 3 min read

In this this video, we look at how to create Azure Virtual Network Peering across subscriptions that are in different Azure Active Directory tenants using Service Principal authentication. We look at how to mark Azure AD application in one of the tenants as “multi-tenanted”, how to consent to the multi-tenanted application from the second tenant, and how to establish the VNet peering using Service Principal authentication using Azure PowerShell and Azure Resource Manager REST API calls via Postman.

Video Walkthrough

Tip: Play the video full screen.

Table of Contents

00:00 Beginning of video
01:07 Mark Azure AD app as “multi-tenanted”
04:05 Consent to the multi-tenanted app to create service principal in 2nd tenant
07:09 Assign Contributor permission to the service principal
09:20 Create VNet peering using Azure PowerShell
14:21 Login using Azure CLI to obtain access tokens
17:25 Create VNet peering using Azure Resource Manager API in Postman

Update November 27, 2018: At 14:21 in the video above I mentioned that Azure CLI version 2.0.50 does not work properly with multi-tenanted service principals across tenant. As of November 27, Azure CLI team fixed the bug via Pull Request #7916 and future Azure CLI versions 2.0.52 and later will work properly. I tested just now using Docker image latest dev azure-cli build “docker run — it azuresdk/azure-cli-python:dev.

In the 1st Azure AD tenant, create Azure AD application and set its Settings->Properties for multi-tenanted = Yes.
Record application id (client_id) and key (client_secret).

In the 2nd Azure AD tenant, consent to the multi-tenanted application so that corresponding Service Principal is created in the 2nd tenant.

Consent URL example

https:// login.microsoftonline.com/TENANT2_ID/oauth2/authorize?client_id=CLIENT_ID_OF_MULTI_TENATED_APPLICATION&response_type=code&redirect_uri=http%3A%2F%2Fwww.microsoft.com%2F
$applicationId = "CLIENT_ID"
$key = "CLIENT_SECRET| ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object -TypeName PSCredential -ArgumentList $applicationId, $key
Clear-AzureRmContextConnect-AzureRMAccount -ServicePrincipal -Credential $cred -Tenant "TENANT1_ID"

Get-AzureRmResourceGroup
$vnet1 = Get-AzureRmVirtualNetwork -ResourceGroupName "vnetpeer1" -Name "vnetpeer1"
Add-AzureRmVirtualNetworkPeering `
-Name 'peer1-peer2' `
-VirtualNetwork $vnet1 `
-RemoteVirtualNetworkId "/subscriptions/SUBSCRIPTION2_ID/resourceGroups/vnetpeer2/providers/Microsoft.Network/virtualNetworks/vnetpeer2" ` -Debug
Connect-AzureRMAccount -ServicePrincipal -Credential $cred -Tenant "TENANT2_ID"
Get-AzureRmResourceGroup
$vnet2 = Get-AzureRmVirtualNetwork -ResourceGroupName "vnetpeer2" -Name "vnetpeer2"
Add-AzureRmVirtualNetworkPeering ` -Name 'peer2-peer1' ` -VirtualNetwork $vnet2 ` -RemoteVirtualNetworkId "/subscriptions/SUBSCRIPTION1_ID/resourceGroups/vnetpeer1/providers/Microsoft.Network/virtualNetworks/vnetpeer1"
## Azure CLI login using service principal authentication
az account clear
az login --service-principal -u "CLIENT_ID" -p "CLIENT_SECRET" --tenant "TENANT1_ID"
az account get-access-token

az login --service-principal -u "CLIENT_ID" -p "CLIENT_SECRET" --tenant "TENANT2_ID"
az account get-access-token
## The following did not work properly in Azure CLI version 2.0.50 when using multi-tenanted application service principal
## However, as of 2018-11-27, the issue is fixed in Azure CLI versions 2.0.52 and later via this pull request https://github.com/Azure/azure-cli/pull/7916
az network vnet peering create --name vnet1-vnet2 --resource-group vnetpeer1 --vnet-name vnetpeer1 --remote-vnet "/subscriptions/SUBSCRIPTION2_ID/resourceGroups/vnetpeer2/providers/Microsoft.Network/virtualNetworks/vnetpeer2" --allow-vnet-access
az network vnet peering create --name vnet2-vnet1 --resource-group vnetpeer2 --vnet-name vnetpeer2 --remote-vnet "/subscriptions/SUBSCRIPTION1_ID/resourceGroups/vnetpeer1/providers/Microsoft.Network/virtualNetworks/vnetpeer1" --allow-vnet-access
# Create VNet Peering in Subscription 1
curl -X PUT \
'https://management.azure.com/subscriptions/SUBSCRIPTION1_ID/resourceGroups/vnetpeer1/providers/Microsoft.Network/virtualNetworks/vnetpeer1/virtualNetworkPeerings/peer1-peer2?api-version=2018-02-01' \
-H 'Authorization: Bearer TENANT1_TOKEN' \
-H 'Content-Type: application/json' \
-H 'cache-control: no-cache' \
-H 'x-ms-authorization-auxiliary: Bearer TENANT2_TOKEN' \
-d '{ "properties": { "allowVirtualNetworkAccess": true, "allowForwardedTraffic": false, "allowGatewayTransit": false, "useRemoteGateways": false, "remoteVirtualNetwork": { "id": "/subscriptions/SUBSCRIPTION2_ID/resourceGroups/vnetpeer2/providers/Microsoft.Network/virtualNetworks/vnetpeer2" } } }'
# Create VNet Peering in Subscription 2curl -X PUT \
'https://management.azure.com/subscriptions/SUBSCRIPTION2_ID/resourceGroups/vnetpeer2/providers/Microsoft.Network/virtualNetworks/vnetpeer2/virtualNetworkPeerings/peer2-peer1?api-version=2018-02-01' \
-H 'Authorization: Bearer TENANT2_TOKEN' \
-H 'Content-Type: application/json' \
-H 'cache-control: no-cache' \
-H 'x-ms-authorization-auxiliary: Bearer TENANT1_TOKEN' \
-d '{ "properties": { "allowVirtualNetworkAccess": true, "allowForwardedTraffic": false, "allowGatewayTransit": false, "useRemoteGateways": false, "remoteVirtualNetwork": { "id": "/subscriptions/SUBSCRIPTION1_ID/resourceGroups/vnetpeer1/providers/Microsoft.Network/virtualNetworks/vnetpeer1" } } }'

Thank you!

Please leave feedback and questions below or on Twitter https://twitter.com/ArsenVlad


Originally published at blogs.msdn.microsoft.com on November 20, 2018.

Arsen Vladimirskiy

Written by

Azure Cloud Architect & Software Engineer at Microsoft, Commercial Software Engineering (CSE) Team