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

resource/aws_kms_grant: Support operations on asymmetric keys #17836

Merged
merged 2 commits into from
Mar 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .changelog/17836.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
resource/aws_kms_grant: Adds support for operations on asymmetric keys
```
34 changes: 9 additions & 25 deletions aws/resource_aws_kms_grant.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,8 @@ func resourceAwsKmsGrant() *schema.Resource {
Type: schema.TypeSet,
Set: schema.HashString,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice([]string{
kms.GrantOperationCreateGrant,
kms.GrantOperationDecrypt,
kms.GrantOperationDescribeKey,
kms.GrantOperationEncrypt,
kms.GrantOperationGenerateDataKey,
kms.GrantOperationGenerateDataKeyWithoutPlaintext,
kms.GrantOperationReEncryptFrom,
kms.GrantOperationReEncryptTo,
kms.GrantOperationRetireGrant,
}, false),
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice(kms.GrantOperation_Values(), false),
},
Required: true,
ForceNew: true,
Expand Down Expand Up @@ -155,8 +145,6 @@ func resourceAwsKmsGrantCreate(d *schema.ResourceData, meta interface{}) error {
input.GrantTokens = expandStringSet(v.(*schema.Set))
}

log.Printf("[DEBUG]: Adding new KMS Grant: %s", input)

var out *kms.CreateGrantOutput

err := resource.Retry(3*time.Minute, func() *resource.RetryError {
Expand All @@ -171,10 +159,8 @@ func resourceAwsKmsGrantCreate(d *schema.ResourceData, meta interface{}) error {
isAWSErr(err, kms.ErrCodeInternalException, "") ||
isAWSErr(err, kms.ErrCodeInvalidArnException, "") {
return resource.RetryableError(
fmt.Errorf("Error adding new KMS Grant for key: %s, retrying %s",
*input.KeyId, err))
fmt.Errorf("error creating KMS Grant for Key (%s), retrying: %w", keyId, err))
}
log.Printf("[ERROR] An error occurred creating new AWS KMS Grant: %s", err)
return resource.NonRetryableError(err)
}
return nil
Expand All @@ -185,11 +171,10 @@ func resourceAwsKmsGrantCreate(d *schema.ResourceData, meta interface{}) error {
}

if err != nil {
return fmt.Errorf("Error creating KMS grant: %s", err)
return fmt.Errorf("error creating KMS Grant for Key (%s): %w", keyId, err)
}

log.Printf("[DEBUG] Created new KMS Grant: %s", *out.GrantId)
d.SetId(fmt.Sprintf("%s:%s", keyId, *out.GrantId))
d.SetId(fmt.Sprintf("%s:%s", keyId, aws.StringValue(out.GrantId)))
d.Set("grant_id", out.GrantId)
d.Set("grant_token", out.GrantToken)

Expand All @@ -204,20 +189,19 @@ func resourceAwsKmsGrantRead(d *schema.ResourceData, meta interface{}) error {
return err
}

log.Printf("[DEBUG] Looking for grant id: %s", grantId)
grant, err := findKmsGrantByIdWithRetry(conn, keyId, grantId)

if err != nil {
if isResourceNotFoundError(err) {
log.Printf("[WARN] %s KMS grant id not found for key id %s, removing from state file", grantId, keyId)
log.Printf("[WARN] KMS Grant (%s) not found for Key (%s), removing from state file", grantId, keyId)
d.SetId("")
return nil
}
return err
}

if grant == nil {
log.Printf("[WARN] %s KMS grant id not found for key id %s, removing from state file", grantId, keyId)
log.Printf("[WARN] KMS Grant (%s) not found for Key (%s), removing from state file", grantId, keyId)
d.SetId("")
return nil
}
Expand Down Expand Up @@ -245,7 +229,7 @@ func resourceAwsKmsGrantRead(d *schema.ResourceData, meta interface{}) error {
if err := d.Set("operations", aws.StringValueSlice(grant.Operations)); err != nil {
log.Printf("[DEBUG] Error setting operations for grant %s with error %s", grantId, err)
}
if *grant.Name != "" {
if aws.StringValue(grant.Name) != "" {
d.Set("name", grant.Name)
}
if grant.Constraints != nil {
Expand Down Expand Up @@ -402,7 +386,7 @@ func findKmsGrantById(conn *kms.KMS, keyId string, grantId string, marker *strin
}

if err != nil {
return nil, fmt.Errorf("error listing KMS Grants: %s", err)
return nil, fmt.Errorf("error listing KMS Grants: %w", err)
}

grant = getKmsGrantById(out.Grants, grantId)
Expand Down
62 changes: 62 additions & 0 deletions aws/resource_aws_kms_grant_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,31 @@ func TestAccAWSKmsGrant_ARN(t *testing.T) {
})
}

func TestAccAWSKmsGrant_AsymmetricKey(t *testing.T) {
resourceName := "aws_kms_grant.test"
rName := acctest.RandomWithPrefix("tf-acc-test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSKmsGrantDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSKmsGrant_AsymmetricKey(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSKmsGrantExists(resourceName),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"grant_token", "retire_on_delete"},
},
},
})
}

func TestAccAWSKmsGrant_disappears(t *testing.T) {
resourceName := "aws_kms_grant.test"
rName := acctest.RandomWithPrefix("tf-acc-test")
Expand Down Expand Up @@ -327,3 +352,40 @@ resource "aws_kms_grant" "test" {
}
`, rName, operations)
}

