Azure Terraform Storage Account Provisioning, Security Hardening, and State Management

Infrastructure as code for Azure Storage Accounts requires precise provider configuration, repeatable resource definitions, and deliberate security decisions from the initial declaration. Terraform makes it possible to define storage accounts consistently with the right security and networking settings from day one. The reference implementation covers creating storage accounts in Terraform with all the production-ready configuration options including replication, networking rules, lifecycle management, and encryption.

Provider Configuration and Version Constraints

Provider configuration establishes the baseline for all subsequent Azure resources.

hcl terraform { required_version = ">= 1.5.0" required_providers { azurerm = { source = "hashicorp/azurerm" version = "~> 4.0" } } } provider "azurerm" { features {} subscription_id = var.subscription_id }

The requiredversion constraint of >= 1.5.0 ensures the Terraform core supports modern syntax and state handling. The azurerm provider source hashicorp/azurerm with version ~> 4.0 locks compatibility with the v4 API surface. The impact for operators is predictable behavior across team members and CI pipelines. Version pinning prevents unexpected provider changes from altering resource plans. The provider block with features {} enables the default feature set while subscriptionid is passed via variable to avoid hard coding subscription context.

Contextually, provider configuration precedes resource group and storage account definitions. Without a stable provider, replication, encryption, and networking settings cannot be reliably enforced.

Resource Group Foundation

The resource group creates the container for all storage assets.

hcl resource "azurerm_resource_group" "storage" { name = "rg-storage-production" location = "East US" }

Naming the resource group rg-storage-production communicates purpose and environment. Location East US determines the initial data residency and network latency profile. The impact is that all child storage accounts inherit the location unless explicitly overridden. Changing location later requires recreation. In a production landscape, resource group naming conventions enable cost allocation, access control boundaries, and automated governance policies.

Basic Storage Account Definition

A straightforward storage account configuration provides a starting point for production use.

hcl resource "azurerm_storage_account" "main" { name = var.storage_account_name resource_group_name = azurerm_resource_group.storage.name location = azurerm_resource_group.storage.location account_tier = "Standard" account_replication_type = "GRS" account_kind = "StorageV2" https_traffic_only_enabled = true min_tls_version = "TLS1_2" infrastructure_encryption_enabled = true access_tier = "Hot" }

The name is sourced from var.storageaccountname to satisfy the requirement that the storage account name must be globally unique. Global uniqueness means the name must be unique across all of Azure, not only within a subscription. Collisions cause deployment failures. The resourcegroupname and location reference the previously defined resource group, ensuring co-location.

Account tier Standard selects the general purpose performance tier. Account replication type GRS denotes Geo-redundant storage. Geo-redundancy replicates data to a secondary region for disaster recovery. The impact is higher durability at increased cost versus LRS.

Account kind StorageV2 is the general purpose v2 storage account. It supports blob, file, queue, and table services. Httpstrafficonlyenabled = true blocks unencrypted HTTP traffic. This eliminates plaintext exposure. Mintlsversion = "TLS12" enforces modern cipher suites and rejects older TLS versions. Infrastructure encryption enabled adds double encryption, meaning customer data is encrypted by Microsoft-managed keys and an additional encryption layer managed by the Azure platform. Access tier Hot optimizes for frequently accessed data with lower latency and higher request costs.

The configuration also notes allow or deny public blob access at the account level. Public blob access controls exposure of containers and blobs to anonymous requests. Restricting public access reduces attack surface for data exfiltration.

Replication, Tier, and Encryption Settings

Replication, tier, and encryption choices directly affect cost, durability, and compliance posture.

Standard tier with GRS replication provides a balance between cost and regional failover. Operators can evaluate needs for read-access secondary versus zone-redundant options. Infrastructure encryption enabled provides defense in depth. If an attacker compromises storage infrastructure, double encryption increases the effort required to decrypt data.

Minimum TLS 1.2 is a compliance requirement for many regulatory frameworks. Enforcing it prevents legacy clients from connecting. The impact is that older applications must be upgraded, but security posture improves.

Hot access tier impacts billing for storage versus access. Hot tier charges lower storage rates with higher transaction fees, suitable for active workloads.

Network Security and Public Access Controls

Network controls are critical for production storage accounts.

Httpstrafficonly_enabled = true is a baseline. In a production deployment, it is recommended to restrict access to this storage account using a storage firewall, service endpoint, or private endpoint. Public network access allowed in example configurations creates exposure. Restricting access via firewall rules limits traffic to approved IP ranges or virtual networks. Private endpoints provide secure and direct connectivity to Azure Storage over a private network. This eliminates public internet exposure entirely.

