I am trying to write Terraform that will create an Azure Storage account and then a bunch of storage containers inside it. An important detail is that the storage account has network rules that restrict access to a specific address space. This was causing the container creation to fail.
I managed to get around this by using azurerm_storage_account_network_rules
, depending on the containers so not to block their creation. Something like this:
resource "azurerm_storage_account" "this" {
name = local.storage_name
resource_group_name = azurerm_resource_group.this.name
location = var.location
account_tier = "Standard"
account_kind = "StorageV2"
is_hns_enabled = true
account_replication_type = "LRS"
}
resource "azurerm_storage_container" "data" {
for_each = toset(var.storage_containers)
name = each.value
storage_account_name = azurerm_storage_account.this.name
container_access_type = "private"
}
# FIXME This order prevents destruction of infrastructure :(
resource "azurerm_storage_account_network_rules" "this" {
storage_account_id = azurerm_storage_account.this.id
default_action = "Deny"
bypass = ["AzureServices"]
virtual_network_subnet_ids = [
# Some address space here...
]
# NOTE The order here matters: We cannot create storage
# containers once the network rules are locked down
depends_on = [
azurerm_storage_container.data
]
}
This works for creating the infrastructure, but when I try to terraform destroy
, I get a 403 authentication error:
Error: retrieving Container "data" (Account "XXX" / Resource Group "XXX"): containers.Client#GetProperties: Failure responding to request: StatusCode=403 -- Original Error: autorest/azure: Service returned an error. Status=403 Code="AuthorizationFailure" Message="This request is not authorized to perform this operation.\nRequestId:XXX\nTime:XXX"
This is with my Service Principal, which has Contributor
and User Access Administrator
roles on the same subscription. Interestingly, when I'm logged in to the Azure Portal as myself (with the Owner
role), I can add and remove storage containers regardless of the network rules being present.
So, is there a way of setting the Terraform dependencies such that they can both be built and destroyed without hitting any authentication conflicts? Alternatively, would upgrading my SP's role to Owner
(or adding another, more targeted role) solve the problem?
This is an expected behavior as you are setting up the network rules
for the storage account to deny
and only bypassing
the Azure Services
.
When you deny
and bypass Azure Services
the Azure Services
like Azure Portal's IP
gets the access to the storage account and you are able to delete it . But at the same time , when you use terraform
to perform a destroy , then it denies because your IP
which is being used by your machine to send terraform
requests to Azure is not bypassed
.
I tested your code like below with the same permissions:
As a Solution you will have to add ip rules
while creating the storage account to the add the client_ip
like below :
provider "azurerm" {
features{}
client_id="f6a2f33d-xxxx-xxxx-xxxx-xxxx"
client_secret= "GZ67Q~xxxx~3N-qLT"
tenant_id = "72f988bf-xxxx-xxxx-xxxx-2d7cd011db47"
subscription_id="948d4068-xxxx-xxxx-xxxx-xxxx"
}
locals {
storage_name = "ansumantestsacc12"
subnet_id_list = [
"/subscriptions/xxxx/resourceGroups/xxxx/providers/Microsoft.Network/virtualNetworks/xxxx/subnets/xxxx"
]
my_ip = ["xx.xx.xx.xxx"] # IP used by me
}
variable "storage_containers" {
default = [
"test",
"terraform"
]
}
data "azurerm_resource_group" "this" {
name = "ansumantest"
}
resource "azurerm_storage_account" "this" {
name = local.storage_name
resource_group_name = data.azurerm_resource_group.this.name
location = data.azurerm_resource_group.this.location
account_tier = "Standard"
account_kind = "StorageV2"
is_hns_enabled = true
account_replication_type = "LRS"
}
resource "azurerm_storage_container" "data" {
for_each = toset(var.storage_containers)
name = each.value
storage_account_name = azurerm_storage_account.this.name
container_access_type = "private"
}
# FIXED
resource "azurerm_storage_account_network_rules" "this" {
storage_account_id = azurerm_storage_account.this.id
default_action = "Deny"
bypass = ["AzureServices"]
ip_rules = local.my_ip # need to set this to use terraform in our machine
virtual_network_subnet_ids = local.subnet_id_list
# NOTE The order here matters: We cannot create storage
# containers once the network rules are locked down
depends_on = [
azurerm_storage_container.data
]
}
Output: