Skip to content

Commit f306b84

Browse files
modular-magicianemilymye
authored andcommitted
Make sure KMS key "deletion" disables rotation (#3624)
Signed-off-by: Modular Magician <[email protected]>
1 parent 0149d37 commit f306b84

File tree

2 files changed

+57
-21
lines changed

2 files changed

+57
-21
lines changed

google/resource_kms_crypto_key.go

+26-8
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,24 @@ func clearCryptoKeyVersions(cryptoKeyId *kmsCryptoKeyId, config *Config) error {
224224
return nil
225225
}
226226

227-
/*
228-
Because KMS CryptoKey resources cannot be deleted on GCP, we are only going to remove it from state
229-
and destroy all its versions, rendering the key useless for encryption and decryption of data.
230-
Re-creation of this resource through Terraform will produce an error.
231-
*/
227+
func disableCryptoKeyRotation(cryptoKeyId *kmsCryptoKeyId, config *Config) error {
228+
keyClient := config.clientKms.Projects.Locations.KeyRings.CryptoKeys
229+
_, err := keyClient.Patch(cryptoKeyId.cryptoKeyId(), &cloudkms.CryptoKey{
230+
NullFields: []string{"rotationPeriod", "nextRotationTime"},
231+
}).
232+
UpdateMask("rotationPeriod,nextRotationTime").Do()
233+
234+
return err
235+
}
232236

237+
// Because KMS CryptoKey keys cannot be deleted (in GCP proper), we "delete"
238+
// the key ring by
239+
// a) marking all key versions for destruction (24hr soft-delete)
240+
// b) disabling rotation of the key
241+
// c) removing it from state
242+
// This disables all usage of previous versions of the key and makes it
243+
// generally useless for encryption and decryption of data.
244+
// Re-creation of this resource through Terraform will produce an error.
233245
func resourceKmsCryptoKeyDelete(d *schema.ResourceData, meta interface{}) error {
234246
config := meta.(*Config)
235247

@@ -242,12 +254,18 @@ func resourceKmsCryptoKeyDelete(d *schema.ResourceData, meta interface{}) error
242254
[WARNING] KMS CryptoKey resources cannot be deleted from GCP. The CryptoKey %s will be removed from Terraform state,
243255
and all its CryptoKeyVersions will be destroyed, but it will still be present on the server.`, cryptoKeyId.cryptoKeyId())
244256

245-
err = clearCryptoKeyVersions(cryptoKeyId, config)
246-
247-
if err != nil {
257+
// Delete all versions of the key
258+
if err := clearCryptoKeyVersions(cryptoKeyId, config); err != nil {
248259
return err
249260
}
250261

262+
// Make sure automatic key rotation is disabled.
263+
if err := disableCryptoKeyRotation(cryptoKeyId, config); err != nil {
264+
return fmt.Errorf(
265+
"While cryptoKeyVersions were cleared, Terraform was unable to disable automatic rotation of key due to an error: %s."+
266+
"Please retry or manually disable automatic rotation to prevent creation of a new version of this key.", err)
267+
}
268+
251269
d.SetId("")
252270
return nil
253271
}

google/resource_kms_crypto_key_test.go

+31-13
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ func TestAccKmsCryptoKey_basic(t *testing.T) {
137137
Check: resource.ComposeTestCheckFunc(
138138
testAccCheckGoogleKmsCryptoKeyWasRemovedFromState("google_kms_crypto_key.crypto_key"),
139139
testAccCheckGoogleKmsCryptoKeyVersionsDestroyed(projectId, location, keyRingName, cryptoKeyName),
140+
testAccCheckGoogleKmsCryptoKeyRotationDisabled(projectId, location, keyRingName, cryptoKeyName),
140141
),
141142
},
142143
},
@@ -189,16 +190,15 @@ func TestAccKmsCryptoKey_rotation(t *testing.T) {
189190
Check: resource.ComposeTestCheckFunc(
190191
testAccCheckGoogleKmsCryptoKeyWasRemovedFromState("google_kms_crypto_key.crypto_key"),
191192
testAccCheckGoogleKmsCryptoKeyVersionsDestroyed(projectId, location, keyRingName, cryptoKeyName),
193+
testAccCheckGoogleKmsCryptoKeyRotationDisabled(projectId, location, keyRingName, cryptoKeyName),
192194
),
193195
},
194196
},
195197
})
196198
}
197199

198-
/*
199-
KMS KeyRings cannot be deleted. This ensures that the CryptoKey resource was removed from state,
200-
even though the server-side resource was not removed.
201-
*/
200+
// KMS KeyRings cannot be deleted. This ensures that the CryptoKey resource was removed from state,
201+
// even though the server-side resource was not removed.
202202
func testAccCheckGoogleKmsCryptoKeyWasRemovedFromState(resourceName string) resource.TestCheckFunc {
203203
return func(s *terraform.State) error {
204204
_, ok := s.RootModule().Resources[resourceName]
@@ -211,11 +211,8 @@ func testAccCheckGoogleKmsCryptoKeyWasRemovedFromState(resourceName string) reso
211211
}
212212
}
213213

214-
/*
215-
KMS KeyRings cannot be deleted. This ensures that the CryptoKey resource's CryptoKeyVersion
216-
sub-resources were scheduled to be destroyed, rendering the key itself inoperable.
217-
*/
218-
214+
// KMS KeyRings cannot be deleted. This ensures that the CryptoKey resource's CryptoKeyVersion
215+
// sub-resources were scheduled to be destroyed, rendering the key itself inoperable.
219216
func testAccCheckGoogleKmsCryptoKeyVersionsDestroyed(projectId, location, keyRingName, cryptoKeyName string) resource.TestCheckFunc {
220217
return func(_ *terraform.State) error {
221218
config := testAccProvider.Meta().(*Config)
@@ -239,10 +236,31 @@ func testAccCheckGoogleKmsCryptoKeyVersionsDestroyed(projectId, location, keyRin
239236
}
240237
}
241238

242-
/*
243-
This test runs in its own project, otherwise the test project would start to get filled
244-
with undeletable resources
245-
*/
239+
// KMS KeyRings cannot be deleted. This ensures that the CryptoKey autorotation
240+
// was disabled to prevent more versions of the key from being created.
241+
func testAccCheckGoogleKmsCryptoKeyRotationDisabled(projectId, location, keyRingName, cryptoKeyName string) resource.TestCheckFunc {
242+
return func(_ *terraform.State) error {
243+
config := testAccProvider.Meta().(*Config)
244+
gcpResourceUri := fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", projectId, location, keyRingName, cryptoKeyName)
245+
246+
response, err := config.clientKms.Projects.Locations.KeyRings.CryptoKeys.Get(gcpResourceUri).Do()
247+
if err != nil {
248+
return fmt.Errorf("Unexpected failure while verifying 'deleted' crypto key: %s", err)
249+
}
250+
251+
if response.NextRotationTime != "" {
252+
return fmt.Errorf("Expected empty nextRotationTime for 'deleted' crypto key, got %s", response.NextRotationTime)
253+
}
254+
if response.RotationPeriod != "" {
255+
return fmt.Errorf("Expected empty RotationPeriod for 'deleted' crypto key, got %s", response.RotationPeriod)
256+
}
257+
258+
return nil
259+
}
260+
}
261+
262+
// This test runs in its own project, otherwise the test project would start to get filled
263+
// with undeletable resources
246264
func testGoogleKmsCryptoKey_basic(projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName string) string {
247265
return fmt.Sprintf(`
248266
resource "google_project" "acceptance" {

0 commit comments

Comments
 (0)