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

New Data Source: aws_kms_key #2224

Merged
merged 19 commits into from
Feb 26, 2018
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
110 changes: 110 additions & 0 deletions aws/data_source_aws_kms_key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package aws

import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/kms"
"github.com/hashicorp/terraform/helper/schema"
"time"
)

func dataSourceAwsKmsKey() *schema.Resource {
return &schema.Resource{
Read: dataSourceAwsKmsKeyRead,
Schema: map[string]*schema.Schema{
"key_id": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validateKmsKey,
},
"grant_tokens": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"arn": {
Type: schema.TypeString,
Computed: true,
},
"aws_account_id": {
Type: schema.TypeString,
Computed: true,
},
"creation_date": {
Type: schema.TypeString,
Computed: true,
},
"deletion_date": {
Type: schema.TypeString,
Computed: true,
},
"description": {
Type: schema.TypeString,
Computed: true,
},
"enabled": {
Type: schema.TypeBool,
Computed: true,
},
"expiration_model": {
Type: schema.TypeString,
Computed: true,
},
"key_manager": {
Type: schema.TypeString,
Computed: true,
},
"key_state": {
Type: schema.TypeString,
Computed: true,
},
"key_usage": {
Type: schema.TypeString,
Computed: true,
},
"origin": {
Type: schema.TypeString,
Computed: true,
},
"valid_to": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func dataSourceAwsKmsKeyRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).kmsconn
keyId := d.Get("key_id")
var grantTokens []*string
if v, ok := d.GetOk("grant_tokens"); ok {
grantTokens = aws.StringSlice(v.([]string))
}
input := &kms.DescribeKeyInput{
KeyId: aws.String(keyId.(string)),
GrantTokens: grantTokens,
}
output, err := conn.DescribeKey(input)
if err != nil {
return fmt.Errorf("error while describing key [%s]: %s", keyId, err)
}
d.SetId(aws.StringValue(output.KeyMetadata.KeyId))
d.Set("arn", output.KeyMetadata.Arn)
d.Set("aws_account_id", output.KeyMetadata.AWSAccountId)
d.Set("creation_date", aws.TimeValue(output.KeyMetadata.CreationDate).Format(time.RFC3339))
if output.KeyMetadata.DeletionDate != nil {
d.Set("deletion_date", aws.TimeValue(output.KeyMetadata.DeletionDate).Format(time.RFC3339))
}
d.Set("description", output.KeyMetadata.Description)
d.Set("enabled", output.KeyMetadata.Enabled)
d.Set("expiration_model", output.KeyMetadata.ExpirationModel)
d.Set("key_manager", output.KeyMetadata.KeyManager)
d.Set("key_state", output.KeyMetadata.KeyState)
d.Set("key_usage", output.KeyMetadata.KeyUsage)
d.Set("origin", output.KeyMetadata.Origin)
if output.KeyMetadata.ValidTo != nil {
d.Set("valid_to", aws.TimeValue(output.KeyMetadata.ValidTo).Format(time.RFC3339))
}
return nil
}
75 changes: 75 additions & 0 deletions aws/data_source_aws_kms_key_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package aws

import (
"fmt"
"testing"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"regexp"
)

func TestAccDataSourceAwsKmsKey_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAwsKmsKeyConfig,
Check: resource.ComposeTestCheckFunc(
testAccDataSourceAwsKmsKeyCheck("data.aws_kms_key.arbitrary"),
resource.TestMatchResourceAttr("data.aws_kms_key.arbitrary", "arn", regexp.MustCompile("^arn:[^:]+:kms:[^:]+:[^:]+:key/.+")),
resource.TestCheckResourceAttrSet("data.aws_kms_key.arbitrary", "aws_account_id"),
resource.TestCheckResourceAttrSet("data.aws_kms_key.arbitrary", "creation_date"),
resource.TestCheckResourceAttr("data.aws_kms_key.arbitrary", "description", "Terraform acc test"),
resource.TestCheckResourceAttr("data.aws_kms_key.arbitrary", "enabled", "true"),
resource.TestCheckResourceAttrSet("data.aws_kms_key.arbitrary", "key_manager"),
resource.TestCheckResourceAttrSet("data.aws_kms_key.arbitrary", "key_state"),
resource.TestCheckResourceAttr("data.aws_kms_key.arbitrary", "key_usage", "ENCRYPT_DECRYPT"),
resource.TestCheckResourceAttrSet("data.aws_kms_key.arbitrary", "origin"),
),
},
},
})
}

