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

Enhancement: azurerm_key_vault: Add support for soft delete, purge protection, and purge on destroy #5344

Merged
merged 40 commits into from
Feb 21, 2020
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
39fb80f
Key Vault: support for soft delete
WodansSon Jan 8, 2020
beafb4c
fix lint errors
WodansSon Jan 8, 2020
70a6a18
Update website/docs/r/key_vault.html.markdown
WodansSon Jan 23, 2020
22701db
Update website/docs/r/key_vault.html.markdown
WodansSon Jan 23, 2020
50563f8
Update azurerm/internal/services/keyvault/resource_arm_key_vault.go
WodansSon Jan 23, 2020
872984b
Merge branch 'master' of https://github.com/terraform-providers/terra…
WodansSon Jan 23, 2020
68f55a9
WIP Get value from provider
WodansSon Feb 1, 2020
e424d9a
Merge branch 'master' of https://github.com/terraform-providers/terra…
WodansSon Feb 3, 2020
924c38a
Done except for purge on destroy
WodansSon Feb 4, 2020
0f89dbd
Working soft delete and purge
WodansSon Feb 6, 2020
023aa56
Complete
WodansSon Feb 7, 2020
7b9909c
updated or to and
WodansSon Feb 7, 2020
96a36df
Fix features test cases
WodansSon Feb 7, 2020
3912093
Removed sku support from datasource
WodansSon Feb 7, 2020
b02dd08
Add code to skip purge if not soft deleted
WodansSon Feb 7, 2020
d1dc823
Merge branch 'e_keyvault_puge_softdelete' of https://github.com/terra…
WodansSon Feb 7, 2020
96f858a
Remove depricated sku from tests
WodansSon Feb 8, 2020
b8c1418
Fix basic test
WodansSon Feb 8, 2020
abd8429
Fix test case lint issue
WodansSon Feb 8, 2020
38848cf
Merge branch 'master' into e_keyvault_puge_softdelete
WodansSon Feb 12, 2020
f00d8f4
Merge branch 'master' into e_keyvault_puge_softdelete
WodansSon Feb 18, 2020
7f48f3a
Update test cases
WodansSon Feb 18, 2020
94dfc85
Fix test case
WodansSon Feb 19, 2020
0cd0b77
Merge branch 'master' of https://github.com/terraform-providers/terra…
WodansSon Feb 19, 2020
6c5e904
validate: removing the bool validators
tombuildsstuff Feb 20, 2020
76babfa
(d|r)/key_vault: moving the name validation into that package
tombuildsstuff Feb 20, 2020
d38b743
r/key_vault: moving the migration code closer to the package
tombuildsstuff Feb 20, 2020
586901d
r/key_vault: handling conditionally updating the key vault resource
tombuildsstuff Feb 20, 2020
872de6b
r/key_vault: updating the docs
tombuildsstuff Feb 20, 2020
d2cd248
minor: committing some lingering test files
tombuildsstuff Feb 20, 2020
31f5a73
Start adding purge on destroy back in
WodansSon Feb 20, 2020
6a7b3e5
Added Purge on Destroy back in
WodansSon Feb 21, 2020
a349df8
r/key_vault: fixing up the tests
tombuildsstuff Feb 21, 2020
300e2c2
Merge branch 'e_keyvault_puge_softdelete' of github.com:terraform-pro…
tombuildsstuff Feb 21, 2020
3a222df
r/key_vault: outputting a warning rather than an error during the delete
tombuildsstuff Feb 21, 2020
e85e4d1
r/key_vault: updating the docs
tombuildsstuff Feb 21, 2020
5cc9062
r/key_vault: removing a superflurious if statement
tombuildsstuff Feb 21, 2020
dc7b871
r/keyvault: removing dead code
tombuildsstuff Feb 21, 2020
415d4fd
r/keyvault: fixing the soft delete disabled test
tombuildsstuff Feb 21, 2020
7bf15ef
linting
tombuildsstuff Feb 21, 2020
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
45 changes: 45 additions & 0 deletions azurerm/helpers/azure/key_vault.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package azure
import (
"context"
"fmt"
"time"

"github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2018-02-14/keyvault"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

Expand Down Expand Up @@ -118,3 +120,46 @@ func KeyVaultExists(ctx context.Context, client *keyvault.VaultsClient, keyVault

return true, nil
}

func KeyVaultCustomizeDiff(d *schema.ResourceDiff, _ interface{}) error {
if d.HasChange("soft_delete_enabled") {
if old, new := d.GetChange("soft_delete_enabled"); old.(bool) && !new.(bool) {
return fmt.Errorf("the property 'soft_delete_enabled' cannot be set to false, enabling the soft delete for a vault is an irreversible action")
}
}

if d.HasChange("purge_protection_enabled") {
if old, new := d.GetChange("purge_protection_enabled"); old.(bool) && !new.(bool) {
return fmt.Errorf("the property 'purge_protection_enabled' cannot be set to false, enabling the purge protection for a vault is an irreversible action")
}
}

return nil
}
tombuildsstuff marked this conversation as resolved.
Show resolved Hide resolved

func KeyVaultGetSoftDeletedState(ctx context.Context, client *keyvault.VaultsClient, name string, location string) (deleteDate interface{}, purgeDate interface{}, err error) {
softDel, err := client.GetDeleted(ctx, name, location)
if err != nil {
return nil, nil, fmt.Errorf("unable to get soft delete state information: %+v", err)
}

// the logic is this way because the GetDeleted call will return an existing key vault
// that is not soft deleted, but the Deleted Vault properties will be nil
if props := softDel.Properties; props != nil {
var delDate interface{}
var purgeDate interface{}

if dd := props.DeletionDate; dd != nil {
delDate = (*dd).Format(time.RFC3339)
}
if pg := props.ScheduledPurgeDate; pg != nil {
purgeDate = (*pg).Format(time.RFC3339)
}
if delDate != nil && purgeDate != nil {
return delDate, purgeDate, nil
}
}

// this means we found an existing key vault that is not soft deleted
return nil, nil, nil
}
23 changes: 23 additions & 0 deletions azurerm/helpers/validate/bool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package validate

import (
"fmt"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func BoolIsTrue() schema.SchemaValidateFunc {
tombuildsstuff marked this conversation as resolved.
Show resolved Hide resolved
return func(i interface{}, k string) (_ []string, errors []error) {
v, ok := i.(bool)
if !ok {
errors = append(errors, fmt.Errorf("expected type of %q to be bool", k))
return
}

if !v {
errors = append(errors, fmt.Errorf("%q can only be set to true, if not required remove key", k))
return
}
return
}
}
35 changes: 35 additions & 0 deletions azurerm/helpers/validate/bool_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package validate

import "testing"

func TestBoolIsTrue(t *testing.T) {
tombuildsstuff marked this conversation as resolved.
Show resolved Hide resolved
testCases := []struct {
Value bool
ShouldHaveError bool
}{
{
Value: true,
ShouldHaveError: false,
}, {
Value: false,
ShouldHaveError: true,
},
}

t.Run("TestBoolIsTrue", func(t *testing.T) {
for _, value := range testCases {
_, errors := BoolIsTrue()(value.Value, "dummy")
hasErrors := len(errors) > 0

if value.ShouldHaveError && !hasErrors {
t.Fatalf("Expected an error but didn't get one for %t", value.Value)
return
}

if !value.ShouldHaveError && hasErrors {
t.Fatalf("Expected %t to return no errors, but got some %+v", value.Value, errors)
return
}
}
})
}
5 changes: 5 additions & 0 deletions azurerm/internal/features/user_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package features
type UserFeatures struct {
VirtualMachine VirtualMachineFeatures
VirtualMachineScaleSet VirtualMachineScaleSetFeatures
KeyVault KeyVaultFeatures
}

type VirtualMachineFeatures struct {
Expand All @@ -12,3 +13,7 @@ type VirtualMachineFeatures struct {
type VirtualMachineScaleSetFeatures struct {
RollInstancesWhenRequired bool
}

type KeyVaultFeatures struct {
PurgeSoftDeleteOnDestroy bool
}
27 changes: 27 additions & 0 deletions azurerm/internal/provider/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@ func schemaFeatures() *schema.Schema {
},
},
},

"key_vault": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"purge_soft_delete_on_destroy": {
Type: schema.TypeBool,
Required: true,
},
},
},
},
}

runningAcceptanceTests := os.Getenv("TF_ACC") != ""
Expand Down Expand Up @@ -70,6 +84,9 @@ func expandFeatures(input []interface{}) features.UserFeatures {
VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{
RollInstancesWhenRequired: true,
},
KeyVault: features.KeyVaultFeatures{
PurgeSoftDeleteOnDestroy: true,
},
}

if len(input) == 0 || input[0] == nil {
Expand Down Expand Up @@ -98,5 +115,15 @@ func expandFeatures(input []interface{}) features.UserFeatures {
}
}

if raw, ok := val["key_vault"]; ok {
items := raw.([]interface{})
if len(items) > 0 {
keyVaultRaw := items[0].(map[string]interface{})
if v, ok := keyVaultRaw["purge_soft_delete_on_destroy"]; ok {
features.KeyVault.PurgeSoftDeleteOnDestroy = v.(bool)
}
}
}

return features
}
111 changes: 110 additions & 1 deletion azurerm/internal/provider/features_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@ func TestExpandFeatures(t *testing.T) {
VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{
RollInstancesWhenRequired: true,
},
KeyVault: features.KeyVaultFeatures{
PurgeSoftDeleteOnDestroy: true,
},
},
},
{
Name: "Complete",
Name: "Complete Enabled",
Input: []interface{}{
map[string]interface{}{
"virtual_machine": []interface{}{
Expand All @@ -40,6 +43,11 @@ func TestExpandFeatures(t *testing.T) {
"roll_instances_when_required": true,
},
},
"key_vault": []interface{}{
map[string]interface{}{
"purge_soft_delete_on_destroy": true,
},
},
},
},
Expected: features.UserFeatures{
Expand All @@ -49,6 +57,42 @@ func TestExpandFeatures(t *testing.T) {
VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{
RollInstancesWhenRequired: true,
},
KeyVault: features.KeyVaultFeatures{
PurgeSoftDeleteOnDestroy: true,
},
},
},
{
Name: "Complete Disabled",
Input: []interface{}{
map[string]interface{}{
"virtual_machine": []interface{}{
map[string]interface{}{
"delete_os_disk_on_deletion": false,
},
},
"virtual_machine_scale_set": []interface{}{
map[string]interface{}{
"roll_instances_when_required": false,
},
},
"key_vault": []interface{}{
map[string]interface{}{
"purge_soft_delete_on_destroy": false,
},
},
},
},
Expected: features.UserFeatures{
VirtualMachine: features.VirtualMachineFeatures{
DeleteOSDiskOnDeletion: false,
},
VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{
RollInstancesWhenRequired: false,
},
KeyVault: features.KeyVaultFeatures{
PurgeSoftDeleteOnDestroy: false,
},
},
},
}
Expand All @@ -62,6 +106,71 @@ func TestExpandFeatures(t *testing.T) {
}
}

