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

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.

Mark Azure AD Application as Multi-Tenanted

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).

Create Service Principal from Application

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


Azure PowerShell Example

$applicationId = "CLIENT_ID"
$key = "CLIENT_SECRET| ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object -TypeName PSCredential -ArgumentList $applicationId, $key


Connect-AzureRMAccount -ServicePrincipal -Credential $cred -Tenant "TENANT1_ID"

$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 Example

## 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
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 \
'' \
-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 2

curl -X PUT \
'' \
-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

Comments (4)

  1. Pixelicous says:

    This doesn’t work, i get:
    AADSTS65005: Misconfigured application. This could be due to one of the following: The client has not listed any permissions for ‘AAD Graph’ in the requested permissions in the client’s application registration. Or, The admin has not consented in the tenant. Or, Check the application identifier in the request to ensure it matches the configured client application identifier. Please contact your admin to fix the configuration or consent on behalf of the tenant. Client app ID: 66d9febb-25ad-4b84-ae1c-78f8b5962161.

    What are the permissions that you should assign on graph?? If i assign all permissions this will go through but i want to assign direct ones..

    You also didn’t explain the app id uri throughly!

    1. Thanks for your comment. Indeed I forgot to show the specific “Required permissions” that I assigned to the avmyapp1 in the video (since that app was created a while back not during the time I was recording the walkthrough). I have the following permissions assigned to the app and granted to all: Windows Azure Active Directory / Delegated Permissions / “Sign in and read user profile”. Can you please try the same and see if it works. For the app id URI of the multi-tenanted app it needs to contain domain of one of the “verified domains within your organization directory” (i.e. you cannot use localhost, it has to be something like

      1. jontreynes says:

        localhost actually worked fine for me @Arsen

  2. jontreynes says:

    This step is missing a quote

    $key = “CLIENT_SECRET| ConvertTo-SecureString -AsPlainText -Force

    It should be

    $key = “CLIENT_SECRET” | ConvertTo-SecureString -AsPlainText -Force

Skip to main content