diff --git a/internal/features/defaults.go b/internal/features/defaults.go index 4b684a919cc9..56fde6f02b8f 100644 --- a/internal/features/defaults.go +++ b/internal/features/defaults.go @@ -18,6 +18,7 @@ func Default() UserFeatures { PurgeSoftDeletedKeysOnDestroy: true, PurgeSoftDeletedCertsOnDestroy: true, PurgeSoftDeletedSecretsOnDestroy: true, + PurgeSoftDeletedHSMsOnDestroy: true, RecoverSoftDeletedKeyVaults: true, RecoverSoftDeletedKeys: true, RecoverSoftDeletedCerts: true, diff --git a/internal/features/user_flags.go b/internal/features/user_flags.go index 4b92ed0aae8c..c1c6c5df155c 100644 --- a/internal/features/user_flags.go +++ b/internal/features/user_flags.go @@ -33,6 +33,7 @@ type KeyVaultFeatures struct { PurgeSoftDeletedKeysOnDestroy bool PurgeSoftDeletedCertsOnDestroy bool PurgeSoftDeletedSecretsOnDestroy bool + PurgeSoftDeletedHSMsOnDestroy bool RecoverSoftDeletedKeyVaults bool RecoverSoftDeletedKeys bool RecoverSoftDeletedCerts bool diff --git a/internal/provider/features.go b/internal/provider/features.go index 7dda3f9f0c37..9ee30f43618c 100644 --- a/internal/provider/features.go +++ b/internal/provider/features.go @@ -98,6 +98,13 @@ func schemaFeatures(supportLegacyTestSuite bool) *pluginsdk.Schema { Default: true, }, + "purge_soft_deleted_hardware_security_modules_on_destroy": { + Description: "When enabled soft-deleted `azurerm_key_vault_managed_hardware_security_module` resources will be permanently deleted (e.g purged), when destroyed", + Type: pluginsdk.TypeBool, + Optional: true, + Default: true, + }, + "recover_soft_deleted_certificates": { Description: "When enabled soft-deleted `azurerm_key_vault_certificate` resources will be restored, instead of creating new ones", Type: pluginsdk.TypeBool, @@ -320,6 +327,9 @@ func expandFeatures(input []interface{}) features.UserFeatures { if v, ok := keyVaultRaw["purge_soft_deleted_secrets_on_destroy"]; ok { featuresMap.KeyVault.PurgeSoftDeletedSecretsOnDestroy = v.(bool) } + if v, ok := keyVaultRaw["purge_soft_deleted_hardware_security_modules_on_destroy"]; ok { + featuresMap.KeyVault.PurgeSoftDeletedHSMsOnDestroy = v.(bool) + } if v, ok := keyVaultRaw["recover_soft_deleted_certificates"]; ok { featuresMap.KeyVault.RecoverSoftDeletedCerts = v.(bool) } diff --git a/internal/provider/features_test.go b/internal/provider/features_test.go index fcd0cdb5f9d1..7fb620ac91f8 100644 --- a/internal/provider/features_test.go +++ b/internal/provider/features_test.go @@ -33,6 +33,7 @@ func TestExpandFeatures(t *testing.T) { PurgeSoftDeletedKeysOnDestroy: true, PurgeSoftDeletedSecretsOnDestroy: true, PurgeSoftDeleteOnDestroy: true, + PurgeSoftDeletedHSMsOnDestroy: true, RecoverSoftDeletedCerts: true, RecoverSoftDeletedKeys: true, RecoverSoftDeletedKeyVaults: true, @@ -81,14 +82,15 @@ func TestExpandFeatures(t *testing.T) { }, "key_vault": []interface{}{ map[string]interface{}{ - "purge_soft_deleted_certificates_on_destroy": true, - "purge_soft_deleted_keys_on_destroy": true, - "purge_soft_deleted_secrets_on_destroy": true, - "purge_soft_delete_on_destroy": true, - "recover_soft_deleted_certificates": true, - "recover_soft_deleted_keys": true, - "recover_soft_deleted_key_vaults": true, - "recover_soft_deleted_secrets": true, + "purge_soft_deleted_certificates_on_destroy": true, + "purge_soft_deleted_keys_on_destroy": true, + "purge_soft_deleted_secrets_on_destroy": true, + "purge_soft_deleted_hardware_security_modules_on_destroy": true, + "purge_soft_delete_on_destroy": true, + "recover_soft_deleted_certificates": true, + "recover_soft_deleted_keys": true, + "recover_soft_deleted_key_vaults": true, + "recover_soft_deleted_secrets": true, }, }, "log_analytics_workspace": []interface{}{ @@ -143,6 +145,7 @@ func TestExpandFeatures(t *testing.T) { PurgeSoftDeletedKeysOnDestroy: true, PurgeSoftDeletedSecretsOnDestroy: true, PurgeSoftDeleteOnDestroy: true, + PurgeSoftDeletedHSMsOnDestroy: true, RecoverSoftDeletedCerts: true, RecoverSoftDeletedKeys: true, RecoverSoftDeletedKeyVaults: true, @@ -191,14 +194,15 @@ func TestExpandFeatures(t *testing.T) { }, "key_vault": []interface{}{ map[string]interface{}{ - "purge_soft_deleted_certificates_on_destroy": false, - "purge_soft_deleted_keys_on_destroy": false, - "purge_soft_deleted_secrets_on_destroy": false, - "purge_soft_delete_on_destroy": false, - "recover_soft_deleted_certificates": false, - "recover_soft_deleted_keys": false, - "recover_soft_deleted_key_vaults": false, - "recover_soft_deleted_secrets": false, + "purge_soft_deleted_certificates_on_destroy": false, + "purge_soft_deleted_keys_on_destroy": false, + "purge_soft_deleted_secrets_on_destroy": false, + "purge_soft_deleted_hardware_security_modules_on_destroy": false, + "purge_soft_delete_on_destroy": false, + "recover_soft_deleted_certificates": false, + "recover_soft_deleted_keys": false, + "recover_soft_deleted_key_vaults": false, + "recover_soft_deleted_secrets": false, }, }, "log_analytics_workspace": []interface{}{ @@ -252,6 +256,7 @@ func TestExpandFeatures(t *testing.T) { PurgeSoftDeletedCertsOnDestroy: false, PurgeSoftDeletedKeysOnDestroy: false, PurgeSoftDeletedSecretsOnDestroy: false, + PurgeSoftDeletedHSMsOnDestroy: false, PurgeSoftDeleteOnDestroy: false, RecoverSoftDeletedCerts: false, RecoverSoftDeletedKeys: false, @@ -510,6 +515,7 @@ func TestExpandFeaturesKeyVault(t *testing.T) { PurgeSoftDeletedKeysOnDestroy: true, PurgeSoftDeletedSecretsOnDestroy: true, PurgeSoftDeleteOnDestroy: true, + PurgeSoftDeletedHSMsOnDestroy: true, RecoverSoftDeletedCerts: true, RecoverSoftDeletedKeys: true, RecoverSoftDeletedKeyVaults: true, @@ -523,14 +529,15 @@ func TestExpandFeaturesKeyVault(t *testing.T) { map[string]interface{}{ "key_vault": []interface{}{ map[string]interface{}{ - "purge_soft_deleted_certificates_on_destroy": true, - "purge_soft_deleted_keys_on_destroy": true, - "purge_soft_deleted_secrets_on_destroy": true, - "purge_soft_delete_on_destroy": true, - "recover_soft_deleted_certificates": true, - "recover_soft_deleted_keys": true, - "recover_soft_deleted_key_vaults": true, - "recover_soft_deleted_secrets": true, + "purge_soft_deleted_certificates_on_destroy": true, + "purge_soft_deleted_keys_on_destroy": true, + "purge_soft_deleted_secrets_on_destroy": true, + "purge_soft_deleted_hardware_security_modules_on_destroy": true, + "purge_soft_delete_on_destroy": true, + "recover_soft_deleted_certificates": true, + "recover_soft_deleted_keys": true, + "recover_soft_deleted_key_vaults": true, + "recover_soft_deleted_secrets": true, }, }, }, @@ -540,6 +547,7 @@ func TestExpandFeaturesKeyVault(t *testing.T) { PurgeSoftDeletedCertsOnDestroy: true, PurgeSoftDeletedKeysOnDestroy: true, PurgeSoftDeletedSecretsOnDestroy: true, + PurgeSoftDeletedHSMsOnDestroy: true, PurgeSoftDeleteOnDestroy: true, RecoverSoftDeletedCerts: true, RecoverSoftDeletedKeys: true, @@ -554,14 +562,15 @@ func TestExpandFeaturesKeyVault(t *testing.T) { map[string]interface{}{ "key_vault": []interface{}{ map[string]interface{}{ - "purge_soft_deleted_certificates_on_destroy": false, - "purge_soft_deleted_keys_on_destroy": false, - "purge_soft_deleted_secrets_on_destroy": false, - "purge_soft_delete_on_destroy": false, - "recover_soft_deleted_certificates": false, - "recover_soft_deleted_keys": false, - "recover_soft_deleted_key_vaults": false, - "recover_soft_deleted_secrets": false, + "purge_soft_deleted_certificates_on_destroy": false, + "purge_soft_deleted_keys_on_destroy": false, + "purge_soft_deleted_secrets_on_destroy": false, + "purge_soft_deleted_hardware_security_modules_on_destroy": false, + "purge_soft_delete_on_destroy": false, + "recover_soft_deleted_certificates": false, + "recover_soft_deleted_keys": false, + "recover_soft_deleted_key_vaults": false, + "recover_soft_deleted_secrets": false, }, }, }, @@ -572,6 +581,7 @@ func TestExpandFeaturesKeyVault(t *testing.T) { PurgeSoftDeletedKeysOnDestroy: false, PurgeSoftDeletedSecretsOnDestroy: false, PurgeSoftDeleteOnDestroy: false, + PurgeSoftDeletedHSMsOnDestroy: false, RecoverSoftDeletedCerts: false, RecoverSoftDeletedKeyVaults: false, RecoverSoftDeletedKeys: false, diff --git a/internal/services/keyvault/key_vault_managed_hardware_security_module_resource.go b/internal/services/keyvault/key_vault_managed_hardware_security_module_resource.go index 8f8ebbe94c94..377ca7fe257f 100644 --- a/internal/services/keyvault/key_vault_managed_hardware_security_module_resource.go +++ b/internal/services/keyvault/key_vault_managed_hardware_security_module_resource.go @@ -208,6 +208,16 @@ func resourceArmKeyVaultManagedHardwareSecurityModuleDelete(d *pluginsdk.Resourc return err } + // We need to grab the keyvault hsm to see if purge protection is enabled prior to deletion + resp, err := client.Get(ctx, id.ResourceGroup, id.Name) + if err != nil || resp.Location == nil { + if utils.ResponseWasNotFound(resp.Response) { + return nil + } + + return fmt.Errorf("retrieving %s: %+v", id, err) + } + future, err := client.Delete(ctx, id.ResourceGroup, id.Name) if err != nil { return fmt.Errorf("deleting %s: %+v", id, err) @@ -221,5 +231,23 @@ func resourceArmKeyVaultManagedHardwareSecurityModuleDelete(d *pluginsdk.Resourc "waiting for deletion of API Management Service %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } } + + shouldPurge := meta.(*clients.Client).Features.KeyVault.PurgeSoftDeletedHSMsOnDestroy + if shouldPurge && resp.Properties != nil && utils.NormaliseNilableBool(resp.Properties.EnablePurgeProtection) { + return fmt.Errorf("cannot purge %s because purge protection is enabled", id) + } + + purgeFuture, err := client.PurgeDeleted(ctx, id.Name, *resp.Location) + if err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) + } + + if err = purgeFuture.WaitForCompletionRef(ctx, client.Client); err != nil { + if !response.WasNotFound(future.Response()) { + return fmt.Errorf( + "waiting for purge of %s: %+v", id, err) + } + } + return nil } diff --git a/internal/services/keyvault/key_vault_managed_hardware_security_module_resource_test.go b/internal/services/keyvault/key_vault_managed_hardware_security_module_resource_test.go index 4d3584ce3f2a..2a4515074e5a 100644 --- a/internal/services/keyvault/key_vault_managed_hardware_security_module_resource_test.go +++ b/internal/services/keyvault/key_vault_managed_hardware_security_module_resource_test.go @@ -99,12 +99,13 @@ provider "azurerm" { %s resource "azurerm_key_vault_managed_hardware_security_module" "test" { - name = "kvHsm%d" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - sku_name = "Standard_B1" - tenant_id = data.azurerm_client_config.current.tenant_id - admin_object_ids = [data.azurerm_client_config.current.object_id] + name = "kvHsm%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + sku_name = "Standard_B1" + tenant_id = data.azurerm_client_config.current.tenant_id + admin_object_ids = [data.azurerm_client_config.current.object_id] + purge_protection_enabled = false } `, template, data.RandomInteger) } @@ -140,7 +141,7 @@ resource "azurerm_key_vault_managed_hardware_security_module" "test" { location = azurerm_resource_group.test.location sku_name = "Standard_B1" soft_delete_retention_days = 7 - purge_protection_enabled = true + purge_protection_enabled = false tenant_id = data.azurerm_client_config.current.tenant_id admin_object_ids = [data.azurerm_client_config.current.object_id] diff --git a/website/docs/guides/features-block.html.markdown b/website/docs/guides/features-block.html.markdown index 7e056132c942..717be3774fe5 100644 --- a/website/docs/guides/features-block.html.markdown +++ b/website/docs/guides/features-block.html.markdown @@ -128,6 +128,8 @@ The `key_vault` block supports the following: * `purge_soft_deleted_secrets_on_destroy` - (Optional) Should the `azurerm_key_vault_secret` resource be permanently deleted (e.g. purged) when destroyed? Defaults to `true`. +* `purge_soft_deleted_hardware_security_modules_on_destroy` - (Optional) Should the `azurerm_key_vault_managed_hardware_security_module` resource be permanently deleted (e.g. purged) when destroyed? Defaults to `true`. + * `recover_soft_deleted_certificates` - (Optional) Should the `azurerm_key_vault_certificate` resource recover a Soft-Deleted Certificate? Defaults to `true`. * `recover_soft_deleted_key_vaults` - (Optional) Should the `azurerm_key_vault` resource recover a Soft-Deleted Key Vault? Defaults to `true`.