Subscription deployments with Bicep files

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.

This article describes how to set the deployment scope to a subscription in a Bicep file.

Note

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

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:

  • artifacts
  • blueprints
  • blueprintAssignments
  • versions

For Azure Policies, use:

  • policyAssignments
  • policyDefinitions
  • policySetDefinitions
  • remediations

For access control, use:

  • accessReviewScheduleDefinitions
  • accessReviewScheduleSettings
  • roleAssignments
  • roleDefinitions
  • roleEligibilityScheduleRequests
  • roleManagementPolicyAssignments

For nested templates that deploy to resource groups, use:

  • deployments

For creating new resource groups, use:

  • resourceGroups

For managing your subscription, use:

  • budgets
  • configurations - Advisor
  • lineOfCredit
  • locks
  • profile - Change Analysis
  • supportPlanTypes
  • tags

For monitoring, use:

  • diagnosticSettings
  • logprofiles

For security, use:

  • advancedThreatProtectionSettings
  • alertsSuppressionRules
  • assessmentMetadata
  • assessments
  • autoProvisioningSettings
  • connectors
  • deviceSecurityGroups
  • ingestionSettings
  • pricings
  • workspaceSettings

Other supported types include:

  • scopeAssignments
  • eventSubscriptions
  • peerAsns

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 chinaeast \
  --template-file main.bicep \
  --parameters rgName=demoResourceGroup rgLocation=chinaeast

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 chinaeast, you can't later create another deployment with the name deployment1 but a location of chinanorth. 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@2022-09-01' = {
  ...
}

For examples of deploying to the subscription, see Create resource groups with Bicep 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 with Bicep.

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@2021-04-01' = {
  scope: tenant()
  name: mgName
  properties: {}
}

output output string = mgName

For more information, see Management group.

Resource groups

For information about creating resource groups, see Create resource group with Bicep.

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@2022-06-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@2021-06-01' = {
  name: 'locationpolicy'
  properties: {
    policyType: 'Custom'
    parameters: {}
    policyRule: {
      if: {
        field: 'location'
        equals: 'chinaeast2'
      }
      then: {
        effect: 'deny'
      }
    }
  }
}

resource locationRestrict 'Microsoft.Authorization/policyAssignments@2022-06-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@2022-09-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@2020-05-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@2022-04-01' = {
  name: roleNameGuid
  properties: {
    roleDefinitionId: roleDefinitionId
    principalId: principalId
  }
}

Next steps

To learn about other scopes, see: