Tenant deployments with ARM templates
As your organization matures, you may need to define and assign policies or Azure role-based access control (Azure RBAC) across your Microsoft Entra tenant. With tenant level templates, you can declaratively apply policies and assign roles at a global level.
Tip
We recommend Bicep because it offers the same capabilities as ARM templates and the syntax is easier to use. To learn more, see tenant deployments.
Supported resources
Not all resource types can be deployed to the tenant level. This section lists which resource types are supported.
For Azure role-based access control (Azure RBAC), use:
For nested templates that deploy to management groups, subscriptions, or resource groups, use:
For creating management groups, use:
For creating subscriptions, use:
For managing costs, use:
For configuring the portal, use:
Built-in policy definitions are tenant-level resources, but you can't deploy custom policy definitions at the tenant. For an example of assigning a built-in policy definition to a resource, see tenantResourceId example.
Schema
The schema you use for tenant deployments is different than the schema for resource group deployments.
For templates, use:
{
"$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#",
...
}
The schema for a parameter file is the same for all deployment scopes. For parameter files, use:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
...
}
Required access
The principal deploying the template must have permissions to create resources at the tenant scope. The principal must have permission to execute the deployment actions (Microsoft.Resources/deployments/*
) and to create the resources defined in the template. For example, to create a management group, the principal must have Contributor permission at the tenant scope. To create role assignments, the principal must have Owner permission.
The Global Administrator for the Microsoft Entra ID doesn't automatically have permission to assign roles. To enable template deployments at the tenant scope, the Global Administrator must do the following steps:
Elevate account access so the Global Administrator can assign roles. For more information, see Elevate access to manage all Azure subscriptions and management groups.
Assign Owner or Contributor to the principal that needs to deploy the templates.
New-AzRoleAssignment -SignInName "[userId]" -Scope "/" -RoleDefinitionName "Owner"
az role assignment create --assignee "[userId]" --scope "/" --role "Owner"
The principal now has the required permissions to deploy the template.
Deployment commands
The commands for tenant deployments are different than the commands for resource group deployments.
For Azure CLI, use az deployment tenant create:
az deployment tenant create \
--name demoTenantDeployment \
--location WestUS \
--template-uri "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/tenant-deployments/new-mg/azuredeploy.json"
For more detailed information about deployment commands and options for deploying ARM templates, see:
- Deploy resources with ARM templates and Azure portal
- Deploy resources with ARM templates and Azure CLI
- Deploy resources with ARM templates and Azure PowerShell
- Deploy resources with ARM templates and Azure Resource Manager REST API
- Use a deployment button to deploy templates from GitHub repository
- Deploy ARM templates from Cloud Shell
Deployment location and name
For tenant level deployments, you must provide a location for the deployment. The location of the deployment is separate from the location of the resources you deploy. The deployment location specifies where to store deployment data. Subscription and management group deployments also require a location. For resource group deployments, the location of the resource group is used to store the deployment data.
You can provide a name for the deployment, or use the default deployment name. The default name is the name of the template file. For example, deploying a template named azuredeploy.json creates a default deployment name of azuredeploy.
For each deployment name, the location is immutable. You can't create a deployment in one location when there's an existing deployment with the same name in a different location. For example, if you create a tenant deployment with the name deployment1 in centralus, you can't later create another deployment with the name deployment1 but a location of westus. If you get the error code InvalidDeploymentLocation
, either use a different name or the same location as the previous deployment for that name.
Deployment scopes
When deploying to a tenant, you can deploy resources to:
- the tenant
- management groups within the tenant
- subscriptions
- resource groups
The only prohibited scope transitions occur from Resource Group to Management Group, or from Subscription to Management Group.
An extension resource can be scoped to a target that is different than the deployment target.
The user deploying the template must have access to the specified scope.
This section shows how to specify different scopes. You can combine these different scopes in a single template.
Scope to tenant
Resources defined within the resources section of the template are applied to the tenant.
{
"$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
tenant-resources
],
"outputs": {}
}
Scope to management group
To target a management group within the tenant, add a nested deployment and specify the scope
property.
{
"$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"mgName": {
"type": "string"
}
},
"variables": {
"mgId": "[concat('Microsoft.Management/managementGroups/', parameters('mgName'))]"
},
"resources": [
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2022-09-01",
"name": "nestedMG",
"scope": "[variables('mgId')]",
"location": "eastus",
"properties": {
"mode": "Incremental",
"template": {
management-group-resources
}
}
}
],
"outputs": {}
}
Scope to subscription
You can also target subscriptions within the tenant. The user deploying the template must have access to the specified scope.
To target a subscription within the tenant, use a nested deployment and the subscriptionId
property.
{
"$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2021-04-01",
"name": "nestedSub",
"location": "westus2",
"subscriptionId": "00000000-0000-0000-0000-000000000000",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
subscription-resources
}
]
}
}
}
]
}
Scope to resource group
You can also target resource groups within the tenant. The user deploying the template must have access to the specified scope.
To target a resource group within the tenant, use a nested deployment. Set the subscriptionId
and resourceGroup
properties. Don't set a location for the nested deployment because it's deployed in the location of the resource group.
{
"$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2021-04-01",
"name": "nestedRGDeploy",
"subscriptionId": "00000000-0000-0000-0000-000000000000",
"resourceGroup": "demoResourceGroup",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
resource-group-resources
}
]
}
}
}
]
}
Create management group
The following template creates a management group.
{
"$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"mgName": {
"type": "string",
"defaultValue": "[concat('mg-', uniqueString(newGuid()))]"
}
},
"resources": [
{
"type": "Microsoft.Management/managementGroups",
"apiVersion": "2020-02-01",
"name": "[parameters('mgName')]",
"properties": {
}
}
]
}
If your account doesn't have permission to deploy to the tenant, you can still create management groups by deploying to another scope. For more information, see Management group.
Assign role
The following template assigns a role at the tenant scope.
{
"$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.5.6.12127",
"templateHash": "17107802581699825924"
}
},
"parameters": {
"principalId": {
"type": "string",
"metadata": {
"description": "principalId if the user that will be given contributor access to the tenant"
}
},
"roleDefinitionId": {
"type": "string",
"defaultValue": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635",
"metadata": {
"description": "roleDefinition for the assignment - default is owner"
}
}
},
"variables": {
"roleAssignmentName": "[guid('/', parameters('principalId'), parameters('roleDefinitionId'))]"
},
"resources": [
{
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2020-03-01-preview",
"name": "[variables('roleAssignmentName')]",
"properties": {
"roleDefinitionId": "[tenantResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))]",
"principalId": "[parameters('principalId')]"
}
}
]
}
Next steps
- To learn about assigning roles, see Assign Azure roles using Azure Resource Manager templates.
- You can also deploy templates at subscription level or management group level.