5

I'm currently porting some infrastructure as code scripts from Azure CLI to Azure Bicep. Among many other things, the Bicep files should create a subnet and allow access from this subnet to an existing Azure SQL Server and an existing Storage Account.

For the SQL Server, this is simple - I can reference the existing server resource and declare a child resource representing the VNET rule:

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

However, with the Storage Account, the network rules are not child resources, but a property of the Storage Account resource (properties.networkAcls.virtualNetworkRules). I cannot declare all the details of the Storage Account in my Bicep file because that resource is way out of scope from the deployment I'm currently working on. In essence, I want to adapt the existing resource, just ensuring a single rule is present.

The following does not work because existing cannot be combined with properties:

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

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

Is there any way I can adapt just a tiny bit of an existing resource using Bicep?

Fabian Schmied
  • 3,885
  • 3
  • 30
  • 49

2 Answers2

4

UPDATE: I just realized you came from Azure CLI and was trying to find a way in bicep - sorry for not answering your actual question - anyway your post made me think about this in another way other than bicep, so my "answer" is what I came up with...

...sounds like we thought about this in the same manner; using bicep to pimp an existing Storage Account, granting a new subnet access. However I ended up using AzureCLI az storage account network-rule add

e.g.

newSubnet='/subscriptions/<subscr-guid>/resourceGroups/<rg-name-where-vnet-resides>/providers/Microsoft.Network/virtualNetworks/<vnet-name>/subnets/<subnet-name>'

az storage account network-rule add -g <rg-name-where-sa-resides> --account-name <storage-account-name> --subnet $newSubnet

run this from a terminal or put it in an AzureCLI task in a devops pipeline (which is what I needed)

Caad9Rider
  • 654
  • 1
  • 8
  • 16
2

The existing keyword in bicep is used to tell bicep that the resource already exists and you just want a symbolic reference to that resource in the code. If the resource doesn't exist it's likely that the the deployment will fail in some way.

Your first snippet is equivalent to:

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

In your second snippet since you want to update properties you have to provide the complete declaration of the resource, IOW you have to define and deploy the storageAccount. This isn't unique to bicep, it's the way the declarative model in Azure works.

That said, if you want to deploy to another scope in bicep, you can use a module with the scope property. E.g.

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

The downside is that you need to make sure you define/declare all the properties need for that storageAccount which is not ideal. There are some ways you can author around that, but if the storageAccount doesn't exist, the deployment is guaranteed to fail. For example, you could assert the storageAccount exists, fetch its properties and then union or modify the properties in the module. You might be able to make that work (depending on the extent of your changes) but it's a bit of an anti-pattern in a declarative model.

That help?

bmoore-msft
  • 8,376
  • 20
  • 22
  • Thanks, that helps a lot! I can't really make the storage account part of this deployment, it's completely out of scope: I'm deploying an AKS cluster and just want to make sure the cluster can connect to an existing storage account. One could argue that the resource definition of the storage account should be adapted to take the new AKS cluster into account. However, that one was created manually, it's not in a declarative model yet. So, I'll probably choose the Azure CLI route for this "connect the cluster to existing resources" use case. – Fabian Schmied Feb 01 '22 at 07:34
  • Just for learning, could you maybe elaborate on the "assert the storageAccount exists, fetch its properties and then union or modify the properties in the module" idea? Does that mean to declare the storage account both as `resource existing` and as an actual `resource`, then somehow using Bicep functions to build up the storage account's properties? Is there an example for this online somewhere? – Fabian Schmied Feb 01 '22 at 07:38
  • (My first, naive version of this does not work, as most values need to be "calculated at the start of the deployment". E.g., kind, location, sku, etc.) – Fabian Schmied Feb 01 '22 at 07:44