The module designed to create Azure Storage Accounts supports the creation of a storage account private endpoint which provides secure and direct connectivity to Azure Storage over a private network. Private endpoints are provisioned in the same region as the storage account. Co-location reduces latency and simplifies routing.

Verification and Lifecycle Operations

After configuration, Terraform operations confirm resource creation and allow safe removal.

Type yes and press Enter to confirm and create the Azure Storage Account and Resource Group.

Step 7: Verify the Resources. Once the apply operation completes successfully, you can verify the created resources in the Azure portal or by running the following command:

bash terraform show

The terraform show command displays the current state of the resources managed by Terraform. Verification confirms that replication type, encryption, and network settings were applied as intended.

Step 7: Deleting the resource created. After creation it is necessary to remove the unwanted resource to avoid extra cost from the side of azure. You can run the below command to remove all the resources:

bash terraform destroy

Destruction removes the storage account and dependent resources. Cost avoidance is immediate. Proper lifecycle management prevents orphaned accounts that continue to incur storage and transaction charges.

Advantages of Infrastructure as Code for Storage Accounts

Creating an Azure Storage Account using Terraform offers several advantages.

  • Infrastructure as Code: Your Azure Storage Account can now be represented in the Terraform configuration files that can be handled by using version control, shared, are replicated across many different environments. This aids organization in maintaining best practices, consistency, reproducibility and collaboration within their group.
  • Automation and Repeatability: When you Terraform and configure automation, you can easily provision and manage Azure Storage Accounts, without any need of human interventions and consequently mistakes
  • This creates a cloud-based storage management, giving you a control of your storage accounts in any part of the, consequently, enabling you to manage your entire infrastructure using one common programming frontend.

Version control provides audit history for changes to replication type, TLS version, and encryption settings. Repeatability ensures identical accounts can be reproduced in dev, test, and production.

Disadvantages and Operational Risks

There are many disadvantages of using terraform to create azure storage account or any other particular service.

  • Learning Curve: Terrraform uses its own domain-specific language (HashiCorp Configuration Language or HCL) and workflow and thus it can be challenging to master them for the first time provided that you may not be familiar with IaC tools. It is probable that grasp of concepts, syntax and best practices of Terraform may take some time and a lot of work.
  • State File Management: terraform employs a state file in order to maintain the status of your infrastructure resources. Proper management and storing of state files should be paid enough attention, because any inconsistency or loss of the state file will cause trouble in the management or updating of resources. A well-structured state file management system is an absolute necessity, particularly for groups or multi-member work.
  • Vendor Lock-in: While Terraform has the flexibility to support cloud services offered by different providers, its configuration files and modules can be classified as provider/version specific

State file management is especially critical because Terraform state is stored in plain text and may contain secrets. If the state is incorrectly secured, unauthorized access to systems and data loss can result. State file loss leads to drift detection failures and potential resource recreation.

Module-Based Provisioning with AzAPI Provider

A Terraform module is designed to create Azure Storage Accounts and its related resources, including blob containers, queues, tables, and file shares. It also supports the creation of a storage account private endpoint which provides secure and direct connectivity to Azure Storage over a private network.

Warning: Major version Zero (0.y.z) is for initial development. Anything MAY change at any time. A module SHOULD NOT be considered stable till at least it is major version one (1.0.0) or greater. Changes will always be via new versions being published and no changes will be made to existing published versions.

Module capabilities include:

  • Create a storage account with various configuration options such as account kind, tier, replication type, network rules, and identity settings.
  • Create blob containers, queues, tables, and file shares within the storage account.
  • Support for customer-managed keys for encrypting the data in the storage account.
  • Enable private endpoint for the storage account, providing secure access over a private network.

The module creates resources in the same region as the storage account. Regional consistency simplifies network planning. Customer-managed keys for encrypting data provide control over key rotation and revocation. The module manages the Storage Account itself, plus its child containers, queues, tables, file shares, private endpoints and role assignments, through the AzAPI provider, which always authenticates with Microsoft Entra ID and never requires a Storage shared key.

Using AzAPI provider avoids shared key exposure. Entra ID authentication enables fine-grained role assignments and audit trails.

Storage Account Name Uniqueness and Regional Placement

The storage account name must be globally unique. Name validation failures are a common source of deployment errors. To learn more about troubleshooting storage account names, see Resolve errors for storage account names.

Global uniqueness requires pre-checks in CI pipelines. The module creates resources in the same region as the storage account. This keeps data plane operations low latency and respects data residency policies.

Terraform State Backend Configuration in Azure Storage

Storing Terraform state in Azure Storage provides durability and collaboration.

To configure the backend state, you need the following Azure storage information:

  • storageaccountname: The name of the Azure Storage account.
  • container_name: The name of the blob container.
  • key: The name of the state store file to be created.
  • access_key: The storage access key.

