Skip to content

Commit

Permalink
feat: Immutability policy storage account [#IOPID-752] (#159)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrea Grillo <[email protected]>
  • Loading branch information
BurnedMarshal and Krusty93 authored Oct 5, 2023
1 parent e139a60 commit 64a6c7b
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 14 deletions.
5 changes: 4 additions & 1 deletion postgres_flexible_server/tests/resources.tf
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,10 @@ module "storage_account" {
blob_delete_retention_days = 7
blob_change_feed_enabled = true
blob_change_feed_retention_in_days = 10
blob_restore_policy_days = 6
blob_storage_policy = {
blob_restore_policy_days = 6
enable_immutability_policy = false
}

tags = var.tags
}
8 changes: 7 additions & 1 deletion storage_account/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ resource "azurerm_private_dns_zone" "storage_account" {
```

## Known Issues

- Applying the immutability policy on an existing storage account fails due to a 404 NotFound error on the threat protection creation for the new storage. Solution, delete the resource and create the new one with the immutability policy.
- Changing the `period_since_creation_in_days` will be updated in terraform state but not in the cloud provider resource. Solution, change the value using the Azure portal.

## Migration from v2

Expand Down Expand Up @@ -202,6 +206,7 @@ No modules.
| [azurerm_advanced_threat_protection.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/advanced_threat_protection) | resource |
| [azurerm_monitor_metric_alert.storage_account_low_availability](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_metric_alert) | resource |
| [azurerm_storage_account.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_account) | resource |
| [null_resource.immutability](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |
## Inputs
Expand All @@ -218,14 +223,15 @@ No modules.
| <a name="input_blob_change_feed_retention_in_days"></a> [blob\_change\_feed\_retention\_in\_days](#input\_blob\_change\_feed\_retention\_in\_days) | (Optional) The duration of change feed events retention in days. The possible values are between 1 and 146000 days (400 years). Setting this to null (or omit this in the configuration file) indicates an infinite retention of the change feed. | `number` | `null` | no |
| <a name="input_blob_container_delete_retention_days"></a> [blob\_container\_delete\_retention\_days](#input\_blob\_container\_delete\_retention\_days) | Retention days for deleted container. Valid value is between 1 and 365 (set to 0 to disable). | `number` | `0` | no |
| <a name="input_blob_delete_retention_days"></a> [blob\_delete\_retention\_days](#input\_blob\_delete\_retention\_days) | Retention days for deleted blob. Valid value is between 1 and 365 (set to 0 to disable). | `number` | `0` | no |
| <a name="input_blob_restore_policy_days"></a> [blob\_restore\_policy\_days](#input\_blob\_restore\_policy\_days) | (Optional) Specifies the number of days that the blob can be restored, between 1 and 365 days. This must be less than the days specified for delete\_retention\_policy. | `number` | `0` | no |
| <a name="input_blob_storage_policy"></a> [blob\_storage\_policy](#input\_blob\_storage\_policy) | Handle immutability policy for stored elements | <pre>object({<br> enable_immutability_policy = bool<br> blob_restore_policy_days = number<br> })</pre> | <pre>{<br> "blob_restore_policy_days": 0,<br> "enable_immutability_policy": false<br>}</pre> | no |
| <a name="input_blob_versioning_enabled"></a> [blob\_versioning\_enabled](#input\_blob\_versioning\_enabled) | Controls whether blob object versioning is enabled. | `bool` | `false` | no |
| <a name="input_cross_tenant_replication_enabled"></a> [cross\_tenant\_replication\_enabled](#input\_cross\_tenant\_replication\_enabled) | (Optional) Should cross Tenant replication be enabled? Defaults to false. | `bool` | `false` | no |
| <a name="input_custom_domain"></a> [custom\_domain](#input\_custom\_domain) | Custom domain for accessing blob data | <pre>object({<br> name = string<br> use_subdomain = bool<br> })</pre> | <pre>{<br> "name": null,<br> "use_subdomain": false<br>}</pre> | no |
| <a name="input_domain"></a> [domain](#input\_domain) | (Optional) Specifies the domain of the Storage Account. | `string` | `null` | no |
| <a name="input_enable_identity"></a> [enable\_identity](#input\_enable\_identity) | (Optional) If true, set the identity as SystemAssigned | `bool` | `false` | no |
| <a name="input_enable_low_availability_alert"></a> [enable\_low\_availability\_alert](#input\_enable\_low\_availability\_alert) | Enable the Low Availability alert. Default is true | `bool` | `true` | no |
| <a name="input_error_404_document"></a> [error\_404\_document](#input\_error\_404\_document) | The absolute path to a custom webpage that should be used when a request is made which does not correspond to an existing file. | `string` | `null` | no |
| <a name="input_immutability_policy_props"></a> [immutability\_policy\_props](#input\_immutability\_policy\_props) | Properties to setup the immutability policy. The resource can be created only with "Disabled" and "Unlocked" state. Change to "Locked" state doens't update the resource for a bug of the current module. | <pre>object({<br> allow_protected_append_writes = bool<br> period_since_creation_in_days = number<br> })</pre> | <pre>{<br> "allow_protected_append_writes": false,<br> "period_since_creation_in_days": 730<br>}</pre> | no |
| <a name="input_index_document"></a> [index\_document](#input\_index\_document) | The webpage that Azure Storage serves for requests to the root of a website or any subfolder. For example, index.html. The value is case-sensitive. | `string` | `null` | no |
| <a name="input_is_hns_enabled"></a> [is\_hns\_enabled](#input\_is\_hns\_enabled) | Enable Hierarchical Namespace enabled (Azure Data Lake Storage Gen 2). Changing this forces a new resource to be created. | `bool` | `false` | no |
| <a name="input_is_sftp_enabled"></a> [is\_sftp\_enabled](#input\_is\_sftp\_enabled) | Enable SFTP | `bool` | `false` | no |
Expand Down
43 changes: 40 additions & 3 deletions storage_account/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ resource "azurerm_storage_account" "this" {
}

dynamic "restore_policy" {
for_each = (var.blob_restore_policy_days == 0 ? [] : [1])
for_each = (var.blob_storage_policy.blob_restore_policy_days == 0 ? [] : [1])
content {
days = var.blob_restore_policy_days
days = var.blob_storage_policy.blob_restore_policy_days
}
}
}
Expand Down Expand Up @@ -81,10 +81,22 @@ resource "azurerm_storage_account" "this" {
}
}

dynamic "immutability_policy" {
for_each = var.blob_storage_policy.enable_immutability_policy ? [1] : []

content {
allow_protected_append_writes = var.immutability_policy_props.allow_protected_append_writes
state = "Unlocked"
period_since_creation_in_days = var.immutability_policy_props.period_since_creation_in_days
}
}

# the use of storage_account_customer_managed_key resource will cause a bug on the plan: this paramenter will always see as changed.
# the state property is ignored because is overridden from a null_resource.
lifecycle {
ignore_changes = [
customer_managed_key
customer_managed_key,
immutability_policy.0.state
]
}

Expand Down Expand Up @@ -134,3 +146,28 @@ resource "azurerm_monitor_metric_alert" "storage_account_low_availability" {

tags = var.tags
}

resource "null_resource" "immutability" {

triggers = {
immutability_policy : var.blob_storage_policy.enable_immutability_policy
resouce_group_name : var.resource_group_name
name : var.name
}

provisioner "local-exec" {
command = <<EOT
if ${self.triggers.immutability_policy}; then
az storage account update --immutability-state Locked \
--resource-group ${self.triggers.resouce_group_name} \
--name ${self.triggers.name} \
--query "id"
# query is used to hide other properties from logging
fi
EOT
}

depends_on = [
azurerm_storage_account.this
]
}
39 changes: 38 additions & 1 deletion storage_account/tests/resources.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,44 @@ module "storage_account" {
blob_delete_retention_days = 7
blob_change_feed_enabled = true
blob_change_feed_retention_in_days = 10
blob_restore_policy_days = 6

blob_storage_policy = {
blob_restore_policy_days = 6
enable_immutability_policy = false
}

tags = var.tags
}

module "storage_account_immutable" {
source = "../../storage_account"

name = replace("${local.project}-im-st", "-", "")
account_kind = "StorageV2"
account_tier = "Standard"
access_tier = "Hot"
account_replication_type = "GRS"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
advanced_threat_protection = true
allow_nested_items_to_be_public = false
public_network_access_enabled = true

blob_versioning_enabled = true
blob_container_delete_retention_days = 7
blob_delete_retention_days = 7
blob_change_feed_enabled = true
blob_change_feed_retention_in_days = 10

blob_storage_policy = {
blob_restore_policy_days = 0
enable_immutability_policy = true
}

immutability_policy_props = {
allow_protected_append_writes = false
period_since_creation_in_days = 1
}

tags = var.tags
}
40 changes: 34 additions & 6 deletions storage_account/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,6 @@ variable "blob_change_feed_retention_in_days" {
default = null
}

variable "blob_restore_policy_days" {
description = "(Optional) Specifies the number of days that the blob can be restored, between 1 and 365 days. This must be less than the days specified for delete_retention_policy."
type = number
default = 0
}

variable "cross_tenant_replication_enabled" {
description = "(Optional) Should cross Tenant replication be enabled? Defaults to false."
type = bool
Expand Down Expand Up @@ -163,6 +157,40 @@ variable "custom_domain" {
}
}

# -------------------
# Immutability Policy
# -------------------

variable "blob_storage_policy" {
type = object({
enable_immutability_policy = bool
blob_restore_policy_days = number
})
description = "Handle immutability policy for stored elements"
default = {
enable_immutability_policy = false
blob_restore_policy_days = 0
}

# https://learn.microsoft.com/en-us/azure/storage/blobs/point-in-time-restore-overview#limitations-and-known-issues
validation {
condition = (var.blob_storage_policy.enable_immutability_policy == true && var.blob_storage_policy.blob_restore_policy_days == 0) || var.blob_storage_policy.enable_immutability_policy == false
error_message = "Immutability policy doesn't support Point-in-Time restore"
}
}

variable "immutability_policy_props" {
type = object({
allow_protected_append_writes = bool
period_since_creation_in_days = number
})
description = "Properties to setup the immutability policy. The resource can be created only with \"Disabled\" and \"Unlocked\" state. Change to \"Locked\" state doens't update the resource for a bug of the current module."
default = {
allow_protected_append_writes = false
period_since_creation_in_days = 730
}
}


# -------------------
# Alerts variables
Expand Down
5 changes: 4 additions & 1 deletion storage_account_customer_managed_key/tests/resources.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ module "storage_account" {
blob_delete_retention_days = 7
blob_change_feed_enabled = true
blob_change_feed_retention_in_days = 10
blob_restore_policy_days = 6
blob_storage_policy = {
blob_restore_policy_days = 6
enable_immutability_policy = false
}

enable_identity = true

Expand Down
5 changes: 4 additions & 1 deletion storage_object_replication/tests/resources.tf
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ module "storage_account" {
blob_delete_retention_days = 7
blob_change_feed_enabled = true
blob_change_feed_retention_in_days = 10
blob_restore_policy_days = 6
blob_storage_policy = {
blob_restore_policy_days = 6
enable_immutability_policy = false
}

tags = var.tags
}
Expand Down

0 comments on commit 64a6c7b

Please sign in to comment.