Understanding Bicep Scopes in Azure

When working with Azure Bicep, understanding the concept of scopes is crucial for effective resource management and deployment. Scopes in Bicep define the boundary or level at which your resources will be deployed. Bicep supports multiple levels of scope, including Management Group, Subscription, Resource Group, and Tenant levels. In this post, we'll delve into the different scopes, how to define them in your Bicep files, and some practical examples to illustrate their usage.

Tenant Level

The Tenant level scope is used for resources that need to be deployed across the entire Azure Active Directory tenant. This scope is less commonly used but is essential for certain scenarios, such as deploying Management Groups or role definitions that apply across the tenant.

// Use targetScope to tell Bicep that the resources are for a specific scope
targetScope = 'tenant'

// Define the resource which should be deployed on tenant level
resource managementGroup 'Microsoft.Management/managementGroups@2023-04-01' = {
  name: 'operations'
  properties: {
    displayName: 'Operations'
  }
}

// Define another resource which should be deployed on tenant level
resource managementGroup2 'Microsoft.Management/managementGroups@2023-04-01' = {
  name: 'production'
  properties: {
    displayName: 'Production'
    details: {
      parent: {
        id: managementGroup.id
      }
    }
  }
}

Management Group Level

⚠️
Be extremely careful when you grant access to resources by using management groups, and especially the root management group. Remember that every resource under the management group in the hierarchy inherits the role assignment. Make sure that your organization follows best practices for identity management and authentication, and that it follows the principle of least privilege; that is, don't grant any access that isn't required. (Microsoft.com, 2024)

Management Groups in Azure provide a way to manage access, policies, and compliance across multiple Azure subscriptions. Deploying resources at this level can be beneficial for scenarios that require a consistent configuration across several subscriptions.

// Use targetScope to tell Bicep that the resources are for a specific scope
targetScope = 'managementGroup'

resource policyDefinition 'Microsoft.Authorization/policyDefinitions@2023-04-01' = {
  name: 'policyDefinition'
  // Params ...
}

Subscription Level

Deploying resources at the subscription level is common for scenarios where resources need to be shared across multiple resource groups within a subscription. This is typically used for setting up shared infrastructure, such as virtual networks or resource groups themselves.

// Use targetScope to tell Bicep that the resources are for a specific scope
targetScope = 'subscription'

resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = {
  name: 'rg-proj-dev-001'
  location: 'switzerlandnorth'
}

In this example, we are creating a resource group within a specific subscription. This resource group can then be used to house various other resources.

Multi-Scope

Bicep also supports multi-scope deployments, where you can deploy resources across different scopes within a single Bicep file. This is particularly useful for modular deployments, where different modules need to be deployed at different scopes.

// Use targetScope to tell Bicep that the resources are for a specific scope
targetScope = 'subscription'

module sa 'br:latzo.azurecr.io/bicep/modules/storage/private-blob:1.0.0' = {
  name: 'storage-deployment'
  // Use the scope inside the resource to tell bicep that this resource has a different targetScope - This mostly only works with modules
  scope: resourceGroup('rg-proj-dev-001')
  params: {
    accessTier: 'Hot'
    storageAccountName: 'saprojdev001'
    containerName: 'images'
    storageKind: 'StorageV2'
  }
}

// To deploy a resource into another subscription, add it to the scope as a second argument.
module sa2 'br:latzo.azurecr.io/bicep/modules/storage/private-blob:1.0.0' = {
  name: 'storage-deployment2'
  // Include the target subscription ID and the resource group
  scope: resourceGroup('f0750bbe-ea75-4ae5-b24d-a92ca601da2c', 'rg-storage-dev-002')
  params: {
    accessTier: 'Hot'
    storageAccountName: 'saprojdev002'
    containerName: 'images'
    storageKind: 'StorageV2'
  }
}

In these examples, we are deploying a storage account module to two different resource groups. The first module deploys to a resource group within the current subscription, while the second module deploys to a resource group in another subscription. This demonstrates how Bicep can handle complex deployments across multiple scopes seamlessly.

Understanding and utilizing scopes in Bicep is key to managing your Azure resources efficiently. Whether you're working at the management group, subscription, or resource group level, Bicep provides the flexibility to define and manage resources appropriately. Multi-scope deployments further extend this flexibility, allowing for modular and scalable infrastructure as code practices.

Feel free to experiment with these examples and adapt them to your specific needs. Happy coding!