Exercise - Deploy resources to multiple scopes by using modules

Completed

Note

This exercise requires an Azure subscription. If you don't already have one, you can get a free subscription.

The R&D team has asked for your help to create a virtual network in the Project Teddybear subscription. You know you'll be helping the team with more subscriptions in the future, so you decide to extend your reusable Bicep template to deploy a virtual network for the team members to use.

In this exercise, you'll update the template that you started to build in the last exercise.

During the process, you'll:

  • Update the subscription-scoped template to create a new resource group.
  • Create a separate Bicep module with a virtual network, and use parameters to control how the virtual network is configured.
  • Update the template to deploy the module to the resource group.
  • Deploy the template.

This exercise requires that you have permission to deploy subscription-scoped resources. If you can't meet this requirement with your current Azure account, you can get a free trial and create a new Azure subscription and tenant. Alternatively, you can skip the deployment steps in this exercise.

Create a resource group

  1. In Visual Studio Code, open the main.bicep file that you created in the earlier exercise.

  2. Under the current variable definitions, add the following variable definition:

    var resourceGroupName = 'ToyNetworking'
    
  3. At the bottom of the file, add the following resource definition:

    resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-07-01' = {
      name: resourceGroupName
      location: deployment().location
    }
    

    Notice that you're defining the resource group just as you would define another resource. A resource group is a subscription-scoped resource that can be deployed and managed in Bicep files with the targetScope set to subscription.

  4. Save the changes to the file.

Add a module to create a virtual network

Next, you'll create a Bicep module for the R&D team's virtual network. You'll deploy the resources in the module to the resource group later in this exercise.

  1. In Visual Studio Code, create a new folder called modules in the same folder where you created your main.bicep file.

  2. In the modules folder, create and save a file called virtualNetwork.bicep.

  3. In the virtualNetwork.bicep file, add the following content:

    param virtualNetworkName string
    param virtualNetworkAddressPrefix string
    
    resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-01-01' = {
      name: virtualNetworkName
      location: resourceGroup().location
      properties: {
        addressSpace: {
          addressPrefixes: [
            virtualNetworkAddressPrefix
          ]
        }
      }
    }
    

    Notice that you haven't specified a targetScope for this module. You don't need to specify a target scope when the Bicep file is targeting a resource group.

  4. Save the changes to the file.

Use the module in the subscription deployment

Now you're ready to tell Bicep to deploy the module to the resource group.

  1. In the main.bicep file in Visual Studio Code, under the targetScope line, add the following parameter definitions:

    param virtualNetworkName string
    param virtualNetworkAddressPrefix string
    

    These parameters make the template reusable. Anytime the R&D team needs a new subscription, you can create a virtual network with a unique name and IP address range.

  2. At the bottom of the file, add the following module definition:

    module virtualNetwork 'modules/virtualNetwork.bicep' = {
      scope: resourceGroup
      name: 'virtualNetwork'
      params: {
        virtualNetworkName: virtualNetworkName
        virtualNetworkAddressPrefix: virtualNetworkAddressPrefix
      }
    }
    

    Notice that you're explicitly specifying the scope for the module. Bicep understands that the resources within the module should be deployed to the resource group that you created earlier in the file.

Verify your template

Your main.bicep file should look like the following:

targetScope = 'subscription'

param virtualNetworkName string
param virtualNetworkAddressPrefix string

var policyDefinitionName = 'DenyFandGSeriesVMs'
var policyAssignmentName = 'DenyFandGSeriesVMs'
var resourceGroupName = 'ToyNetworking'

resource policyDefinition 'Microsoft.Authorization/policyDefinitions@2024-05-01' = {
  name: policyDefinitionName
  properties: {
    policyType: 'Custom'
    mode: 'All'
    parameters: {}
    policyRule: {
      if: {
        allOf: [
          {
            field: 'type'
            equals: 'Microsoft.Compute/virtualMachines'
          }
          {
            anyOf: [
              {
                field: 'Microsoft.Compute/virtualMachines/sku.name'
                like: 'Standard_F*'
              }
              {
                field: 'Microsoft.Compute/virtualMachines/sku.name'
                like: 'Standard_G*'
              }
            ]
          }
        ]
      }
      then: {
        effect: 'deny'
      }
    }
  }
}

