Skip to content

Commit

Permalink
Add soft deletion retention to KMS key (#5131) (#9911)
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <[email protected]>
  • Loading branch information
modular-magician authored Aug 25, 2021
1 parent 5172787 commit 9cffe88
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/5131.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
kms: added support for `destroy_scheduled_duration` to `google_kms_crypto_key`
```
25 changes: 25 additions & 0 deletions google/resource_kms_crypto_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ Format: ''projects/{{project}}/locations/{{location}}/keyRings/{{keyRing}}''.`,
ForceNew: true,
Description: `The resource name for the CryptoKey.`,
},
"destroy_scheduled_duration": {
Type: schema.TypeString,
Computed: true,
Optional: true,
ForceNew: true,
Description: `The period of time that versions of this key spend in the DESTROY_SCHEDULED state before transitioning to DESTROYED.
If not specified at creation time, the default duration is 24 hours.`,
},
"labels": {
Type: schema.TypeMap,
Optional: true,
Expand Down Expand Up @@ -168,6 +176,12 @@ func resourceKMSCryptoKeyCreate(d *schema.ResourceData, meta interface{}) error
} else if v, ok := d.GetOkExists("version_template"); !isEmptyValue(reflect.ValueOf(versionTemplateProp)) && (ok || !reflect.DeepEqual(v, versionTemplateProp)) {
obj["versionTemplate"] = versionTemplateProp
}
destroyScheduledDurationProp, err := expandKMSCryptoKeyDestroyScheduledDuration(d.Get("destroy_scheduled_duration"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("destroy_scheduled_duration"); !isEmptyValue(reflect.ValueOf(destroyScheduledDurationProp)) && (ok || !reflect.DeepEqual(v, destroyScheduledDurationProp)) {
obj["destroyScheduledDuration"] = destroyScheduledDurationProp
}

obj, err = resourceKMSCryptoKeyEncoder(d, meta, obj)
if err != nil {
Expand Down Expand Up @@ -260,6 +274,9 @@ func resourceKMSCryptoKeyRead(d *schema.ResourceData, meta interface{}) error {
if err := d.Set("version_template", flattenKMSCryptoKeyVersionTemplate(res["versionTemplate"], d, config)); err != nil {
return fmt.Errorf("Error reading CryptoKey: %s", err)
}
if err := d.Set("destroy_scheduled_duration", flattenKMSCryptoKeyDestroyScheduledDuration(res["destroyScheduledDuration"], d, config)); err != nil {
return fmt.Errorf("Error reading CryptoKey: %s", err)
}

return nil
}
Expand Down Expand Up @@ -436,6 +453,10 @@ func flattenKMSCryptoKeyVersionTemplateProtectionLevel(v interface{}, d *schema.
return v
}

func flattenKMSCryptoKeyDestroyScheduledDuration(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}

func expandKMSCryptoKeyLabels(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) {
if v == nil {
return map[string]string{}, nil
Expand Down Expand Up @@ -489,6 +510,10 @@ func expandKMSCryptoKeyVersionTemplateProtectionLevel(v interface{}, d Terraform
return v, nil
}

func expandKMSCryptoKeyDestroyScheduledDuration(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func resourceKMSCryptoKeyEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
// if rotationPeriod is set, nextRotationTime must also be set.
if d.Get("rotation_period") != "" {
Expand Down
66 changes: 66 additions & 0 deletions google/resource_kms_crypto_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,41 @@ func TestAccKmsCryptoKey_template(t *testing.T) {
})
}

func TestAccKmsCryptoKey_destroyDuration(t *testing.T) {
t.Parallel()

projectId := fmt.Sprintf("tf-test-%d", randInt(t))
projectOrg := getTestOrgFromEnv(t)
location := getTestRegionFromEnv()
projectBillingAccount := getTestBillingAccountFromEnv(t)
keyRingName := fmt.Sprintf("tf-test-%s", randString(t, 10))
cryptoKeyName := fmt.Sprintf("tf-test-%s", randString(t, 10))

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testGoogleKmsCryptoKey_destroyDuration(projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName),
},
{
ResourceName: "google_kms_crypto_key.crypto_key",
ImportState: true,
ImportStateVerify: true,
},
// Use a separate TestStep rather than a CheckDestroy because we need the project to still exist.
{
Config: testGoogleKmsCryptoKey_removed(projectId, projectOrg, projectBillingAccount, keyRingName),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleKmsCryptoKeyWasRemovedFromState("google_kms_crypto_key.crypto_key"),
testAccCheckGoogleKmsCryptoKeyVersionsDestroyed(t, projectId, location, keyRingName, cryptoKeyName),
testAccCheckGoogleKmsCryptoKeyRotationDisabled(t, projectId, location, keyRingName, cryptoKeyName),
),
},
},
})
}

// KMS KeyRings cannot be deleted. This ensures that the CryptoKey resource was removed from state,
// even though the server-side resource was not removed.
func testAccCheckGoogleKmsCryptoKeyWasRemovedFromState(resourceName string) resource.TestCheckFunc {
Expand Down Expand Up @@ -502,3 +537,34 @@ resource "google_kms_key_ring" "key_ring" {
}
`, projectId, projectId, projectOrg, projectBillingAccount, keyRingName)
}

func testGoogleKmsCryptoKey_destroyDuration(projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName string) string {
return fmt.Sprintf(`
resource "google_project" "acceptance" {
name = "%s"
project_id = "%s"
org_id = "%s"
billing_account = "%s"
}
resource "google_project_service" "acceptance" {
project = google_project.acceptance.project_id
service = "cloudkms.googleapis.com"
}
resource "google_kms_key_ring" "key_ring" {
project = google_project_service.acceptance.project
name = "%s"
location = "us-central1"
}
resource "google_kms_crypto_key" "crypto_key" {
name = "%s"
key_ring = google_kms_key_ring.key_ring.self_link
labels = {
key = "value"
}
destroy_scheduled_duration = "129600s"
}
`, projectId, projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName)
}
5 changes: 5 additions & 0 deletions website/docs/r/kms_crypto_key.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ The following arguments are supported:
A template describing settings for new crypto key versions.
Structure is documented below.

* `destroy_scheduled_duration` -
(Optional)
The period of time that versions of this key spend in the DESTROY_SCHEDULED state before transitioning to DESTROYED.
If not specified at creation time, the default duration is 24 hours.

* `skip_initial_version_creation` -
(Optional)
If set to true, the request will create a CryptoKey without any CryptoKeyVersions.
Expand Down

0 comments on commit 9cffe88

Please sign in to comment.