func testAccAWSKmsGrant_AsymmetricKey(rName string) string {
return fmt.Sprintf(`
resource "aws_kms_grant" "test" {
name = "%[1]s"
key_id = aws_kms_key.test.key_id
grantee_principal = aws_iam_role.test.arn
operations = ["GetPublicKey", "Sign", "Verify"]
}

resource "aws_kms_key" "test" {
description = "Terraform acc test key %[1]s"
deletion_window_in_days = 7

key_usage = "SIGN_VERIFY"
customer_master_key_spec = "RSA_2048"
}

data "aws_iam_policy_document" "test" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]

principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
}
}

resource "aws_iam_role" "test" {
name = %[1]q
path = "/service-role/"
assume_role_policy = data.aws_iam_policy_document.test.json
}
`, rName)
}
2 changes: 1 addition & 1 deletion website/docs/r/kms_grant.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ The following arguments are supported:
* `name` - (Optional, Forces new resources) A friendly name for identifying the grant.
* `key_id` - (Required, Forces new resources) The unique identifier for the customer master key (CMK) that the grant applies to. Specify the key ID or the Amazon Resource Name (ARN) of the CMK. To specify a CMK in a different AWS account, you must use the key ARN.
* `grantee_principal` - (Required, Forces new resources) The principal that is given permission to perform the operations that the grant permits in ARN format. Note that due to eventual consistency issues around IAM principals, terraform's state may not always be refreshed to reflect what is true in AWS.
* `operations` - (Required, Forces new resources) A list of operations that the grant permits. The permitted values are: `Decrypt, Encrypt, GenerateDataKey, GenerateDataKeyWithoutPlaintext, ReEncryptFrom, ReEncryptTo, CreateGrant, RetireGrant, DescribeKey`
* `operations` - (Required, Forces new resources) A list of operations that the grant permits. The permitted values are: `Decrypt`, `Encrypt`, `GenerateDataKey`, `GenerateDataKeyWithoutPlaintext`, `ReEncryptFrom`, `ReEncryptTo`, `Sign`, `Verify`, `GetPublicKey`, `CreateGrant`, `RetireGrant`, `DescribeKey`, `GenerateDataKeyPair`, or `GenerateDataKeyPairWithoutPlaintext`.
* `retiring_principal` - (Optional, Forces new resources) The principal that is given permission to retire the grant by using RetireGrant operation in ARN format. Note that due to eventual consistency issues around IAM principals, terraform's state may not always be refreshed to reflect what is true in AWS.
* `constraints` - (Optional, Forces new resources) A structure that you can use to allow certain operations in the grant only when the desired encryption context is present. For more information about encryption context, see [Encryption Context](http://docs.aws.amazon.com/kms/latest/developerguide/encryption-context.html).
* `grant_creation_tokens` - (Optional, Forces new resources) A list of grant tokens to be used when creating the grant. See [Grant Tokens](http://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#grant_token) for more information about grant tokens.
Expand Down