Each of these values can be specified in the Terraform configuration file or on the command line. We recommend that you use an environment variable for the access_key value.

The backend configuration requires elevated permissions on the storage account. Terraform retains this method for backwards compatibility, we do not recommend it for new workloads.

Authentication to the backend can use an Access Key. In this example, Terraform authenticates to the Azure storage account using an Access Key. In a production deployment, it's recommended to evaluate the available authentication options supported by the azurerm backend and to use the most secure option for your use case.

Access keys provide broad permissions. Using Entra ID with limited scope reduces blast radius. State files contain resource identifiers and may contain secrets. Securing the container with private endpoint and firewall rules is recommended.

Backend Configuration Requirements and Optional Lookups

The following configuration options are always required for this method:

  • tenantid: The tenant ID of the Microsoft Entra ID principal is required to authenticate to the storage account management and data plane. If using Azure CLI, this can be inferred from the CLI session. This can also be set via the ARMTENANT_ID environment variable.
  • subscriptionid: The subscription ID of the storage account is required to query the management plane. If using Azure CLI, this can be inferred from the CLI session. This can also be set via the ARMSUBSCRIPTION_ID environment variable.
  • resourcegroupname: The resource group name of the storage account is required to query the management plane.
  • storageaccountname: The name of the storage account to write the state file blob to.
  • container_name: The name of the storage account container to write the state file blob to.
  • key: The name of the blob within the storage account container to write the state file to.

These optional configuration options apply when looking up the data plane URI from the management plane. They are not required when the data plane URI can be inferred from storageaccountname and container_name.

  • lookupblobendpoint: Set to true to lookup the storage account data plane URI from the management plane

Lookup of blob endpoint allows Terraform to resolve regional endpoints dynamically. Explicit endpoint specification reduces lookup latency.

Storage Tasks Integration with Terraform

A storage task can perform operations on blobs in an Azure Storage account. As you create a task, you can define the conditions that must be met by each object (container or blob), and the operations to perform on the object. You can also identify one or more Azure Storage account targets. See What are Azure Storage Actions?

In this how-to article, you learn how to create a storage task using Terraform.

Terraform enables the definition, preview, and deployment of cloud infrastructure. Using Terraform, you create configuration files using HCL syntax. The HCL syntax allows you to specify the cloud provider - such as Azure - and the elements that make up your cloud infrastructure. After you create your configuration files, you create an execution plan that allows you to preview your infrastructure changes before they're deployed.

Storage tasks enable automated lifecycle management for blobs without custom code. Combining storage account provisioning with storage task definitions in the same Terraform configuration ensures policy and storage are versioned together.

Production Readiness Checklist

Structured data for key storage account attributes can be summarized for reference.

| Attribute | Example Value | Purpose |
| accounttier | Standard | General purpose performance tier |
| account
replicationtype | GRS | Geo-redundant storage |
| account
kind | StorageV2 | General purpose v2 |
| httpstrafficonlyenabled | true | Enforce HTTPS |
| min
tlsversion | TLS12 | Minimum TLS version |
| infrastructureencryptionenabled | true | Double encryption |
| access_tier | Hot | Frequent access optimization |

The table reinforces that each setting has a direct impact on cost, security, and performance. Changes to replication type require account recreation in some cases. Changing TLS version affects client compatibility.

Conclusion

Azure Terraform storage account management combines declarative resource definition with operational security practices. Provider version pinning, resource group foundations, and explicit storage account properties ensure repeatability. Replication choice GRS, tier Standard, kind StorageV2, HTTPS enforcement, TLS 1.2 minimum, infrastructure encryption, and Hot access tier together form a production baseline. Network hardening through private endpoints, storage firewalls, and service endpoints addresses the public network access risk highlighted in examples. State backend configuration with tenantid, subscriptionid, resourcegroupname, storageaccountname, container_name, and key provides durable state storage, while access key usage should be replaced with Entra ID authentication where possible. Module-based provisioning via AzAPI provider supports customer-managed keys, private endpoints, and child resources without shared keys. Verification with terraform show and cleanup with terraform destroy completes the lifecycle. Advantages of Infrastructure as Code and automation are balanced against learning curve, state file management complexity, and vendor lock-in. Storage tasks extend Terraform coverage to blob operations, enabling policy as code for data lifecycle.

Sources

  1. How to create Azure storage accounts in Terraform
  2. How to create Azure Storage Account using Terraform
  3. terraform-azurerm-avm-res-storage-storageaccount
  4. Store state in Azure Storage
  5. Storage task quickstart Terraform
  6. Terraform AzureRM Backend

Related Posts