From 0c86d10d4d1951bcccb7235c2946559996aa562b Mon Sep 17 00:00:00 2001 From: Slawomir Koszewski Date: Sat, 28 Feb 2026 22:10:38 +0100 Subject: [PATCH] Enhance Azure Storage Account module with additional variables and blob data protection features --- README.md | 22 ++++++++++-- main.tf | 29 ++++++++++++++++ variables.tf | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3bdcd8c..e6e6d91 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,30 @@ This module creates an Azure Storage Account with the specified name, resource g - `rg_name`: The name of the resource group where the storage account will be created. - `location`: The Azure region where the storage account will be created. -- `storage_account_base_name`: A base name for the storage account. If `storage_account_name` is not provided, the module will generate a unique name using this base name and a hash of the subscription ID, resource group name, and base name. -- `storage_account_name`: The name of the storage account. If not provided, it will be generated based on the `storage_account_base_name`. +- `base_name`: Optional base name used to generate a unique storage account name when `name` is not set. +- `name`: Optional explicit storage account name. If omitted, the module generates a deterministic name from `base_name`. +- `account_tier`: Storage account performance tier. +- `account_replication_type`: Storage account replication strategy. +- `allow_nested_items_to_be_public`: Controls whether nested blobs/containers can be public. +- `public_network_access_enabled`: Enables or disables public network access. +- `tags`: Tags to apply to the storage account. - `containers`: A map of storage containers to be created within the storage account. Each container is defined as an object with the following properties: - `name`: The name of the storage container. - `container_access_type`: The access level of the container (e.g., "private", "blob", "container"). +### Blob Data Protection Inputs + +- `enable_blob_soft_delete` (optional, default `false`): Enables blob soft delete (`delete_retention_policy`) to recover deleted blobs/snapshots within a retention window. +- `blob_soft_delete_retention_days` (optional, default `null`): Retention days for blob soft delete. When `null`, provider default is used. +- `enable_container_soft_delete` (optional, default `false`): Enables container soft delete (`container_delete_retention_policy`) to recover deleted containers. +- `container_soft_delete_retention_days` (optional, default `null`): Retention days for container soft delete. When `null`, provider default is used. +- `enable_blob_versioning` (optional, default `false`): Stores previous blob versions so changes can be rolled back. +- `enable_blob_change_feed` (optional, default `false`): Records ordered blob change events for audit, replay, and recovery workflows. +- `enable_point_in_time_restore_for_containers` (optional, default `false`): Enables point-in-time restore (`restore_policy`) for blob data to recover state from a chosen point in time. +- `point_in_time_restore_days` (optional, default `null`): Restore window in days. Required only when point-in-time restore is enabled. + +Point-in-time restore requires `enable_blob_soft_delete = true`, `enable_blob_versioning = true`, and `enable_blob_change_feed = true`. + ## Outputs - `storage_account_id`: The ID of the created storage account. diff --git a/main.tf b/main.tf index 066f643..4232f7a 100644 --- a/main.tf +++ b/main.tf @@ -24,6 +24,35 @@ resource "azurerm_storage_account" "this" { public_network_access_enabled = var.public_network_access_enabled min_tls_version = "TLS1_2" + blob_properties { + versioning_enabled = var.enable_blob_versioning + change_feed_enabled = var.enable_blob_change_feed + + dynamic "delete_retention_policy" { + for_each = var.enable_blob_soft_delete ? [1] : [] + + content { + days = var.blob_soft_delete_retention_days + } + } + + dynamic "container_delete_retention_policy" { + for_each = var.enable_container_soft_delete ? [1] : [] + + content { + days = var.container_soft_delete_retention_days + } + } + + dynamic "restore_policy" { + for_each = var.enable_point_in_time_restore_for_containers ? [1] : [] + + content { + days = var.point_in_time_restore_days + } + } + } + tags = var.tags } diff --git a/variables.tf b/variables.tf index 03bbe50..0e14c41 100644 --- a/variables.tf +++ b/variables.tf @@ -44,6 +44,100 @@ variable "public_network_access_enabled" { default = true } +variable "enable_blob_soft_delete" { + type = bool + default = false +} + +variable "blob_soft_delete_retention_days" { + type = number + default = null + + validation { + condition = ( + var.enable_blob_soft_delete == false || + var.blob_soft_delete_retention_days == null || + (var.blob_soft_delete_retention_days >= 1 && var.blob_soft_delete_retention_days <= 365) + ) + error_message = "blob_soft_delete_retention_days must be between 1 and 365." + } +} + +variable "enable_container_soft_delete" { + type = bool + default = false +} + +variable "container_soft_delete_retention_days" { + type = number + default = null + + validation { + condition = ( + var.enable_container_soft_delete == false || + var.container_soft_delete_retention_days == null || + (var.container_soft_delete_retention_days >= 1 && var.container_soft_delete_retention_days <= 365) + ) + error_message = "container_soft_delete_retention_days must be between 1 and 365." + } +} + +variable "enable_blob_versioning" { + type = bool + default = false +} + +variable "enable_blob_change_feed" { + type = bool + default = false +} + +variable "enable_point_in_time_restore_for_containers" { + type = bool + default = false + + validation { + condition = ( + var.enable_point_in_time_restore_for_containers == false || + ( + var.enable_blob_soft_delete && + var.enable_blob_versioning && + var.enable_blob_change_feed + ) + ) + error_message = "enable_point_in_time_restore_for_containers requires enable_blob_soft_delete, enable_blob_versioning, and enable_blob_change_feed to be true." + } +} + +variable "point_in_time_restore_days" { + type = number + default = null + + validation { + condition = ( + var.enable_point_in_time_restore_for_containers == false || + var.point_in_time_restore_days != null + ) + error_message = "point_in_time_restore_days must be set when enable_point_in_time_restore_for_containers is true." + } + + validation { + condition = ( + var.enable_point_in_time_restore_for_containers == false || + (var.point_in_time_restore_days >= 1 && var.point_in_time_restore_days <= 365) + ) + error_message = "point_in_time_restore_days must be between 1 and 365." + } + + validation { + condition = ( + var.enable_point_in_time_restore_for_containers == false || + var.point_in_time_restore_days < coalesce(var.blob_soft_delete_retention_days, 7) + ) + error_message = "point_in_time_restore_days must be less than blob_soft_delete_retention_days." + } +} + variable "tags" { type = map(string) default = {}