Search code examples
azureazure-resource-managerazure-virtual-networkazure-bicep

Issue with bicep template for subnet


I have an existing vnet and route table in RG1. All other resources are going in RG2.

I am creating a subnet bicep which will be called as a module and it has to be associated with vnet and route table.

subnet bicep

//parameters
//variables

resource vnetRef 'Microsoft.Network/virtualNetworks@2023-09-01' = {
  name: vnetId
}

resource subnet 'Microsoft.Network/virtualNetworks/subnets@2023-09-01' = {
  name: subnetName
  parent: vnetRef
  properties: {
    addressPrefix: subnetPrefix
    routeTable: {
      id: routeTableId
    }          
  }
}

output subnetId string = subnet.id

main bicep

resource vnet 'Microsoft.Network/virtualNetworks@2023-09-01' existing = {
  name: '${appAcronym}-${subscriptionName}-vnet'
  scope: resourceGroup(sharedScopeRG)
}

resource routeTable 'Microsoft.Network/routeTables@2023-09-01' existing = {
  name: routeTableName
  scope: resourceGroup(sharedScopeRG)
}

module subnetModule '../AnotherRepo/subnet.bicep' = {
  name: 'subnetModule'
  scope: resourceGroup(rgName)
  params: {
    name: subnetName
    subnetPrefix: subnetAddressSpace
    vnetId: vnet.id
    routeTableId: routeTable.id
    //other params for subnet bicep
  }
}

It fails with The template resource '/subscriptions/subid/resourceGroups/RG1/providers/Microsoft.Network/virtualNetworks/myVnet' for type 'Microsoft.Network/virtualNetworks' at line '1' and column '1739' has incorrect segment lengths. A nested resource type must have identical number of segments as its resource name. A root resource type must have segment length one greater than its resource name. Please see https://aka.ms/arm-syntax-resources for usage details.'.

I then passed vnet.name instead of vnet.id when calling subnet bicep and then get the following error: Resource 'myVnet' was disallowed by policy. Error Type: PolicyViolation, Policy Definition Name : Allowed locations, Policy Assignment Name : .

Which means it is trying to create vnet when the subnet module is being called. I have tried multiple ways of referring them but none are working out.


Solution

  • First thing, you should deploy the subnets inside the vnet resource. Otherwise if you rerun the vnet module, the existing subnets not defined in the vnet module will be destroy (see related post).

    in your subnet module, you need to use the existing keyword to reference the existing vnet:

    // subnet.bicep
    param vnetName string
    param subnetName string
    param subnetPrefix string
    param routeTableId string
    
    resource vnetRef 'Microsoft.Network/virtualNetworks@2023-09-01' existing = {
      name: vnetName
    }
    
    resource subnet 'Microsoft.Network/virtualNetworks/subnets@2023-09-01' = {
      parent: vnetRef
      name: subnetName  
      properties: {
        addressPrefix: subnetPrefix
        routeTable: {
          id: routeTableId
        }   
      }
    }
    
    output subnetId string = subnet.id
    

    When invoking the subnet module from your main file, the scope of the module has to be the scope of the vnet resource group:

    param appAcronym string
    param subscriptionName string
    param sharedScopeRG string
    param routeTableName string
    param subnetName string
    param subnetAddressSpace string
    
    resource vnet 'Microsoft.Network/virtualNetworks@2023-09-01' existing = {
      name: '${appAcronym}-${subscriptionName}-vnet'
      scope: resourceGroup(sharedScopeRG)
    }
    
    resource routeTable 'Microsoft.Network/routeTables@2023-09-01' existing = {
      name: routeTableName
      scope: resourceGroup(sharedScopeRG)
    }
    
    module subnetModule 'subnet.bicep' = {
      name: 'subnetModule'
      scope: resourceGroup(sharedScopeRG) // scope should be the scope of the vnet resource group
      params: {
        subnetName: subnetName
        vnetName: vnet.name
        subnetPrefix: subnetAddressSpace
        routeTableId: routeTable.id
      }
    }