Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Immutability policy storage account [#IOPID-752] #159

Merged
merged 8 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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