skip to Main Content

I am giving my first steps with bicep, but I feel completely stuck :-/

I want to get the public ips from a App Service, and after that, I want to limit with them the access to an storage account. I face two problems:

  • The first one is I cannot iterate the "for" loop. It says about "allowedIPAddress" that "This expression is being used in the for-expression, which requires a value that can be calculated at the start of the deployment. you are referencing a variable which cannot be calculated"
  • The second one, how can I update the IpRules of the storage after I have obtained the rules with the IPs??

Here is my code:

////// FIRST PART: TO GET THE APP SERVICE IP
resource sitewww 'Microsoft.Web/sites@2022-03-01' existing = {
name: 'mywebapp'
}

//Here I get the list of IPs
var ipSalidaString = string(sitewww.properties.outboundIpAddresses)

//I split the IPs list to an Array String, so I can use it
var allowedIpAddresses  = split(ipSalidaString,',')

/// THIS FOR LOOP DOES NOT WORK AND I DO NOT KNOW WHY
var additionalIpSecurityRestrictions = [for ip in allowedIpAddresses: {
  action: 'Allow'
  value: ip
 }]


//////  Second Part: Update the IpRules of the Storage Account 

resource almacenamiento 'Microsoft.Storage/storageAccounts@2022-09-01'{
  
  name: 'teststorage'
  location:localizacion
   properties:{
    publicNetworkAccess: 'Enabled'  
     networkAcls:{
      defaultAction:'Deny'
      ipRules: [{   /// MUST BE UPDATED 
        action: 'Allow'
        value: '20.26.196.151'
       
      }
    ]
    }           
}
}

I tried severals ways to iterate the for loop, but always says "this expression is being used in the for-expression, which requires a value that can be calculated at the start of the deployment. you are referencing a variable which cannot be calculated"

I expect to create a object with the IpRules for my storage account

2

Answers


  1. I would recommend to join that AppService to a VNet instead and then using service endpoints to restrict the access on the Storage Account. The public IPs of the App Service Plan might change, this way you wont have to bother updating the rules.

    
    param location string = resourceGroup().location
    
    // Create a virtual network
    resource vnet 'Microsoft.Network/virtualNetworks@2022-07-01' = {
      name: 'myVnet'
      location: location
      properties: {
        addressSpace: {
          addressPrefixes: [
            '10.0.0.0/16'
          ]
        }
        subnets: [
          {
            name: 'mySubnet'
            properties: {
              addressPrefix: '10.0.1.0/24'
              // Enable service endpoint for Microsoft.Storage
              serviceEndpoints: [
                {
                  service: 'Microsoft.Storage'
                  locations: [
                    location
                  ]
                }
              ]
            }
          }
        ]
      }
    }
    
    // Create a storage account
    resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
      name: 'mystorage${uniqueString(resourceGroup().id)}'
      location: location
      kind: 'StorageV2'
      sku: {
        name: 'Standard_LRS'
      }
      properties: {
        // Restrict access to the storage account from the subnet only
        networkAcls: {
          bypass: 'None'
          defaultAction: 'Deny'
          virtualNetworkRules: [
            {
              id: vnet.properties.subnets[0].id // Reference the subnet id
              action: 'Allow'
            }
          ]
        }
        supportsHttpsTrafficOnly: true
      }
    }
    
    // Create an app service plan
    resource appServicePlan 'Microsoft.Web/serverfarms@2021-02-01' = {
      name: 'myAppServicePlan'
      location: location
      sku: {
        name: 'S1'
        tier: 'Standard'
        size: 'S1'
        family: 'S'
        capacity: 1
      }
    }
    
    // Create an app service 
    resource appService 'Microsoft.Web/sites@2022-03-01' = {
      name: 'myAppService${uniqueString(resourceGroup().id)}'
      location: location
      kind: 'app'
      properties: {
        serverFarmId: appServicePlan.id
        siteConfig: {
          alwaysOn: true
          http20Enabled: true
          webSocketsEnabled: true
    
        }
        virtualNetworkSubnetId: vnet.properties.subnets[0].id // Reference the subnet id
      }
    }
    
    
    Login or Signup to reply.
  2. As suggested by @silent, you should definitely use VNET integration to restrict traffic to the storage account rather than adding the outbound Ips of the webApp.

    The issue you’re seeing can be fixed by creating the storage account in its own module:

    // storage-account.bicep
    param location string = resourceGroup().location
    param storageAccountName string
    param ips array
    
    resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
      name: storageAccountName
      location: location
      kind: 'StorageV2'
      sku: {
        name: 'Standard_LRS'
      }
      properties: {
        publicNetworkAccess: 'Enabled'
        networkAcls: {
          defaultAction: 'Deny'
          ipRules: [for ip in ips: {
            action: 'Allow'
            value: ip
          }]
        }
      }
    }
    

    You can then call this module from the parent bicep:

    // main.bicep
    param location string = resourceGroup().location
    param webAppName string = 'mywebapp'
    param storageAccountName string = 'teststorage'
    
    // Get a reference to the existing webapp
    resource webApp 'Microsoft.Web/sites@2022-03-01' existing = {
      name: webAppName
    }
    
    // Create the storage with the IP rules
    module storageAccount 'storage-account.bicep' = {
      name: 'storage-account'
      params: {
        location: location
        storageAccountName: storageAccountName
        ips: split(webApp.properties.outboundIpAddresses, ',')
        
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search