From c80a2d13d0574f8af498a714e5aa8769d56b684f Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 27 Sep 2019 13:42:28 -0400 Subject: [PATCH 1/2] resource/aws_mq_broker: Add encryption_options configuration block (support AWS and customer managed KMS CMKs) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/9455 Output from acceptance testing: ``` --- PASS: TestAccAWSMqBroker_allFieldsCustomVpc (1906.75s) --- PASS: TestAccAWSMqBroker_allFieldsDefaultVpc (1859.86s) --- PASS: TestAccAWSMqBroker_basic (1213.98s) --- PASS: TestAccAWSMqBroker_EncryptionOptions_KmsKeyId (1219.72s) --- PASS: TestAccAWSMqBroker_EncryptionOptions_UseAwsOwnedKey_Disabled (1200.00s) --- PASS: TestAccAWSMqBroker_EncryptionOptions_UseAwsOwnedKey_Enabled (1151.79s) --- PASS: TestAccAWSMqBroker_updateTags (1549.03s) --- PASS: TestAccAWSMqBroker_updateUsers (1610.53s) --- PASS: TestAccDataSourceAWSMqBroker_basic (1232.58s) ``` --- aws/data_source_aws_mq_broker.go | 16 +++ aws/data_source_aws_mq_broker_test.go | 6 ++ aws/resource_aws_mq_broker.go | 61 ++++++++++++ aws/resource_aws_mq_broker_test.go | 131 +++++++++++++++++++++++++ website/docs/r/mq_broker.html.markdown | 6 ++ 5 files changed, 220 insertions(+) diff --git a/aws/data_source_aws_mq_broker.go b/aws/data_source_aws_mq_broker.go index eb65ee3e1a75..e5489f78133c 100644 --- a/aws/data_source_aws_mq_broker.go +++ b/aws/data_source_aws_mq_broker.go @@ -55,6 +55,22 @@ func dataSourceAwsMqBroker() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "encryption_options": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "kms_key_id": { + Type: schema.TypeString, + Computed: true, + }, + "use_aws_owned_key": { + Type: schema.TypeBool, + Computed: true, + }, + }, + }, + }, "engine_type": { Type: schema.TypeString, Computed: true, diff --git a/aws/data_source_aws_mq_broker_test.go b/aws/data_source_aws_mq_broker_test.go index 5bf5bbfb83ff..8c1029ca8801 100644 --- a/aws/data_source_aws_mq_broker_test.go +++ b/aws/data_source_aws_mq_broker_test.go @@ -35,6 +35,12 @@ func TestAccDataSourceAWSMqBroker_basic(t *testing.T) { resource.TestCheckResourceAttrPair( "data.aws_mq_broker.by_id", "configuration.#", "aws_mq_broker.acctest", "configuration.#"), + resource.TestCheckResourceAttrPair( + "data.aws_mq_broker.by_id", "encryption_options.#", + "aws_mq_broker.acctest", "encryption_options.#"), + resource.TestCheckResourceAttrPair( + "data.aws_mq_broker.by_id", "encryption_options.0.use_aws_owned_key", + "aws_mq_broker.acctest", "encryption_options.0.use_aws_owned_key"), resource.TestCheckResourceAttrPair( "data.aws_mq_broker.by_id", "engine_type", "aws_mq_broker.acctest", "engine_type"), diff --git a/aws/resource_aws_mq_broker.go b/aws/resource_aws_mq_broker.go index 704ad6a414d8..9cb6cca85528 100644 --- a/aws/resource_aws_mq_broker.go +++ b/aws/resource_aws_mq_broker.go @@ -65,6 +65,30 @@ func resourceAwsMqBroker() *schema.Resource { Default: "SINGLE_INSTANCE", ForceNew: true, }, + "encryption_options": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + DiffSuppressFunc: suppressMissingOptionalConfigurationBlock, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "kms_key_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validateArn, + }, + "use_aws_owned_key": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Default: true, + }, + }, + }, + }, "engine_type": { Type: schema.TypeString, Required: true, @@ -217,6 +241,7 @@ func resourceAwsMqBrokerCreate(d *schema.ResourceData, meta interface{}) error { AutoMinorVersionUpgrade: aws.Bool(d.Get("auto_minor_version_upgrade").(bool)), BrokerName: aws.String(name), CreatorRequestId: aws.String(requestId), + EncryptionOptions: expandMqEncryptionOptions(d.Get("encryption_options").([]interface{})), EngineType: aws.String(d.Get("engine_type").(string)), EngineVersion: aws.String(d.Get("engine_version").(string)), HostInstanceType: aws.String(d.Get("host_instance_type").(string)), @@ -304,6 +329,11 @@ func resourceAwsMqBrokerRead(d *schema.ResourceData, meta interface{}) error { d.Set("instances", flattenMqBrokerInstances(out.BrokerInstances)) d.Set("broker_name", out.BrokerName) d.Set("deployment_mode", out.DeploymentMode) + + if err := d.Set("encryption_options", flattenMqEncryptionOptions(out.EncryptionOptions)); err != nil { + return fmt.Errorf("error setting encryption_options: %s", err) + } + d.Set("engine_type", out.EngineType) d.Set("engine_version", out.EngineVersion) d.Set("host_instance_type", out.HostInstanceType) @@ -579,6 +609,37 @@ func diffAwsMqBrokerUsers(bId string, oldUsers, newUsers []interface{}) ( return } +func expandMqEncryptionOptions(l []interface{}) *mq.EncryptionOptions { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + encryptionOptions := &mq.EncryptionOptions{ + UseAwsOwnedKey: aws.Bool(m["use_aws_owned_key"].(bool)), + } + + if v, ok := m["kms_key_id"].(string); ok && v != "" { + encryptionOptions.KmsKeyId = aws.String(v) + } + + return encryptionOptions +} + +func flattenMqEncryptionOptions(encryptionOptions *mq.EncryptionOptions) []interface{} { + if encryptionOptions == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "kms_key_id": aws.StringValue(encryptionOptions.KmsKeyId), + "use_aws_owned_key": aws.BoolValue(encryptionOptions.UseAwsOwnedKey), + } + + return []interface{}{m} +} + func validateMqBrokerPassword(v interface{}, k string) (ws []string, errors []error) { min := 12 max := 250 diff --git a/aws/resource_aws_mq_broker_test.go b/aws/resource_aws_mq_broker_test.go index 6b9617404f11..5cec89852a58 100644 --- a/aws/resource_aws_mq_broker_test.go +++ b/aws/resource_aws_mq_broker_test.go @@ -252,6 +252,8 @@ func TestAccAWSMqBroker_basic(t *testing.T) { resource.TestMatchResourceAttr("aws_mq_broker.test", "configuration.0.id", regexp.MustCompile(`^c-[a-z0-9-]+$`)), resource.TestMatchResourceAttr("aws_mq_broker.test", "configuration.0.revision", regexp.MustCompile(`^[0-9]+$`)), resource.TestCheckResourceAttr("aws_mq_broker.test", "deployment_mode", "SINGLE_INSTANCE"), + resource.TestCheckResourceAttr("aws_mq_broker.test", "encryption_options.#", "1"), + resource.TestCheckResourceAttr("aws_mq_broker.test", "encryption_options.0.use_aws_owned_key", "true"), resource.TestCheckResourceAttr("aws_mq_broker.test", "engine_type", "ActiveMQ"), resource.TestCheckResourceAttr("aws_mq_broker.test", "engine_version", "5.15.0"), resource.TestCheckResourceAttr("aws_mq_broker.test", "host_instance_type", "mq.t2.micro"), @@ -507,6 +509,71 @@ func TestAccAWSMqBroker_allFieldsCustomVpc(t *testing.T) { }) } +func TestAccAWSMqBroker_EncryptionOptions_KmsKeyId(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + kmsKeyResourceName := "aws_kms_key.test" + resourceName := "aws_mq_broker.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSMq(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsMqBrokerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccMqBrokerConfigEncryptionOptionsKmsKeyId(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsMqBrokerExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "encryption_options.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "encryption_options.0.kms_key_id", kmsKeyResourceName, "arn"), + resource.TestCheckResourceAttr(resourceName, "encryption_options.0.use_aws_owned_key", "false"), + ), + }, + }, + }) +} + +func TestAccAWSMqBroker_EncryptionOptions_UseAwsOwnedKey_Disabled(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_mq_broker.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSMq(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsMqBrokerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccMqBrokerConfigEncryptionOptionsUseAwsOwnedKey(rName, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsMqBrokerExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "encryption_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "encryption_options.0.use_aws_owned_key", "false"), + ), + }, + }, + }) +} + +func TestAccAWSMqBroker_EncryptionOptions_UseAwsOwnedKey_Enabled(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_mq_broker.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSMq(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsMqBrokerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccMqBrokerConfigEncryptionOptionsUseAwsOwnedKey(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsMqBrokerExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "encryption_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "encryption_options.0.use_aws_owned_key", "true"), + ), + }, + }, + }) +} + func TestAccAWSMqBroker_updateUsers(t *testing.T) { sgName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) brokerName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) @@ -846,6 +913,70 @@ resource "aws_mq_broker" "test" { `, sgName, sgName, cfgName, cfgBody, brokerName) } +func testAccMqBrokerConfigEncryptionOptionsKmsKeyId(rName string) string { + return fmt.Sprintf(` +resource "aws_kms_key" "test" { + description = %[1]q + deletion_window_in_days = 7 +} + +resource "aws_security_group" "test" { + name = %[1]q +} + +resource "aws_mq_broker" "test" { + broker_name = %[1]q + engine_type = "ActiveMQ" + engine_version = "5.15.0" + host_instance_type = "mq.t2.micro" + security_groups = ["${aws_security_group.test.id}"] + + encryption_options { + kms_key_id = "${aws_kms_key.test.arn}" + use_aws_owned_key = false + } + + logs { + general = true + } + + user { + username = "Test" + password = "TestTest1234" + } +} +`, rName) +} + +func testAccMqBrokerConfigEncryptionOptionsUseAwsOwnedKey(rName string, useAwsOwnedKey bool) string { + return fmt.Sprintf(` +resource "aws_security_group" "test" { + name = %[1]q +} + +resource "aws_mq_broker" "test" { + broker_name = %[1]q + engine_type = "ActiveMQ" + engine_version = "5.15.0" + host_instance_type = "mq.t2.micro" + security_groups = ["${aws_security_group.test.id}"] + + encryption_options { + use_aws_owned_key = %[2]t + } + + logs { + general = true + } + + user { + username = "Test" + password = "TestTest1234" + } +} +`, rName, useAwsOwnedKey) +} + func testAccMqBrokerConfig_updateUsers1(sgName, brokerName string) string { return fmt.Sprintf(` resource "aws_security_group" "test" { diff --git a/website/docs/r/mq_broker.html.markdown b/website/docs/r/mq_broker.html.markdown index 8e18a1da5263..6883d3a30d95 100644 --- a/website/docs/r/mq_broker.html.markdown +++ b/website/docs/r/mq_broker.html.markdown @@ -58,6 +58,7 @@ The following arguments are supported: * `broker_name` - (Required) The name of the broker. * `configuration` - (Optional) Configuration of the broker. See below. * `deployment_mode` - (Optional) The deployment mode of the broker. Supported: `SINGLE_INSTANCE` and `ACTIVE_STANDBY_MULTI_AZ`. Defaults to `SINGLE_INSTANCE`. +* `encryption_options` - (Optional) Configuration block containing encryption options. See below. * `engine_type` - (Required) The type of broker engine. Currently, Amazon MQ supports only `ActiveMQ`. * `engine_version` - (Required) The version of the broker engine. Currently, See the [AmazonMQ Broker Engine docs](https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/broker-engine.html) for supported versions. * `host_instance_type` - (Required) The broker's instance type. e.g. `mq.t2.micro` or `mq.m4.large` @@ -76,6 +77,11 @@ The following arguments are supported: * `id` - (Optional) The Configuration ID. * `revision` - (Optional) Revision of the Configuration. +#### `encryption_options` + +* `kms_key_id` - (Optional) Amazon Resource Name (ARN) of Key Management Service (KMS) Customer Master Key (CMK) to use for encryption at rest. Requires setting `use_aws_owned_key` to `false`. To perform drift detection when AWS managed CMKs or customer managed CMKs are in use, the value must be configured. +* `use_aws_owned_key` - (Optional) Boolean to enable an AWS owned Key Management Service (KMS) Customer Master Key (CMK) that is not in your account. Defaults to `true`. Setting to `false` without configuring `kms_key_id` will create an AWS managed Customer Master Key (CMK) aliased to `aws/mq` in your account. + #### `maintenance_window_start_time` * `day_of_week` - (Required) The day of the week. e.g. `MONDAY`, `TUESDAY`, or `WEDNESDAY` From cec03824451d0816214ad1c6460c009295f8db81 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 27 Sep 2019 16:10:48 -0400 Subject: [PATCH 2/2] docs/resource/aws_mq_broker: Clarify kms_key_id drift detection statement Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/10276#discussion_r329224475 --- website/docs/r/mq_broker.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/mq_broker.html.markdown b/website/docs/r/mq_broker.html.markdown index 6883d3a30d95..52303f09bde0 100644 --- a/website/docs/r/mq_broker.html.markdown +++ b/website/docs/r/mq_broker.html.markdown @@ -79,7 +79,7 @@ The following arguments are supported: #### `encryption_options` -* `kms_key_id` - (Optional) Amazon Resource Name (ARN) of Key Management Service (KMS) Customer Master Key (CMK) to use for encryption at rest. Requires setting `use_aws_owned_key` to `false`. To perform drift detection when AWS managed CMKs or customer managed CMKs are in use, the value must be configured. +* `kms_key_id` - (Optional) Amazon Resource Name (ARN) of Key Management Service (KMS) Customer Master Key (CMK) to use for encryption at rest. Requires setting `use_aws_owned_key` to `false`. To perform drift detection when AWS managed CMKs or customer managed CMKs are in use, this value must be configured. * `use_aws_owned_key` - (Optional) Boolean to enable an AWS owned Key Management Service (KMS) Customer Master Key (CMK) that is not in your account. Defaults to `true`. Setting to `false` without configuring `kms_key_id` will create an AWS managed Customer Master Key (CMK) aliased to `aws/mq` in your account. #### `maintenance_window_start_time`