diff --git a/.changelog/38492.txt b/.changelog/38492.txt new file mode 100644 index 00000000000..de4753d6ca7 --- /dev/null +++ b/.changelog/38492.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_cloudwatch_event_bus: Add `kms_key_identifier` argument +``` + +```release-note:enhancement +data-source/aws_cloudwatch_event_bus: Add `kms_key_identifier` attribute +``` diff --git a/internal/service/events/bus.go b/internal/service/events/bus.go index f82e3b3ebfe..29a75c29b57 100644 --- a/internal/service/events/bus.go +++ b/internal/service/events/bus.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" @@ -46,6 +47,11 @@ func resourceBus() *schema.Resource { ForceNew: true, ValidateFunc: validSourceName, }, + "kms_key_identifier": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 2048), + }, names.AttrName: { Type: schema.TypeString, Required: true, @@ -74,6 +80,10 @@ func resourceBusCreate(ctx context.Context, d *schema.ResourceData, meta interfa input.EventSourceName = aws.String(v.(string)) } + if v, ok := d.GetOk("kms_key_identifier"); ok { + input.KmsKeyIdentifier = aws.String(v.(string)) + } + output, err := conn.CreateEventBus(ctx, input) // Some partitions (e.g. ISO) may not support tag-on-create. @@ -123,6 +133,7 @@ func resourceBusRead(ctx context.Context, d *schema.ResourceData, meta interface } d.Set(names.AttrARN, output.Arn) + d.Set("kms_key_identifier", output.KmsKeyIdentifier) d.Set(names.AttrName, output.Name) return diags @@ -130,8 +141,23 @@ func resourceBusRead(ctx context.Context, d *schema.ResourceData, meta interface func resourceBusUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).EventsClient(ctx) + + if d.HasChange("kms_key_identifier") { + input := &eventbridge.UpdateEventBusInput{ + Name: aws.String(d.Get(names.AttrName).(string)), + } + + if v, ok := d.GetOk("kms_key_identifier"); ok { + input.KmsKeyIdentifier = aws.String(v.(string)) + } + + _, err := conn.UpdateEventBus(ctx, input) - // Tags only. + if err != nil { + return sdkdiag.AppendErrorf(diags, "updating EventBridge Event Bus (%s): %s", d.Id(), err) + } + } return append(diags, resourceBusRead(ctx, d, meta)...) } diff --git a/internal/service/events/bus_data_source.go b/internal/service/events/bus_data_source.go index 025249e5608..f71ec0347b5 100644 --- a/internal/service/events/bus_data_source.go +++ b/internal/service/events/bus_data_source.go @@ -23,6 +23,10 @@ func dataSourceBus() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "kms_key_identifier": { + Type: schema.TypeString, + Computed: true, + }, names.AttrName: { Type: schema.TypeString, Required: true, @@ -44,6 +48,7 @@ func dataSourceBusRead(ctx context.Context, d *schema.ResourceData, meta interfa d.SetId(eventBusName) d.Set(names.AttrARN, output.Arn) + d.Set("kms_key_identifier", output.KmsKeyIdentifier) d.Set(names.AttrName, output.Name) return diags diff --git a/internal/service/events/bus_data_source_test.go b/internal/service/events/bus_data_source_test.go index 9d89c887b0c..9baad712d58 100644 --- a/internal/service/events/bus_data_source_test.go +++ b/internal/service/events/bus_data_source_test.go @@ -35,6 +35,27 @@ func TestAccEventsBusDataSource_basic(t *testing.T) { }) } +func TestAccEventsBusDataSource_kmsKeyIdentifier(t *testing.T) { + ctx := acctest.Context(t) + busName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSourceName := "data.aws_cloudwatch_event_bus.test" + resourceName := "aws_cloudwatch_event_bus.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EventsServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccBusDataSourceConfig_kmsKeyIdentifier(busName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "kms_key_identifier", resourceName, "kms_key_identifier"), + ), + }, + }, + }) +} + func testAccBusDataSourceConfig_basic(busName string) string { return fmt.Sprintf(` resource "aws_cloudwatch_event_bus" "test" { @@ -46,3 +67,68 @@ data "aws_cloudwatch_event_bus" "test" { } `, busName) } + +func testAccBusDataSourceConfig_kmsKeyIdentifier(busName string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} + +data "aws_partition" "current" {} + +resource "aws_kms_key" "test" { + deletion_window_in_days = 7 +} + +data "aws_iam_policy_document" "key_policy" { + statement { + actions = [ + "kms:Decrypt", + "kms:GenerateDataKey" + ] + + resources = [ + aws_kms_key.test.arn, + ] + + principals { + type = "Service" + identifiers = ["events.amazonaws.com"] + } + + condition { + test = "StringEquals" + variable = "aws:SourceAccount" + values = [data.aws_caller_identity.current.account_id] + } + } + + statement { + actions = [ + "kms:*", + ] + + resources = [ + aws_kms_key.test.arn + ] + + principals { + type = "AWS" + identifiers = ["arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root"] + } + } +} + +resource "aws_kms_key_policy" "test" { + key_id = aws_kms_key.test.id + policy = data.aws_iam_policy_document.key_policy.json +} + +resource "aws_cloudwatch_event_bus" "test" { + name = %[1]q + kms_key_identifier = aws_kms_key.test.arn +} + +data "aws_cloudwatch_event_bus" "test" { + name = aws_cloudwatch_event_bus.test.name +} +`, busName) +} diff --git a/internal/service/events/bus_test.go b/internal/service/events/bus_test.go index fcbf1d2445f..704caee5e16 100644 --- a/internal/service/events/bus_test.go +++ b/internal/service/events/bus_test.go @@ -74,6 +74,41 @@ func TestAccEventsBus_basic(t *testing.T) { }) } +func TestAccEventsBus_kmsKeyIdentifier(t *testing.T) { + ctx := acctest.Context(t) + var v1, v2 eventbridge.DescribeEventBusOutput + busName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_cloudwatch_event_bus.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EventsServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckBusDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccBusConfig_kmsKeyIdentifier1(busName), + Check: resource.ComposeTestCheckFunc( + testAccCheckBusExists(ctx, resourceName, &v1), + resource.TestCheckResourceAttrPair(resourceName, "kms_key_identifier", "aws_kms_key.test1", names.AttrARN), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccBusConfig_kmsKeyIdentifier2(busName), + Check: resource.ComposeTestCheckFunc( + testAccCheckBusExists(ctx, resourceName, &v2), + resource.TestCheckResourceAttrPair(resourceName, "kms_key_identifier", "aws_kms_key.test2", names.AttrARN), + ), + }, + }, + }) +} + func TestAccEventsBus_tags(t *testing.T) { ctx := acctest.Context(t) var v1, v2, v3 eventbridge.DescribeEventBusOutput @@ -300,3 +335,92 @@ resource "aws_cloudwatch_event_bus" "test" { } `, name) } + +func testAccBusConfig_kmsKeyIdentifierBase() string { + return ` +data "aws_caller_identity" "current" {} + +data "aws_partition" "current" {} + +resource "aws_kms_key" "test1" { + deletion_window_in_days = 7 +} + +resource "aws_kms_key" "test2" { + deletion_window_in_days = 7 +} + +data "aws_iam_policy_document" "key_policy" { + statement { + actions = [ + "kms:Decrypt", + "kms:GenerateDataKey" + ] + + resources = [ + aws_kms_key.test1.arn, + aws_kms_key.test2.arn, + ] + + principals { + type = "Service" + identifiers = ["events.amazonaws.com"] + } + + condition { + test = "StringEquals" + variable = "aws:SourceAccount" + values = [data.aws_caller_identity.current.account_id] + } + } + + statement { + actions = [ + "kms:*", + ] + + resources = [ + aws_kms_key.test1.arn, + aws_kms_key.test2.arn, + ] + + principals { + type = "AWS" + identifiers = ["arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root"] + } + } +} + +resource "aws_kms_key_policy" "test1" { + key_id = aws_kms_key.test1.id + policy = data.aws_iam_policy_document.key_policy.json +} + +resource "aws_kms_key_policy" "test2" { + key_id = aws_kms_key.test2.id + policy = data.aws_iam_policy_document.key_policy.json +} +` +} + +func testAccBusConfig_kmsKeyIdentifier1(name string) string { + return acctest.ConfigCompose( + testAccBusConfig_kmsKeyIdentifierBase(), + fmt.Sprintf(` +resource "aws_cloudwatch_event_bus" "test" { + name = %[1]q + kms_key_identifier = aws_kms_key.test1.arn +} +`, name)) +} + +func testAccBusConfig_kmsKeyIdentifier2(name string) string { + return acctest.ConfigCompose( + testAccBusConfig_kmsKeyIdentifierBase(), + fmt.Sprintf(` +resource "aws_cloudwatch_event_bus" "test" { + name = %[1]q + kms_key_identifier = aws_kms_key.test2.arn +} +`, name)) +} diff --git a/website/docs/d/cloudwatch_event_bus.html.markdown b/website/docs/d/cloudwatch_event_bus.html.markdown index d3232cc7bc9..3a804c6ad5d 100644 --- a/website/docs/d/cloudwatch_event_bus.html.markdown +++ b/website/docs/d/cloudwatch_event_bus.html.markdown @@ -29,3 +29,4 @@ data "aws_cloudwatch_event_bus" "example" { This data source exports the following attributes in addition to the arguments above: * `arn` - ARN. +* `kms_key_identifier` - The identifier of the AWS KMS customer managed key for EventBridge to use to encrypt events on this event bus, if one has been specified. diff --git a/website/docs/r/cloudwatch_event_bus.html.markdown b/website/docs/r/cloudwatch_event_bus.html.markdown index 1fe814860a7..cefcf691583 100644 --- a/website/docs/r/cloudwatch_event_bus.html.markdown +++ b/website/docs/r/cloudwatch_event_bus.html.markdown @@ -36,7 +36,8 @@ resource "aws_cloudwatch_event_bus" "examplepartner" { This resource supports the following arguments: * `name` - (Required) The name of the new event bus. The names of custom event buses can't contain the / character. To create a partner event bus, ensure the `name` matches the `event_source_name`. -* `event_source_name` (Optional) The partner event source that the new event bus will be matched with. Must match `name`. +* `event_source_name` - (Optional) The partner event source that the new event bus will be matched with. Must match `name`. +* `kms_key_identifier` - (Optional) The identifier of the AWS KMS customer managed key for EventBridge to use, if you choose to use a customer managed key to encrypt events on this event bus. The identifier can be the key Amazon Resource Name (ARN), KeyId, key alias, or key alias ARN. * `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. ## Attribute Reference