Coder Perfect

How can I use Azure Bicep to modify an existing resource?

Problem

I’m actively transferring some Azure CLI infrastructure to Azure Bicep as code scripts. The Bicep files should, among other things, construct a subnet and grant access to an existing Azure SQL Server and Storage Account from this subnet.

This is straightforward with SQL Server; I simply reference the existing server resource and declare a child resource to represent the VNET rule:

resource azureSqlServer 'Microsoft.Sql/servers@2021-05-01-preview' existing = {
  name: azureSqlServerName

  resource vnetRule 'virtualNetworkRules' = {
    name: azureSqlServerVnetRuleName
    properties: {
      virtualNetworkSubnetId: subnetId
    }
  }
}

The network rules, on the other hand, are a property of the Storage Account resource, not a child resource (properties.networkAcls.virtualNetworkRules). Because that resource is totally out of scope for the deployment I’m presently working on, I can’t specify all of the information of the Storage Account in my Bicep file. In essence, I’d like to modify the existing resource by adding a single rule.

Because existing cannot be mixed with properties, the following does not work:

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' existing = {
  name: storageAccountName

  properties: {
    networkAcls: {
      virtualNetworkRules: [
        {
          id: subnetId
          action: 'Allow'
        }
      ]
    }
  }
}

Is there any way I can use Bicep to alter a small portion of an existing resource?

Asked by Fabian Schmied

Solution #1

The existing keyword in bicep is used to tell bicep that the resource already exists and that all you want in the code is a symbolic reference to it. If the resource does not exist, the deployment is likely to fail in some way.

The following is the equivalent of your first snippet:

resource vnetRule 'Microsoft.Sql/servers/virtualNetworkRules@2021-05-01-preview' = {
  name: '${azureSqlServerName}/${azureSqlServerVnetRuleName}'
  properties: {
    virtualNetworkSubnetId: subnetId
  }
}

Because you want to update properties in your second excerpt, you must give the resource’s complete declaration, that is, you must define and deploy the storageAccount. This isn’t specific to bicep; it’s how Azure’s declarative model works.

In bicep, however, you may use a module with the scope attribute to deploy to a different scope. E.g.

module updateStorage 'storage.bicep' = {
  scope: resourceGroup(storageResourceGroupName)
  name: 'updateStorage'
}

The disadvantage is that you must define/declare all of the characteristics required for that storageAccount, which is inconvenient. There are a few ways to get past this, however if the storageAccount does not exist, the deployment will fail. For example, you could verify that the storageAccount exists, retrieve its properties, and then union or modify the module’s properties. You might be able to make it work (depending on the amount of your changes), but in a declarative model, it’s a bit of an anti-pattern.

That help?

Answered by bmoore-msft

Post is based on https://stackoverflow.com/questions/70924899/how-can-i-adapt-an-existing-resource-with-azure-bicep