func TestExpandFeaturesKeyVault(t *testing.T) {
testData := []struct {
Name string
Input []interface{}
EnvVars map[string]interface{}
Expected features.UserFeatures
}{
{
Name: "Empty Block",
Input: []interface{}{
map[string]interface{}{
"key_vault": []interface{}{},
},
},
Expected: features.UserFeatures{
KeyVault: features.KeyVaultFeatures{
PurgeSoftDeleteOnDestroy: true,
},
},
},
{
Name: "Purge Soft Delete On Destroy Enabled",
Input: []interface{}{
map[string]interface{}{
"key_vault": []interface{}{
map[string]interface{}{
"purge_soft_delete_on_destroy": true,
},
},
},
},
Expected: features.UserFeatures{
KeyVault: features.KeyVaultFeatures{
PurgeSoftDeleteOnDestroy: true,
},
},
},
{
Name: "Purge Soft Delete On Destroy Disabled",
Input: []interface{}{
map[string]interface{}{
"key_vault": []interface{}{
map[string]interface{}{
"purge_soft_delete_on_destroy": false,
},
},
},
},
Expected: features.UserFeatures{
KeyVault: features.KeyVaultFeatures{
PurgeSoftDeleteOnDestroy: false,
},
},
},
}

for _, testCase := range testData {
t.Logf("[DEBUG] Test Case: %q", testCase.Name)
result := expandFeatures(testCase.Input)
if !reflect.DeepEqual(result.KeyVault, testCase.Expected.KeyVault) {
t.Fatalf("Expected %+v but got %+v", result.KeyVault, testCase.Expected.KeyVault)
}
}
}

func TestExpandFeaturesVirtualMachine(t *testing.T) {
testData := []struct {
Name string
Expand Down
12 changes: 12 additions & 0 deletions azurerm/internal/services/keyvault/data_source_key_vault.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,16 @@ func dataSourceArmKeyVault() *schema.Resource {
},
},

"purge_protection_enabled": {
Type: schema.TypeBool,
Computed: true,
},

"soft_delete_enabled": {
Type: schema.TypeBool,
Computed: true,
},

"tags": tags.SchemaDataSource(),
},
}
Expand Down Expand Up @@ -175,6 +185,8 @@ func dataSourceArmKeyVaultRead(d *schema.ResourceData, meta interface{}) error {
d.Set("enabled_for_deployment", props.EnabledForDeployment)
d.Set("enabled_for_disk_encryption", props.EnabledForDiskEncryption)
d.Set("enabled_for_template_deployment", props.EnabledForTemplateDeployment)
d.Set("soft_delete_enabled", props.EnableSoftDelete)
d.Set("purge_protection_enabled", props.EnablePurgeProtection)
d.Set("vault_uri", props.VaultURI)

if sku := props.Sku; sku != nil {
Expand Down
Loading