-
Notifications
You must be signed in to change notification settings - Fork 9.3k
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
EBS default encryption #8771
EBS default encryption #8771
Changes from 3 commits
5d6355d
00f6a10
6b028d1
0d6ce4c
54ddb3f
05b9633
753fb23
84f451d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,80 @@ | ||||||
package aws | ||||||
|
||||||
import ( | ||||||
"fmt" | ||||||
|
||||||
"github.com/aws/aws-sdk-go/aws" | ||||||
"github.com/aws/aws-sdk-go/service/ec2" | ||||||
|
||||||
"github.com/hashicorp/terraform/helper/resource" | ||||||
"github.com/hashicorp/terraform/helper/schema" | ||||||
) | ||||||
|
||||||
func resourceAwsEbsDefaultKmsKey() *schema.Resource { | ||||||
return &schema.Resource{ | ||||||
Create: resourceAwsEbsDefaultKmsKeyCreate, | ||||||
Read: resourceAwsEbsDefaultKmsKeyRead, | ||||||
Update: resourceAwsEbsDefaultKmsKeyUpdate, | ||||||
Delete: resourceAwsEbsDefaultKmsKeyDelete, | ||||||
|
||||||
Schema: map[string]*schema.Schema{ | ||||||
"key_id": { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the API requires the ARN instead of just the ID, it seems like we should prefer to naming this more clearly (even though its slightly off from the API itself 👍 )
Suggested change
|
||||||
Type: schema.TypeString, | ||||||
Required: true, | ||||||
ValidateFunc: validateArn, | ||||||
}, | ||||||
}, | ||||||
} | ||||||
} | ||||||
|
||||||
func resourceAwsEbsDefaultKmsKeyCreate(d *schema.ResourceData, meta interface{}) error { | ||||||
conn := meta.(*AWSClient).ec2conn | ||||||
|
||||||
_, err := conn.ModifyEbsDefaultKmsKeyId(&ec2.ModifyEbsDefaultKmsKeyIdInput{ | ||||||
KmsKeyId: aws.String(d.Get("key_id").(string)), | ||||||
}) | ||||||
if err != nil { | ||||||
return fmt.Errorf("error creating EBS default KMS key: %s", err) | ||||||
} | ||||||
|
||||||
d.SetId(resource.UniqueId()) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we set this to the key ARN/ID instead of a random identifier so its usable in downstream resources? 😄 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently we are allowing the ARN to change and doing a resource update - If we go with using the ARN as the ID then we need to add |
||||||
|
||||||
return resourceAwsEbsDefaultKmsKeyRead(d, meta) | ||||||
} | ||||||
|
||||||
func resourceAwsEbsDefaultKmsKeyRead(d *schema.ResourceData, meta interface{}) error { | ||||||
conn := meta.(*AWSClient).ec2conn | ||||||
|
||||||
resp, err := conn.GetEbsDefaultKmsKeyId(&ec2.GetEbsDefaultKmsKeyIdInput{}) | ||||||
if err != nil { | ||||||
return fmt.Errorf("error reading EBS default KMS key: %s", err) | ||||||
} | ||||||
|
||||||
d.Set("key_id", aws.StringValue(resp.KmsKeyId)) | ||||||
|
||||||
return nil | ||||||
} | ||||||
|
||||||
func resourceAwsEbsDefaultKmsKeyUpdate(d *schema.ResourceData, meta interface{}) error { | ||||||
conn := meta.(*AWSClient).ec2conn | ||||||
|
||||||
_, err := conn.ModifyEbsDefaultKmsKeyId(&ec2.ModifyEbsDefaultKmsKeyIdInput{ | ||||||
KmsKeyId: aws.String(d.Get("key_id").(string)), | ||||||
}) | ||||||
if err != nil { | ||||||
return fmt.Errorf("error updating EBS default KMS key: %s", err) | ||||||
} | ||||||
|
||||||
return resourceAwsEbsDefaultKmsKeyRead(d, meta) | ||||||
} | ||||||
|
||||||
func resourceAwsEbsDefaultKmsKeyDelete(d *schema.ResourceData, meta interface{}) error { | ||||||
conn := meta.(*AWSClient).ec2conn | ||||||
|
||||||
_, err := conn.ResetEbsDefaultKmsKeyId(&ec2.ResetEbsDefaultKmsKeyIdInput{}) | ||||||
if err != nil { | ||||||
return fmt.Errorf("error deleting EBS default KMS key: %s", err) | ||||||
} | ||||||
|
||||||
return nil | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package aws | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/aws/arn" | ||
"github.com/aws/aws-sdk-go/service/ec2" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
func TestAccAWSEBSDefaultKmsKey_basic(t *testing.T) { | ||
resourceName := "aws_ebs_default_kms_key.test" | ||
resourceNameKey1 := "aws_kms_key.test1" | ||
resourceNameKey2 := "aws_kms_key.test2" | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckAwsEbsDefaultKmsKeyDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccAwsEbsDefaultKmsKeyConfig_basic, | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckEbsDefaultKmsKey(resourceName), | ||
resource.TestCheckResourceAttrPair(resourceName, "key_id", resourceNameKey1, "arn"), | ||
), | ||
}, | ||
{ | ||
Config: testAccAwsEbsDefaultKmsKeyConfig_updated, | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckEbsDefaultKmsKey(resourceName), | ||
resource.TestCheckResourceAttrPair(resourceName, "key_id", resourceNameKey2, "arn"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccCheckAwsEbsDefaultKmsKeyDestroy(s *terraform.State) error { | ||
ec2conn := testAccProvider.Meta().(*AWSClient).ec2conn | ||
kmsconn := testAccProvider.Meta().(*AWSClient).kmsconn | ||
|
||
alias, err := findKmsAliasByName(kmsconn, "alias/aws/ebs", nil) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice! |
||
if err != nil { | ||
return err | ||
} | ||
|
||
aliasARN, err := arn.Parse(aws.StringValue(alias.AliasArn)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
arn := arn.ARN{ | ||
Partition: aliasARN.Partition, | ||
Service: aliasARN.Service, | ||
Region: aliasARN.Region, | ||
AccountID: aliasARN.AccountID, | ||
Resource: fmt.Sprintf("key/%s", aws.StringValue(alias.TargetKeyId)), | ||
} | ||
|
||
resp, err := ec2conn.GetEbsDefaultKmsKeyId(&ec2.GetEbsDefaultKmsKeyIdInput{}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if aws.StringValue(resp.KmsKeyId) != arn.String() { | ||
return fmt.Errorf("Default CMK (%s) is not the account's AWS-managed default CMK (%s)", aws.StringValue(resp.KmsKeyId), arn.String()) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func testAccCheckEbsDefaultKmsKey(name string) resource.TestCheckFunc { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it worth having this function do the inverse of the destroy check? |
||
return func(s *terraform.State) error { | ||
_, ok := s.RootModule().Resources[name] | ||
if !ok { | ||
return fmt.Errorf("Not found: %s", name) | ||
} | ||
|
||
return nil | ||
} | ||
} | ||
|
||
const testAccAwsEbsDefaultKmsKeyConfigBase = ` | ||
resource "aws_kms_key" "test1" {} | ||
|
||
resource "aws_kms_key" "test2" {} | ||
` | ||
|
||
const testAccAwsEbsDefaultKmsKeyConfig_basic = testAccAwsEbsDefaultKmsKeyConfigBase + ` | ||
resource "aws_ebs_default_kms_key" "test" { | ||
key_id = "${aws_kms_key.test1.arn}" | ||
} | ||
` | ||
|
||
const testAccAwsEbsDefaultKmsKeyConfig_updated = testAccAwsEbsDefaultKmsKeyConfigBase + ` | ||
resource "aws_ebs_default_kms_key" "test" { | ||
key_id = "${aws_kms_key.test2.arn}" | ||
} | ||
` |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,80 @@ | ||||||
package aws | ||||||
|
||||||
import ( | ||||||
"fmt" | ||||||
|
||||||
"github.com/aws/aws-sdk-go/aws" | ||||||
"github.com/aws/aws-sdk-go/service/ec2" | ||||||
|
||||||
"github.com/hashicorp/terraform/helper/resource" | ||||||
"github.com/hashicorp/terraform/helper/schema" | ||||||
) | ||||||
|
||||||
func resourceAwsEbsEncryptionByDefault() *schema.Resource { | ||||||
return &schema.Resource{ | ||||||
Create: resourceAwsEbsEncryptionByDefaultCreate, | ||||||
Read: resourceAwsEbsEncryptionByDefaultRead, | ||||||
Update: resourceAwsEbsEncryptionByDefaultUpdate, | ||||||
Delete: resourceAwsEbsEncryptionByDefaultDelete, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we are going to do nothing in the
Suggested change
The documentation in that case should also explicitly state that it is only removing Terraform's management of the setting. Instead of an empty |
||||||
|
||||||
Schema: map[string]*schema.Schema{ | ||||||
"enabled": { | ||||||
Type: schema.TypeBool, | ||||||
Required: true, | ||||||
ewbankkit marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
}, | ||||||
}, | ||||||
} | ||||||
} | ||||||
|
||||||
func resourceAwsEbsEncryptionByDefaultCreate(d *schema.ResourceData, meta interface{}) error { | ||||||
conn := meta.(*AWSClient).ec2conn | ||||||
|
||||||
enabled := d.Get("enabled").(bool) | ||||||
if err := setEbsEncryptionByDefault(conn, enabled); err != nil { | ||||||
return fmt.Errorf("error creating EBS encryption by default (%t): %s", enabled, err) | ||||||
} | ||||||
|
||||||
d.SetId(resource.UniqueId()) | ||||||
|
||||||
return resourceAwsEbsEncryptionByDefaultRead(d, meta) | ||||||
} | ||||||
|
||||||
func resourceAwsEbsEncryptionByDefaultRead(d *schema.ResourceData, meta interface{}) error { | ||||||
conn := meta.(*AWSClient).ec2conn | ||||||
|
||||||
resp, err := conn.GetEbsEncryptionByDefault(&ec2.GetEbsEncryptionByDefaultInput{}) | ||||||
if err != nil { | ||||||
return fmt.Errorf("error reading EBS encryption by default: %s", err) | ||||||
} | ||||||
|
||||||
d.Set("enabled", aws.BoolValue(resp.EbsEncryptionByDefault)) | ||||||
|
||||||
return nil | ||||||
} | ||||||
|
||||||
func resourceAwsEbsEncryptionByDefaultUpdate(d *schema.ResourceData, meta interface{}) error { | ||||||
conn := meta.(*AWSClient).ec2conn | ||||||
|
||||||
enabled := d.Get("enabled").(bool) | ||||||
if err := setEbsEncryptionByDefault(conn, enabled); err != nil { | ||||||
return fmt.Errorf("error updating EBS encryption by default (%t): %s", enabled, err) | ||||||
} | ||||||
|
||||||
return resourceAwsEbsEncryptionByDefaultRead(d, meta) | ||||||
} | ||||||
|
||||||
func resourceAwsEbsEncryptionByDefaultDelete(d *schema.ResourceData, meta interface{}) error { | ||||||
return nil | ||||||
} | ||||||
|
||||||
func setEbsEncryptionByDefault(conn *ec2.EC2, enabled bool) error { | ||||||
var err error | ||||||
|
||||||
if enabled { | ||||||
_, err = conn.EnableEbsEncryptionByDefault(&ec2.EnableEbsEncryptionByDefaultInput{}) | ||||||
} else { | ||||||
_, err = conn.DisableEbsEncryptionByDefault(&ec2.DisableEbsEncryptionByDefaultInput{}) | ||||||
} | ||||||
|
||||||
return err | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package aws | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/service/ec2" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
func TestAccAWSEBSEncryptionByDefault_basic(t *testing.T) { | ||
resourceName := "aws_ebs_encryption_by_default.test" | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the Ideally though, this resource seems like it should enable encryption by default when its added and disable encryption when its removed. The |
||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccAwsEbsEncryptionByDefaultConfig(false), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckEbsEncryptionByDefault(resourceName, false), | ||
resource.TestCheckResourceAttr(resourceName, "enabled", "false"), | ||
), | ||
}, | ||
{ | ||
Config: testAccAwsEbsEncryptionByDefaultConfig(true), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckEbsEncryptionByDefault(resourceName, true), | ||
resource.TestCheckResourceAttr(resourceName, "enabled", "true"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccCheckEbsEncryptionByDefault(n string, enabled bool) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
rs, ok := s.RootModule().Resources[n] | ||
if !ok { | ||
return fmt.Errorf("Not found: %s", n) | ||
} | ||
|
||
if rs.Primary.ID == "" { | ||
return fmt.Errorf("No ID is set") | ||
} | ||
|
||
conn := testAccProvider.Meta().(*AWSClient).ec2conn | ||
|
||
response, err := conn.GetEbsEncryptionByDefault(&ec2.GetEbsEncryptionByDefaultInput{}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if aws.BoolValue(response.EbsEncryptionByDefault) != enabled { | ||
return fmt.Errorf("EBS encryption by default is not in expected state (%t)", enabled) | ||
} | ||
|
||
return nil | ||
} | ||
} | ||
|
||
func testAccAwsEbsEncryptionByDefaultConfig(enabled bool) string { | ||
return fmt.Sprintf(` | ||
resource "aws_ebs_encryption_by_default" "test" { | ||
enabled = %[1]t | ||
} | ||
`, enabled) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
--- | ||
layout: "aws" | ||
page_title: "AWS: aws_ebs_default_kms_key" | ||
sidebar_current: "docs-aws-ebs-default-kms-key" | ||
description: |- | ||
Manages the default customer master key (CMK) that your AWS account uses to encrypt EBS volumes. | ||
--- | ||
|
||
# Resource: aws_ebs_default_kms_key | ||
|
||
Provides a resource to manage the default customer master key (CMK) that your AWS account uses to encrypt EBS volumes. | ||
|
||
Your AWS account has an AWS-managed default CMK that is used for encrypting an EBS volume when no CMK is specified in the API call that creates the volume. | ||
By using the `aws_ebs_default_kms_key` resource, you can specify a customer-managed CMK to use in place of the AWS-managed default CMK. | ||
|
||
~> **NOTE:** Creating an `aws_ebs_default_kms_key` resource does not enable default EBS encryption. Use the [`aws_ebs_encryption_by_default`](ebs_encryption_by_default.html) to enable default EBS encryption. | ||
|
||
~> **NOTE:** Destroying this resource will reset the default CMK to the account's AWS-managed default CMK for EBS. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💯 |
||
|
||
## Example Usage | ||
|
||
```hcl | ||
resource "aws_ebs_default_kms_key" "example" { | ||
key_id = "${aws_kms_key.example.arn}" | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `key_id` - (Required) The ARN of the AWS Key Management Service (AWS KMS) customer master key (CMK) to use to encrypt the EBS volume. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add import support from the get-go, e.g. via the key ARN as the ID 🚀
In the testing:
And the documentation:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since
resourceAwsEbsDefaultKmsKeyRead()
doesn't actually use the resource's ID for the AWS API call (there's a single default EBS CMK per region per account) do we want to check that the KMS key ARN passed toterraform import
is really the current default EBS CMK?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the Terraform code corresponding to the imported resource has the same
key_arn
value as the ARN passed toterraform import
then I think that havingForceNew
on thekey_arn
attribute will cause the resource to be recreated.