Skip to content

Commit

Permalink
Merge pull request #19967 from DrFaust92/r/kms_key_multi
Browse files Browse the repository at this point in the history
r/kms_key - correctly handle `PendingDeletion` state
  • Loading branch information
ewbankkit authored Jul 15, 2021
2 parents 0ff25a2 + 19f18ba commit a265fbd
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 62 deletions.
3 changes: 3 additions & 0 deletions .changelog/19967.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_kms_key: Add plan time validation to `description`.
```
60 changes: 23 additions & 37 deletions aws/resource_aws_kms_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/kms"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand Down Expand Up @@ -40,35 +39,24 @@ func resourceAwsKmsKey() *schema.Resource {
Computed: true,
},
"description": {
Type: schema.TypeString,
Optional: true,
Computed: true,
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringLenBetween(0, 8192),
},
"key_usage": {
Type: schema.TypeString,
Optional: true,
Default: kms.KeyUsageTypeEncryptDecrypt,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{
kms.KeyUsageTypeEncryptDecrypt,
kms.KeyUsageTypeSignVerify,
}, false),
Type: schema.TypeString,
Optional: true,
Default: kms.KeyUsageTypeEncryptDecrypt,
ForceNew: true,
ValidateFunc: validation.StringInSlice(kms.KeyUsageType_Values(), false),
},
"customer_master_key_spec": {
Type: schema.TypeString,
Optional: true,
Default: kms.CustomerMasterKeySpecSymmetricDefault,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{
kms.CustomerMasterKeySpecSymmetricDefault,
kms.CustomerMasterKeySpecRsa2048,
kms.CustomerMasterKeySpecRsa3072,
kms.CustomerMasterKeySpecRsa4096,
kms.CustomerMasterKeySpecEccNistP256,
kms.CustomerMasterKeySpecEccNistP384,
kms.CustomerMasterKeySpecEccNistP521,
kms.CustomerMasterKeySpecEccSecgP256k1,
}, false),
Type: schema.TypeString,
Optional: true,
Default: kms.CustomerMasterKeySpecSymmetricDefault,
ForceNew: true,
ValidateFunc: validation.StringInSlice(kms.CustomerMasterKeySpec_Values(), false),
},
"policy": {
Type: schema.TypeString,
Expand Down Expand Up @@ -210,7 +198,7 @@ func resourceAwsKmsKeyRead(d *schema.ResourceData, meta interface{}) error {
p := pOut.(*kms.GetKeyPolicyOutput)
policy, err := structure.NormalizeJsonString(*p.Policy)
if err != nil {
return fmt.Errorf("policy contains an invalid JSON: %s", err)
return fmt.Errorf("policy contains an invalid JSON: %w", err)
}
d.Set("policy", policy)

Expand Down Expand Up @@ -246,7 +234,7 @@ func resourceAwsKmsKeyRead(d *schema.ResourceData, meta interface{}) error {
}

if err != nil {
return fmt.Errorf("error listing tags for KMS Key (%s): %s", d.Id(), err)
return fmt.Errorf("error listing tags for KMS Key (%s): %w", d.Id(), err)
}

tags = tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig)
Expand Down Expand Up @@ -302,7 +290,7 @@ func resourceAwsKmsKeyUpdate(d *schema.ResourceData, meta interface{}) error {
o, n := d.GetChange("tags_all")

if err := keyvaluetags.KmsUpdateTags(conn, d.Id(), o, n); err != nil {
return fmt.Errorf("error updating KMS Key (%s) tags: %s", d.Id(), err)
return fmt.Errorf("error updating KMS Key (%s) tags: %w", d.Id(), err)
}
}

Expand All @@ -327,7 +315,7 @@ func resourceAwsKmsKeyDescriptionUpdate(conn *kms.KMS, d *schema.ResourceData) e
func resourceAwsKmsKeyPolicyUpdate(conn *kms.KMS, d *schema.ResourceData) error {
policy, err := structure.NormalizeJsonString(d.Get("policy").(string))
if err != nil {
return fmt.Errorf("policy contains an invalid JSON: %s", err)
return fmt.Errorf("policy contains an invalid JSON: %w", err)
}
keyId := d.Get("key_id").(string)

Expand Down Expand Up @@ -377,8 +365,7 @@ func updateKmsKeyStatus(conn *kms.KMS, id string, shouldBeEnabled bool) error {
KeyId: aws.String(id),
})
if err != nil {
awsErr, ok := err.(awserr.Error)
if ok && awsErr.Code() == "NotFoundException" {
if isAWSErr(err, kms.ErrCodeNotFoundException, "") {
return nil, fmt.Sprintf("%t", !shouldBeEnabled), nil
}
return resp, "FAILED", err
Expand All @@ -392,7 +379,7 @@ func updateKmsKeyStatus(conn *kms.KMS, id string, shouldBeEnabled bool) error {

_, err = wait.WaitForState()
if err != nil {
return fmt.Errorf("Failed setting KMS key status to %t: %s", shouldBeEnabled, err)
return fmt.Errorf("Failed setting KMS key status to %t: %w", shouldBeEnabled, err)
}

return nil
Expand All @@ -405,11 +392,10 @@ func updateKmsKeyRotationStatus(conn *kms.KMS, d *schema.ResourceData) error {
err := handleKeyRotation(conn, shouldEnableRotation, aws.String(d.Id()))

if err != nil {
awsErr, ok := err.(awserr.Error)
if ok && awsErr.Code() == "DisabledException" {
if isAWSErr(err, kms.ErrCodeDisabledException, "") {
return resource.RetryableError(err)
}
if ok && awsErr.Code() == "NotFoundException" {
if isAWSErr(err, kms.ErrCodeNotFoundException, "") {
return resource.RetryableError(err)
}

Expand Down Expand Up @@ -438,7 +424,7 @@ func updateKmsKeyRotationStatus(conn *kms.KMS, d *schema.ResourceData) error {
log.Printf("[DEBUG] Checking if KMS key %s rotation status is %t",
d.Id(), shouldEnableRotation)

out, err := retryOnAwsCode("NotFoundException", func() (interface{}, error) {
out, err := retryOnAwsCode(kms.ErrCodeNotFoundException, func() (interface{}, error) {
return conn.GetKeyRotationStatus(&kms.GetKeyRotationStatusInput{
KeyId: aws.String(d.Id()),
})
Expand Down
39 changes: 15 additions & 24 deletions aws/resource_aws_kms_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,34 +23,37 @@ func init() {
func testSweepKmsKeys(region string) error {
client, err := sharedClientForRegion(region)
if err != nil {
return fmt.Errorf("error getting client: %s", err)
return fmt.Errorf("error getting client: %w", err)
}
conn := client.(*AWSClient).kmsconn

err = conn.ListKeysPages(&kms.ListKeysInput{Limit: aws.Int64(int64(1000))}, func(out *kms.ListKeysOutput, lastPage bool) bool {
for _, k := range out.Keys {
kKeyId := aws.StringValue(k.KeyId)
kOut, err := conn.DescribeKey(&kms.DescribeKeyInput{
KeyId: k.KeyId,
})
if err != nil {
log.Printf("Error: Failed to describe key %q: %s", *k.KeyId, err)
log.Printf("Error: Failed to describe key %q: %s", kKeyId, err)
return false
}
if *kOut.KeyMetadata.KeyManager == kms.KeyManagerTypeAws {
if aws.StringValue(kOut.KeyMetadata.KeyManager) == kms.KeyManagerTypeAws {
// Skip (default) keys which are managed by AWS
continue
}
if *kOut.KeyMetadata.KeyState == kms.KeyStatePendingDeletion {
if aws.StringValue(kOut.KeyMetadata.KeyState) == kms.KeyStatePendingDeletion {
// Skip keys which are already scheduled for deletion
continue
}

_, err = conn.ScheduleKeyDeletion(&kms.ScheduleKeyDeletionInput{
KeyId: k.KeyId,
PendingWindowInDays: aws.Int64(int64(7)),
})
r := resourceAwsKmsKey()
d := r.Data(nil)
d.SetId(kKeyId)
d.Set("key_id", kKeyId)
d.Set("deletion_window_in_days", "7")
err = r.Delete(d, client)
if err != nil {
log.Printf("Error: Failed to schedule key %q for deletion: %s", *k.KeyId, err)
log.Printf("Error: Failed to schedule key %q for deletion: %s", kKeyId, err)
return false
}
}
Expand All @@ -61,7 +64,7 @@ func testSweepKmsKeys(region string) error {
log.Printf("[WARN] Skipping KMS Key sweep for %s: %s", region, err)
return nil
}
return fmt.Errorf("Error describing KMS keys: %s", err)
return fmt.Errorf("Error describing KMS keys: %w", err)
}

return nil
Expand All @@ -84,6 +87,7 @@ func TestAccAWSKmsKey_basic(t *testing.T) {
testAccCheckAWSKmsKeyExists(resourceName, &key),
resource.TestCheckResourceAttr(resourceName, "customer_master_key_spec", "SYMMETRIC_DEFAULT"),
resource.TestCheckResourceAttr(resourceName, "key_usage", "ENCRYPT_DECRYPT"),
resource.TestCheckResourceAttr(resourceName, "tags.%", "0"),
),
},
{
Expand Down Expand Up @@ -134,7 +138,7 @@ func TestAccAWSKmsKey_disappears(t *testing.T) {
Config: testAccAWSKmsKey(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSKmsKeyExists(resourceName, &key),
testAccCheckAWSKmsKeyDisappears(&key),
testAccCheckResourceDisappears(testAccProvider, resourceAwsKmsKey(), resourceName),
),
ExpectNonEmptyPlan: true,
},
Expand Down Expand Up @@ -417,19 +421,6 @@ func testAccCheckAWSKmsKeyIsEnabled(key *kms.KeyMetadata, isEnabled bool) resour
}
}

func testAccCheckAWSKmsKeyDisappears(key *kms.KeyMetadata) resource.TestCheckFunc {
return func(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).kmsconn

_, err := conn.ScheduleKeyDeletion(&kms.ScheduleKeyDeletionInput{
KeyId: key.KeyId,
PendingWindowInDays: aws.Int64(int64(7)),
})

return err
}
}

func testAccAWSKmsKey(rName string) string {
return fmt.Sprintf(`
resource "aws_kms_key" "test" {
Expand Down
2 changes: 1 addition & 1 deletion website/docs/r/kms_key.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ description: |-

# Resource: aws_kms_key

Provides a KMS customer master key.
Provides a KMS single-Region customer master key (CMK).

## Example Usage

Expand Down

0 comments on commit a265fbd

Please sign in to comment.