Patrick Lane
Patrick Lane

Reputation: 9

Creating multiple network rules for an Azure storage account using for_each in Terraform

I have used for_each loops to create a number of subnets and a number of storage accounts. I am trying now to allow all traffic on some storage accounts, while simultaneously allowing others to be accessed only from certain subnets.

In my main.tf file:

resource "azurerm_subnet" "subnets" {
  for_each = var.subnets
  name = each.key
  resource_group_name = var.rgname
  virtual_network_name = each.value.virtual_network_name
  address_prefixes = each.value.address_prefixes
  service_endpoints = ["Microsoft.Storage"]

  depends_on = [ azurerm_virtual_network.vnet_apps, azurerm_virtual_network.vnet_main ]
}

resource "azurerm_storage_account" "storage_accounts" {
  for_each = var.storage_accounts
  name = each.key
  resource_group_name = var.rgname
  location = var.location
  account_replication_type = "LRS"
  account_tier = "Standard"

  network_rules {
    default_action = each.value.network_action
    virtual_network_subnet_ids = [azurerm_subnet.subnets[each.value.subnetids].id]
  }
}

In my variables.tf file:

variable "subnets" {
  type = map(object({
     virtual_network_name = string
     address_prefixes = list(string)
     route_table = string
  }))
}

variable "storage_accounts" {
  type = map(object({
    network_action = string
    subnetids = list(string)
  }))
}

In my .tfvars file:

subnets = {
    vm_subnet = {
        virtual_network_name = "vnet_main"
        address_prefixes = ["10.1.1.0/25"]
        route_table = "vm_rt"
    }
    sql_subnet = {
        virtual_network_name = "vnet_main"
        address_prefixes = ["10.1.1.128/25"]
        route_table = "vm_rt"
    }
    app1_subnet = {
        virtual_network_name = "vnet_apps"
        address_prefixes = ["10.1.2.0/25"]
        route_table = "vm_rt"
    }
    app2_subnet = {
        virtual_network_name = "vnet_apps"
        address_prefixes = ["10.1.2.128/25"]
        route_table = "app_rt"
    }
}

storage_accounts = {
  mynamedefaultstorage57 = {
    network_action = "Allow"
    subnetids = ["app1_subnet"]
  }
  mynamedefaultstorage108 = {
    network_action = "Deny"
    subnetids = ["vm_subnet", "app2_subnet"]
  }
}

If I change subnetids to a string (rather than a list of strings) and change the tfvars file to only allow one subnet, it will work properly. But that doesn't allow me to do multiple subnets at once, and if I try it is as I have laid out here, I get this error:

on main.tf line 114, in resource "azurerm_storage_account" "storage_accounts":
│  114:     virtual_network_subnet_ids = [azurerm_subnet.subnets[each.value.subnetids].id]
│     ├────────────────
│     │ azurerm_subnet.subnets is object with 4 attributes
│     │ each.value.subnetids is list of string with 1 element
│
│ The given key does not identify an element in this collection value: string required.

Thanks in advance for any assistance you can offer.

Upvotes: 0

Views: 682

Answers (1)

Helder Sepulveda
Helder Sepulveda

Reputation: 17664

Here is a sample using dynamic blocks ... I think that should work but I have not tested

resource "azurerm_storage_account" "storage_accounts" {
  for_each = var.storage_accounts
  name = each.key
  resource_group_name = var.rgname
  location = var.location
  account_replication_type = "LRS"
  account_tier = "Standard"

  dynamic "network_rules" {
    for_each                   = each.value.subnetids
    default_action             = each.value.network_action
    virtual_network_subnet_ids = [azurerm_subnet.subnets[network_rules.value].id]
  }
}

Looking at the documentation for azurerm_storage_account there is a note:

Network Rules can be defined either directly on the azurerm_storage_account resource, or using the azurerm_storage_account_network_rules resource - but the two cannot be used together. If both are used against the same Storage Account, spurious changes will occur. When managing Network Rules using this resource, to change from a default_action of Deny to Allow requires defining, rather than removing, the block.

Maybe you should move to using the azurerm_storage_account_network_rules

Upvotes: 0

Related Questions