func testAccDataSourceAwsKmsKeyCheck(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("root module has no resource called %s", name)
}

kmsKeyRs, ok := s.RootModule().Resources["aws_kms_key.arbitrary"]
if !ok {
return fmt.Errorf("can't find aws_kms_key.arbitrary in state")
}

attr := rs.Primary.Attributes

checkProperties := []string{"arn", "key_usage", "description"}

for _, p := range checkProperties {
if attr[p] != kmsKeyRs.Primary.Attributes[p] {
return fmt.Errorf(
"%s is %s; want %s",
p,
attr[p],
kmsKeyRs.Primary.Attributes[p],
)
}
}

return nil
}
}

const testAccDataSourceAwsKmsKeyConfig = `
resource "aws_kms_key" "arbitrary" {
description = "Terraform acc test"
deletion_window_in_days = 7
}

data "aws_kms_key" "arbitrary" {
key_id = "${aws_kms_key.arbitrary.key_id}"
}`
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ func Provider() terraform.ResourceProvider {
"aws_kinesis_stream": dataSourceAwsKinesisStream(),
"aws_kms_alias": dataSourceAwsKmsAlias(),
"aws_kms_ciphertext": dataSourceAwsKmsCiphertext(),
"aws_kms_key": dataSourceAwsKmsKey(),
"aws_kms_secret": dataSourceAwsKmsSecret(),
"aws_nat_gateway": dataSourceAwsNatGateway(),
"aws_network_interface": dataSourceAwsNetworkInterface(),
Expand Down
16 changes: 16 additions & 0 deletions aws/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -2144,6 +2144,22 @@ func validateDxConnectionBandWidth(v interface{}, k string) (ws []string, errors
return
}

func validateKmsKey(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
arnPrefixPattern := `arn:[^:]+:kms:[^:]+:[^:]+:`
keyIdPattern := "[A-Za-z0-9-]+"
keyArnPattern := arnPrefixPattern + "key/" + keyIdPattern
aliasNamePattern := "alias/[a-zA-Z0-9:/_-]+"
aliasArnPattern := arnPrefixPattern + aliasNamePattern
if !regexp.MustCompile(fmt.Sprintf("^%s$", keyIdPattern)).MatchString(value) &&
!regexp.MustCompile(fmt.Sprintf("^%s$", keyArnPattern)).MatchString(value) &&
!regexp.MustCompile(fmt.Sprintf("^%s$", aliasNamePattern)).MatchString(value) &&
!regexp.MustCompile(fmt.Sprintf("^%s$", aliasArnPattern)).MatchString(value) {
errors = append(errors, fmt.Errorf("%q must be one of the following patterns: %s, %s, %s or %s", k, keyIdPattern, keyArnPattern, aliasNamePattern, aliasArnPattern))
}
return
}

func validateAwsElastiCacheReplicationGroupAuthToken(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if (len(value) < 16) || (len(value) > 128) {
Expand Down
47 changes: 47 additions & 0 deletions aws/validators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2888,6 +2888,53 @@ func TestValidateDxConnectionBandWidth(t *testing.T) {
}
}

func TestValidateKmsKey(t *testing.T) {
cases := []struct {
Value string
ErrCount int
}{
{
Value: "arbitrary-uuid-1234",
ErrCount: 0,
},
{
Value: "arn:aws:kms:us-west-2:111122223333:key/arbitrary-uuid-1234",
ErrCount: 0,
},
{
Value: "alias/arbitrary-key",
ErrCount: 0,
},
{
Value: "alias/arbitrary/key",
ErrCount: 0,
},
{
Value: "arn:aws:kms:us-west-2:111122223333:alias/arbitrary-key",
ErrCount: 0,
},
{
Value: "arn:aws:kms:us-west-2:111122223333:alias/arbitrary/key",
ErrCount: 0,
},
{
Value: "$%wrongkey",
ErrCount: 1,
},
{
Value: "arn:aws:lamda:foo:bar:key/xyz",
ErrCount: 1,
},
}

for _, tc := range cases {
_, errors := validateKmsKey(tc.Value, "key_id")
if len(errors) != tc.ErrCount {
t.Fatalf("%q validation failed: %v", tc.Value, errors)
}
}
}

func TestValidateCognitoUserPoolReplyEmailAddress(t *testing.T) {
validTypes := []string{
"[email protected]",
Expand Down
3 changes: 3 additions & 0 deletions website/aws.erb
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@
<li<%= sidebar_current("docs-aws-datasource-kms-alias") %>>
<a href="/docs/providers/aws/d/kms_alias.html">aws_kms_alias</a>
</li>
<li<%= sidebar_current("docs-aws-datasource-kms-key") %>>
<a href="/docs/providers/aws/d/kms_key.html">aws_kms_key</a>
</li>
<li<%= sidebar_current("docs-aws-datasource-kms-ciphertext") %>>
<a href="/docs/providers/aws/d/kms_ciphertext.html">aws_kms_ciphertext</a>
</li>
Expand Down
59 changes: 59 additions & 0 deletions website/docs/d/kms_key.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
layout: "aws"
page_title: "AWS: aws_kms_key"
sidebar_current: "docs-aws-datasource-kms-key"
description: |-
Get information on a AWS Key Management Service (KMS) Key
---

# aws_kms_key

Use this data source to get detailed information about
the specified KMS Key with flexible key id input.
This can be useful to reference key alias
without having to hard code the ARN as input.

## Example Usage

```hcl
data "aws_kms_key" "foo" {
key_id = "alias/my-key"
}

data "aws_kms_key" "foo" {
key_id = "1234abcd-12ab-34cd-56ef-1234567890ab"
}

data "aws_kms_key" "foo" {
key_id = "arn:aws:kms:us-east-1:111122223333:alias/my-key"
}

data "aws_kms_key" "foo" {
key_id = "arn:aws:kms:us-east-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"
}
```

## Argument Reference

* `key_id` - (Required) Key identifier which can be one of the following format:
* Key ID. E.g: `1234abcd-12ab-34cd-56ef-1234567890ab`
* Key ARN. E.g.: `arn:aws:kms:us-east-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab`
* Alias name. E.g.: `alias/my-key`
* Alias ARN: E.g.: `arn:aws:kms:us-east-1:111122223333:alias/my-key`
* `grant_tokens` - (Optional) List of grant tokens

## Attributes Reference

* `id`: The globally unique identifier for the key
* `arn`: The Amazon Resource Name (ARN) of the key
* `aws_account_id`: The twelve-digit account ID of the AWS account that owns the key
* `creation_date`: The date and time when the key was created
* `deletion_date`: The date and time after which AWS KMS deletes the key. This value is present only when `key_state` is `PendingDeletion`, otherwise this value is 0
* `description`: The description of the key.
* `enabled`: Specifies whether the key is enabled. When `key_state` is `Enabled` this value is true, otherwise it is false
* `expiration_model`: Specifies whether the Key's key material expires. This value is present only when `origin` is `EXTERNAL`, otherwise this value is empty
* `key_manager`: The key's manager
* `key_state`: The state of the key
* `key_usage`: Currently the only allowed value is `ENCRYPT_DECRYPT`
* `origin`: When this value is `AWS_KMS`, AWS KMS created the key material. When this value is `EXTERNAL`, the key material was imported from your existing key management infrastructure or the CMK lacks key material
* `valid_to`: The time at which the imported key material expires. This value is present only when `origin` is `EXTERNAL` and whose `expiration_model` is `KEY_MATERIAL_EXPIRES`, otherwise this value is 0