Create resources at the management group level

As your organization matures, you may need to define and assign policies or role-based access controls for a management group. With management group level templates, you can declaratively apply policies and assign roles at the management group level.

Supported resources

You can deploy the following resource types at the management group level:

Schema

The schema you use for management group deployments is different than the schema for resource group deployments.

For templates, use:

https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#

The schema for a parameter file is the same for all deployment scopes. For parameter files, use:

https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#

Deployment commands

The commands for management group deployments are different than the commands for resource group deployments.

For Azure CLI, use az deployment mg create:

az deployment mg create \
  --name demoMGDeployment \
  --location WestUS \
  --management-group-id myMG \
  --template-uri "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/management-level-deployment/azuredeploy.json"

For Azure PowerShell, use New-AzManagementGroupDeployment.

New-AzManagementGroupDeployment `
  -Name demoMGDeployment `
  -Location "West US" `
  -ManagementGroupId "myMG" `
  -TemplateUri "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/management-level-deployment/azuredeploy.json"

For REST API, use Deployments - Create At Management Group Scope.

Deployment location and name

For management group 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.

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. If you get the error code InvalidDeploymentLocation, either use a different name or the same location as the previous deployment for that name.

Use template functions

For management group deployments, there are some important considerations when using template functions:

  • The resourceGroup() function is not supported.

  • The subscription() function is not supported.

  • The reference() and list() functions are supported.

  • The resourceId() function is supported. Use it to get the resource ID for resources that are used at management group level deployments. Don't provide a value for the resource group parameter.

    For example, to get the resource ID for a policy definition, use:

    resourceId('Microsoft.Authorization/policyDefinitions/', parameters('policyDefinition'))
    

    The returned resource ID has the following format:

    /providers/{resourceProviderNamespace}/{resourceType}/{resourceName}
    

Create policies

Define policy

The following example shows how to define a policy at the management group level.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Authorization/policyDefinitions",
      "apiVersion": "2018-05-01",
      "name": "locationpolicy",
      "properties": {
        "policyType": "Custom",
        "parameters": {},
        "policyRule": {
          "if": {
            "field": "location",
            "equals": "northeurope"
          },
          "then": {
            "effect": "deny"
          }
        }
      }
    }
  ]
}

Assign policy

The following example assigns an existing policy definition to the management group. If the policy takes parameters, provide them as an object. If the policy doesn't take parameters, use the default empty object.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "policyDefinitionID": {
      "type": "string"
    },
    "policyName": {
      "type": "string"
    },
    "policyParameters": {
      "type": "object",
      "defaultValue": {}
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Authorization/policyAssignments",
      "apiVersion": "2018-03-01",
      "name": "[parameters('policyName')]",
      "properties": {
        "policyDefinitionId": "[parameters('policyDefinitionID')]",
        "parameters": "[parameters('policyParameters')]"
      }
    }
  ]
}

Template sample

Next steps