Creating an Azure Blob storage container with Terraform in an Azure storage account with network rules restricting access
If you need to create an Azure Blob storage container in an Azure storage account with network rules restricting access, this post will outline the issues you'll encounter if you don't have appropriate access and how to create the Azure Blob storage container without adding additional Azure storage firewall rules.
Background
Recently I encountered a case where I needed to create an Azure Blob storage container in an Azure storage account with network rules enabled from a CI provider hosted runner with Terraform. The issue was that the CI provider hosted runners weren't permitted to access the Azure storage account due to the network rules. As of 2022-08-19, the Terraform AzureRM provider uses the Microsoft Storage APIs for provisioning of objects within an Azure storage account. Therefore, if you attempt to create an Azure Blob storage container within an Azure storage account with network rules preventing access from the host running Terraform, you'll get an error similar to the following
$ terraform apply
...
azurerm_storage_container.name: Creating...
│ Error: 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."
Working around this issue
The Microsoft Storage APIs are subject to the network rules on Azure storage account. I needed a way to create the Azure Blob storage container using the Azure Resource Provider APIs for Blob containers which are not subject to the network rules on Azure storage account.
To achieve that goal, I leveraged the AzAPI Terraform Provider which according to the documentation
... is a very thin layer on top of the Azure ARM REST APIs. This provider compliments the AzureRM provider by enabling the management of Azure resources that are not yet or may never be supported in the AzureRM provider such as private/public preview services and features.
For example, to create an Azure Blob storage container inside of an Azure storage account with network rules enabled you can use the following azapi_resource
snippet from the AzAPI provider
# Other resources omitted for brevity
resource "azapi_resource" "example_storage_container" {
type = "Microsoft.Storage/storageAccounts/blobServices/containers@2021-09-01"
name = "azapi-example"
parent_id = "${azurerm_storage_account.example.id}/blobServices/default"
body = jsonencode({
properties = {
# Set publicAccess to `None` to match the default behavior of
# azurerm_storage_container. May also be set to `Blob` or `Container`.
publicAccess = "None"
}
})
}
and a full working example of creating an Azure resource group, storage account, and blob storage container using the AzureRM and AzAPI provider to show how to tie it all together.
terraform {
required_providers {
azapi = {
source = "azure/azapi"
}
azurerm = {
source = "hashicorp/azurerm"
}
random = {
source = "hashicorp/random"
}
}
}
provider "azapi" {}
provider "azurerm" {
features {}
}
resource "random_string" "example" {
length = 24
numeric = true
special = false
upper = false
}
resource "azurerm_resource_group" "example" {
name = random_string.example.result
location = "East US"
}
resource "azurerm_storage_account" "example" {
name = random_string.example.result
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
account_tier = "Standard"
account_replication_type = "LRS"
network_rules {
# Deny all access for proving the example. In reality you'd
# have Virtual Network rules or Private Link access.
default_action = "Deny"
}
}
resource "azapi_resource" "example_storage_container" {
type = "Microsoft.Storage/storageAccounts/blobServices/containers@2021-09-01"
name = "azapi-example"
parent_id = "${azurerm_storage_account.example.id}/blobServices/default"
body = jsonencode({
properties = {
# Set publicAccess to `None` to match the default behavior of
# azurerm_storage_container. May also be set to `Blob` or `Container`.
publicAccess = "None"
}
})
}
Applying the previous Terraform configuration leads to a successful creation of the resource group, storage account, and blob storage container.
$ terraform apply
...
Plan: 4 to add, 0 to change, 0 to destroy.
...
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
Summary
I've shown you how you can leverage the AzAPI Terraform Provider to create an Azure Blob storage container in an Azure storage account with network rules restricting access by using the azapi_resource
. If you commonly manage Azure resources with Terraform, keep the AzAPI provider in mind as it is a valuable tool for augmenting the AzureRM Terraform provider and can easily prevent you from having to implement worse workarounds to solve the same problem.
To quote a peer of mine
AzAPI feels like a cheat code