Subscription deployments with Bicep files

This article describes how to set scope with Bicep when deploying to a subscription.

To simplify the management of resources, you can deploy resources at the level of your Azure subscription. For example, you can deploy policies and Azure role-based access control (Azure RBAC) to your subscription, which applies them across your subscription. You can also create resource groups within the subscription and deploy resources to resource groups in the subscription.

Note

You can deploy to 800 different resource groups in a subscription level deployment.

Microsoft Learn

To learn more about deployment scopes, and for hands-on guidance, see Deploy resources to subscriptions, management groups, and tenants by using Bicep on Microsoft Learn.

Supported resources

Not all resource types can be deployed to the subscription level. This section lists which resource types are supported.

For Azure Blueprints, use:

For Azure Policies, use:

For Azure role-based access control (Azure RBAC), use:

For nested templates that deploy to resource groups, use:

For creating new resource groups, use:

For managing your subscription, use:

Other supported types include:

Set scope

To set the scope to subscription, use:

targetScope = 'subscription'

Deployment commands

To deploy to a subscription, use the subscription-level deployment commands.

For Azure CLI, use az deployment sub create. The following example deploys a template to create a resource group:

az deployment sub create \
  --name demoSubDeployment \
  --location centralus \
  --template-file main.bicep \
  --parameters rgName=demoResourceGroup rgLocation=centralus

For more detailed information about deployment commands and options for deploying ARM templates, see:

Deployment location and name

For subscription 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. Management group and tenant 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 main.json creates a default deployment name of main.

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 subscription 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 subscription, you can deploy resources to:

  • the target subscription from the operation
  • any subscription in the tenant
  • resource groups within the subscription or other subscriptions
  • the tenant for the subscription

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.

Scope to subscription

To deploy resources to the target subscription, add those resources with the resource keyword.

targetScope = 'subscription'

// resource group created in target subscription
resource exampleResource 'Microsoft.Resources/resourceGroups@2020-10-01' = {
  ...
}

For examples of deploying to the subscription, see Create resource groups and Assign policy definition.

To deploy resources to a subscription that is different than the subscription from the operation, add a module. Use the subscription function to set the scope property. Provide the subscriptionId property to the ID of the subscription you want to deploy to.

targetScope = 'subscription'

param otherSubscriptionID string

// module deployed at subscription level but in a different subscription
module exampleModule 'module.bicep' = {
  name: 'deployToDifferentSub'
  scope: subscription(otherSubscriptionID)
}

Scope to resource group

To deploy resources to a resource group within the subscription, add a module and set its scope property. If the resource group already exists, use the resourceGroup function to set the scope value. Provide the resource group name.

targetScope = 'subscription'

param resourceGroupName string

module exampleModule 'module.bicep' = {
  name: 'exampleModule'
  scope: resourceGroup(resourceGroupName)
}

If the resource group is created in the same Bicep file, use the symbolic name of the resource group to set the scope value. For an example of setting the scope to the symbolic name, see Create resource group and resources.

Scope to tenant

To create resources at the tenant, add a module. Use the tenant function to set its scope property.

The user deploying the template must have the required access to deploy at the tenant.

The following example includes a module that is deployed to the tenant.

targetScope = 'subscription'

// module deployed at tenant level
module exampleModule 'module.bicep' = {
  name: 'deployToTenant'
  scope: tenant()
}

Instead of using a module, you can set the scope to tenant() for some resource types. The following example deploys a management group at the tenant.

targetScope = 'subscription'

param mgName string = 'mg-${uniqueString(newGuid())}'

// management group created at tenant
resource managementGroup 'Microsoft.Management/managementGroups@2020-05-01' = {
  scope: tenant()
  name: mgName
  properties: {}
}

output output string = mgName

For more information, see Management group.

Resource groups

Create resource groups

To create a resource group, define a Microsoft.Resources/resourceGroups resource with a name and location for the resource group.

The following example creates an empty resource group.

targetScope='subscription'

param resourceGroupName string
param resourceGroupLocation string

resource newRG 'Microsoft.Resources/resourceGroups@2021-01-01' = {
  name: resourceGroupName
  location: resourceGroupLocation
}