resource policyAssignment 'Microsoft.Authorization/policyAssignments@2024-05-01' = {
  name: policyAssignmentName
  properties: {
    policyDefinitionId: policyDefinition.id
  }
}

resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-07-01' = {
  name: resourceGroupName
  location: deployment().location
}

module virtualNetwork 'modules/virtualNetwork.bicep' = {
  scope: resourceGroup
  name: 'virtualNetwork'
  params: {
    virtualNetworkName: virtualNetworkName
    virtualNetworkAddressPrefix: virtualNetworkAddressPrefix
  }
}

Your modules/virtualNetwork.bicep file should look like the following:

param virtualNetworkName string
param virtualNetworkAddressPrefix string

resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-01-01' = {
  name: virtualNetworkName
  location: resourceGroup().location
  properties: {
    addressSpace: {
      addressPrefixes: [
        virtualNetworkAddressPrefix
      ]
    }
  }
}

If either file doesn't match the example, either copy the example or adjust your template.

Deploy the template to Azure

In the Visual Studio Code terminal, deploy the template by using the following Azure CLI commands:

templateFile="main.bicep"
today=$(date +"%d-%b-%Y")
deploymentName="sub-scope-"$today
virtualNetworkName="rnd-vnet-001"
virtualNetworkAddressPrefix="10.0.0.0/24"

az deployment sub create \
    --name $deploymentName \
    --location westus \
    --template-file $templateFile \
    --parameters virtualNetworkName=$virtualNetworkName \
                 virtualNetworkAddressPrefix=$virtualNetworkAddressPrefix

In the Visual Studio Code terminal, deploy the template by using the following Azure PowerShell commands:

$templateFile = 'main.bicep'
$today = Get-Date -Format 'MM-dd-yyyy'
$deploymentName = "sub-scope-$today"
$virtualNetworkName = 'rnd-vnet-001'
$virtualNetworkAddressPrefix = '10.0.0.0/24'

New-AzSubscriptionDeployment `
  -Name $deploymentName `
  -Location westus `
  -TemplateFile $templateFile `
  -virtualNetworkName $virtualNetworkName `
  -virtualNetworkAddressPrefix $virtualNetworkAddressPrefix

Notice that you're passing in values for the virtualNetworkName and virtualNetworkAddressPrefix parameters. When another R&D team asks you to prepare a subscription for them, you'll be able to change these values to give that team its own virtual network.

The deployment might take a minute or two to finish, and then you'll see a successful deployment.

Verify the deployment

Now you'll check the resource group and the deployment that the module created.

  1. Go to the Azure portal.

  2. On the left pane, select Resource groups. Notice that the ToyNetworking resource group has been created.

  3. Select the ToyNetworking resource group. Notice that the module has been deployed to the resource group successfully, and that the virtual network has been created:

    Screenshot of the Azure portal, showing the ToyNetworking resource group.

Clean up the resources

You've successfully deployed the subscription-scoped resources, including a resource group, and you've used a module to deploy the resource to the resource group you created. You can remove the policy resources and resource group that you've created.

Caution

This command will permanently delete the resource group named ToyNetworking and all its resources. If you've deployed anything else to this resource group, you should skip this step.

subscriptionId=$(az account show --query 'id' --output tsv)

az policy assignment delete --name 'DenyFandGSeriesVMs' --scope "/subscriptions/$subscriptionId"
az policy definition delete --name 'DenyFandGSeriesVMs' --subscription $subscriptionId
az group delete --name ToyNetworking
$subscriptionId = (Get-AzContext).Subscription.Id

Remove-AzPolicyAssignment -Name 'DenyFandGSeriesVMs' -Scope "/subscriptions/$subscriptionId"
Remove-AzPolicyDefinition -Name 'DenyFandGSeriesVMs' -SubscriptionId $subscriptionId
Remove-AzResourceGroup -Name ToyNetworking