Search code examples
azureterraformazure-blob-storageazure-storage

Terraform Multiple Storage Account and Containers


I am trying to create multiple storage accounts and then containers, file shares, tables etc. for those storage accounts in azure. In the example, I have 2 storage accounts, the first has 2 containers, the second has none.

This is my variables.tf :

variable "location" {
  type    = string
  default = ""
}
variable "resource_group_name" {
  type    = string
  default = ""
}
variable "storage_account_name" {
  type    = string
  default = ""
}


######################################################################################################################

################### Storage Account

######################################################################################################################

variable "storageAccount" {
  type = map(
    object({
      name                                   = string
      owner                                  = string
      CreatedBy                              = string
      env                                    = string
      change_feed_enabled                    = bool
      container_delete_retention_policy_days = number
      delete_retention_policy_days           = number
      account_tier                           = string
      account_replication_type               = string
      table_encryption_key_type              = string
      queue_encryption_key_type              = string
      infrastructure_encryption_enabled      = bool
      storageBlobContainers = list(object({
        name = string
      }))
    })
  )
  default = {
    "storageAccount" = {
      name                                   = ""
      owner                                  = ""
      CreatedBy                              = ""
      env                                    = ""
      change_feed_enabled                    = false
      container_delete_retention_policy_days = 0
      delete_retention_policy_days           = 0
      account_tier                           = ""
      account_replication_type               = ""
      table_encryption_key_type              = ""
      queue_encryption_key_type              = ""
      infrastructure_encryption_enabled      = false
      storageBlobContainers                  = []
    }
  }
}

######################################################################################################################

################### Storage Account Blob Containers

######################################################################################################################

variable "storageBlobContainer" {
  type = map(list(string))
  description = "Map of storage account names and associated container names"
}

My tfvars:

  location            = "northeurope"
    resource_group_name = "finance-sandbox"
    
    storageAccount = {
      "d365fodev1sbconsstg" = {
        name                                   = "d365consstg"
        env                                    = "sandbox"
        owner                                  = "somsubhra.mukherjee"
        CreatedBy                              = "somsubhra.mukherjee"
        account_tier                           = "Standard"
        account_replication_type               = "LRS"
        table_encryption_key_type              = "Account"
        queue_encryption_key_type              = "Account"
        infrastructure_encryption_enabled      = false
        change_feed_enabled                    = false
        container_delete_retention_policy_days = 7
        delete_retention_policy_days           = 7
      }
        "d365fodev1sbfilesstg" = {
          name                                   = "d365filesstg",
          env                                    = "sandbox",
          owner                                  = "somsubhra.mukherjee",
          CreatedBy                              = "somsubhra.mukherjee",
          account_tier                           = "Standard",
          account_replication_type               = "LRS",
          table_encryption_key_type              = "Account",
          queue_encryption_key_type              = "Account",
          infrastructure_encryption_enabled      = false,
          change_feed_enabled                    = false,
          container_delete_retention_policy_days = 7,
          delete_retention_policy_days           = 7
        }
        }
    storageBlobContainer = {
  "d365consstg" = ["azure-webjobs-hosts", "azure-webjobs-secrets"]
  "d365consstg" = ["container1"]
}

My storageAccount.tf

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>3.0"
    }
  }
}

provider "azurerm" {
  features {
    key_vault {
      recover_soft_deleted_secrets = false
    }
  }
  skip_provider_registration = true
}

###############   Storage Account ##########################

resource "azurerm_storage_account" "storageAccount" {
  for_each = var.storageAccount
  name                              = each.value.name
  resource_group_name               = var.resource_group_name
  location                          = var.location
  account_tier                      = each.value.account_tier
  account_replication_type          = each.value.account_replication_type
  table_encryption_key_type         = each.value.table_encryption_key_type
  queue_encryption_key_type         = each.value.queue_encryption_key_type
  infrastructure_encryption_enabled = each.value.infrastructure_encryption_enabled
  tags = {
    env       = each.value.env
    owner     = each.value.owner
    CreatedBy = each.value.CreatedBy
  }

  blob_properties {
    change_feed_enabled = each.value.change_feed_enabled
    container_delete_retention_policy {
      days = each.value.container_delete_retention_policy_days
    }
    delete_retention_policy {
      days = each.value.delete_retention_policy_days
    }
  }
}

resource "azurerm_storage_container" "storageBlobContainer" {
  # count = length(flatten([for containers in values(var.storageBlobContainer) : containers]))
  for_each = var.storageBlobContainer

  storage_account_name = azurerm_storage_account.storageAccount[each.key].name
  name                 = each.value

}

I am a terraform newbie and cannot seem to create the containers properly. Ideally I would like it to happen automatically as first the storage account gets created and then the containers get created. But not sure how to do that.

Error Received :

Error: Invalid index
│
│   on storageAccount.tf line 59, in resource "azurerm_storage_container" "storageBlobContainer":
│   59:   storage_account_name = azurerm_storage_account.storageAccount[each.key].name
│     ├────────────────
│     │ azurerm_storage_account.storageAccount is object with 2 attributes
│     │ each.key is "storage_account2"
│
│ The given key does not identify an element in this collection value.
╵
╷
│ Error: Incorrect attribute value type
│
│   on storageAccount.tf line 60, in resource "azurerm_storage_container" "storageBlobContainer":
│   60:   name                 = each.value
│     ├────────────────
│     │ each.value is list of string with 2 elements
│
│ Inappropriate value for attribute "name": string required.

Solution

  • You have made a few mistakes:

    • container is defined on wrong level in tfvars
    • you iterate over storage account variable to create containers, you suppose to flatten your configuration to properly create containers.

    Take a look at this configuration:

    locals {
      storages = {
        order = {
          name       = "orderst"
          containers = ["order", "order-logs"]
        }
        catalog = {
          name       = "catalogst"
          containers = ["catalog", "catalog-logs"]
        }
      }
    }
    
    resource "azurerm_resource_group" "example" {
      name     = "example-resources"
      location = "West Europe"
    }
    
    resource "azurerm_storage_account" "example" {
      for_each                 = local.storages
      name                     = each.value.name
      resource_group_name      = azurerm_resource_group.example.name
      location                 = azurerm_resource_group.example.location
      account_tier             = "Standard"
      account_replication_type = "GRS"
    
      tags = {
        environment = "staging"
      }
    }
    
    locals {
      storage_account_names = flatten([for key, value in local.storages : [for container in value.containers : {
        name                 = container
        storage_account_name = azurerm_storage_account.example[key].name
        }]
      ])
    
    }
    
    resource "azurerm_storage_container" "example" {
      for_each              = { for storage in local.storage_account_names : storage.name => storage }
      name                  = each.value.name
      storage_account_name  = each.value.storage_account_name
      container_access_type = "private"
    }
    

    It will create 2 storage accounts and 4 containers (2 per account).

    It first create storage account iterating over variable(here local), and then it flatten configuration to create set of containing storage account name and container name to create containers.