Create resource group and resources

To create the resource group and deploy resources to it, add a module. The module includes the resources to deploy to the resource group. Set the scope for the module to the symbolic name for the resource group you create. You can deploy to up to 800 resource groups.

The following example creates a resource group, and deploys a storage account to the resource group. Notice that the scope property for the module is set to newRG, which is the symbolic name for the resource group that is being created.

targetScope='subscription'

param resourceGroupName string
param resourceGroupLocation string
param storageName string
param storageLocation string

resource newRG 'Microsoft.Resources/resourceGroups@2021-01-01' = {
  name: resourceGroupName
  location: resourceGroupLocation
}

module storageAcct 'storage.bicep' = {
  name: 'storageModule'
  scope: newRG
  params: {
    storageLocation: storageLocation
    storageName: storageName
  }
}

The module uses a Bicep file named storage.bicep with the following contents:

param storageLocation string
param storageName string

resource storageAcct 'Microsoft.Storage/storageAccounts@2019-06-01' = {
  name: storageName
  location: storageLocation
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'Storage'
  properties: {}
}

Azure Policy

Assign policy definition

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

targetScope = 'subscription'

param policyDefinitionID string
param policyName string
param policyParameters object = {}

resource policyAssign 'Microsoft.Authorization/policyAssignments@2020-09-01' = {
  name: policyName
  properties: {
    policyDefinitionId: policyDefinitionID
    parameters: policyParameters
  }
}

Create and assign policy definitions

You can define and assign a policy definition in the same Bicep file.

targetScope = 'subscription'

resource locationPolicy 'Microsoft.Authorization/policyDefinitions@2020-09-01' = {
  name: 'locationpolicy'
  properties: {
    policyType: 'Custom'
    parameters: {}
    policyRule: {
      if: {
        field: 'location'
        equals: 'northeurope'
      }
      then: {
        effect: 'deny'
      }
    }
  }
}

resource locationRestrict 'Microsoft.Authorization/policyAssignments@2020-09-01' = {
  name: 'allowedLocation'
  properties: {
    policyDefinitionId: locationPolicy.id
  }
}

Access control

To learn about assigning roles, see Add Azure role assignments using Azure Resource Manager templates.

The following example creates a resource group, applies a lock to it, and assigns a role to a principal.

targetScope = 'subscription'

@description('Name of the resourceGroup to create')
param resourceGroupName string

@description('Location for the resourceGroup')
param resourceGroupLocation string

@description('principalId of the user that will be given contributor access to the resourceGroup')
param principalId string

@description('roleDefinition to apply to the resourceGroup - default is contributor')
param roleDefinitionId string = 'b24988ac-6180-42a0-ab88-20f7382dd24c'

@description('Unique name for the roleAssignment in the format of a guid')
param roleAssignmentName string = guid(principalId, roleDefinitionId, resourceGroupName)

var roleID = '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/${roleDefinitionId}'

resource newResourceGroup 'Microsoft.Resources/resourceGroups@2019-10-01' = {
  name: resourceGroupName
  location: resourceGroupLocation
  properties: {}
}

module applyLock 'lock.bicep' = {
  name: 'applyLock'
  scope: newResourceGroup
}

module assignRole 'role.bicep' = {
  name: 'assignRBACRole'
  scope: newResourceGroup
  params: {
    principalId: principalId
    roleNameGuid: roleAssignmentName
    roleDefinitionId: roleID
  }
}

The following example shows the module to apply the lock:

resource createRgLock 'Microsoft.Authorization/locks@2016-09-01' = {
  name: 'rgLock'
  properties: {
    level: 'CanNotDelete'
    notes: 'Resource group should not be deleted.'
  }
}

The next example shows the module to assign the role:

@description('The principal to assign the role to')
param principalId string

@description('A GUID used to identify the role assignment')
param roleNameGuid string = newGuid()

param roleDefinitionId string

resource roleNameGuid_resource 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
  name: roleNameGuid
  properties: {
    roleDefinitionId: roleDefinitionId
    principalId: principalId
  }
}

Next steps

To learn about other scopes, see: