From a6346f08584e8badf648c3ba7935cb354a6d5ce6 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Thu, 10 Sep 2026 11:12:39 +0100 Subject: [PATCH 01/35] chore(eventbridge): create directory --- infrastructure/modules/eventbridge/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 infrastructure/modules/eventbridge/README.md diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md new file mode 100644 index 00000000..9df56b73 --- /dev/null +++ b/infrastructure/modules/eventbridge/README.md @@ -0,0 +1,14 @@ +# EventBridge + +NHS Screening wrapper around the community +[`terraform-aws-modules/terraform-aws-eventbridge`](https://registry.terraform.io/modules/terraform-aws-modules/eventbridge/aws/4.3.2) +module that consumes the shared `context.tf` for naming and tagging. + +DAVEH + + + + + + + From 516e7b7b6675fdf12602ac9bc516729c89fb1b87 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Thu, 10 Sep 2026 11:22:10 +0100 Subject: [PATCH 02/35] chore: add versions --- .github/dependabot.yaml | 1 + README.md | 1 + .../modules/eventbridge/.terraform.lock.hcl | 30 +++++++++++++++++++ infrastructure/modules/eventbridge/README.md | 26 ++++++++++++++++ infrastructure/modules/eventbridge/main.tf | 0 infrastructure/modules/eventbridge/outputs.tf | 0 .../modules/eventbridge/variables.tf | 0 .../modules/eventbridge/versions.tf | 10 +++++++ 8 files changed, 68 insertions(+) create mode 100644 infrastructure/modules/eventbridge/.terraform.lock.hcl create mode 100644 infrastructure/modules/eventbridge/main.tf create mode 100644 infrastructure/modules/eventbridge/outputs.tf create mode 100644 infrastructure/modules/eventbridge/variables.tf create mode 100644 infrastructure/modules/eventbridge/versions.tf diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 6b252b9e..acb49f6f 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -53,6 +53,7 @@ updates: - "infrastructure/modules/ecs-service" - "infrastructure/modules/efs" - "infrastructure/modules/elasticache" + - "infrastructure/modules/eventbridge" - "infrastructure/modules/github-config" - "infrastructure/modules/guardduty" - "infrastructure/modules/iam" diff --git a/README.md b/README.md index ff744ad4..3435d779 100644 --- a/README.md +++ b/README.md @@ -340,6 +340,7 @@ Rules: | `ecs-service` | terraform-aws-modules/ecs/aws//modules/service | ECS service and task definition | | `efs` | terraform-aws-modules/efs/aws | EFS file system with access points and mount targets | | `elasticache` | — | ElastiCache cluster (Redis/Memcached) | +| `eventbridge` | — | — | | `github-config` | — | GitHub OIDC provider and runner configuration | | `guardduty` | — | GuardDuty threat detection | | `iam` | terraform-aws-modules/iam/aws | IAM policies and roles | diff --git a/infrastructure/modules/eventbridge/.terraform.lock.hcl b/infrastructure/modules/eventbridge/.terraform.lock.hcl new file mode 100644 index 00000000..2f63013b --- /dev/null +++ b/infrastructure/modules/eventbridge/.terraform.lock.hcl @@ -0,0 +1,30 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "6.64.0" + constraints = ">= 6.42.0" + hashes = [ + "h1:/wtl8WUDUuXhCa2iiZA4Qm2uwo3sAi0zegrHiC7YiJ0=", + "h1:2fTLxzUDmp/KVIHbIeLTB4bIzWHx8E6Dw+1ALLUi+Yw=", + "h1:4siTahLyzGh4BoMQcL7VXeL/mn8iR/zKv93NyhQob+0=", + "h1:EEWCXlg69fty/Qi+kehrREnVEaWdKnLlVon542b6nxQ=", + "h1:wXARLY+IeQ7ufYxCLTPCwToWGMRvOpiOTfJS97iwUzI=", + "zh:07172315d67bc9781240272759cdfc7bd32b7e72384a56862c2c1da3cca99a81", + "zh:154ce7d2659de9a59ddfe96d7cab41a9ddc2cb267a7d4bcdf4e737ff2ffdec06", + "zh:17324d4335a7a7ac01cc23eded530775606680ff53b47cb74a3cb95d1121f836", + "zh:307ab92324ec5a61b124881ab8cac1d9e316f4527dfd0e1b59794c229407eb4e", + "zh:31e25f1903661332e36a95283042dd3ec50b47c186db00663fbd976a11e6a6b2", + "zh:3311d9f3bd12a24886027dbe73859dcd1e67bd0e3046227a338cf2c7ca04d18e", + "zh:37916156a3aac3b29be3acebd15d53145ea4ab5d4aaa825eaebe75481fa00500", + "zh:4158cb8c38b3ac6aa98eb15935ec6bd7c30838d85d2b00acc9812df8382ae908", + "zh:5bfb9499c66d9db5b34dc5c60f426a1ab1baa5457ce2aefebca826a9c3f92fb0", + "zh:6eb29ead5a4aca3b1f35812e7e8c75419180e1928e479b458f206861277736db", + "zh:7a82b6dd0c0cdef8045a4adfbddd36acb86b6b23fcbed8e189c2d71f7dc4a502", + "zh:9556bd792032c3f7e73ea4dd08cec88dc1327f5a4a57d79c30ba844ae2b9a3c0", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:c5234180464cb800c83a41f57462742b802c150ad7d4417626fcd9cb511c01d2", + "zh:cd776b83b1f7b36635957350afe7ce28ba4e4ea3a5e2deb00d13dbd3b35d9d40", + "zh:fb583a7b791c6f915b86573d04f05ddbf7f1a5e4120c5d8a7450a3086c1225c4", + ] +} diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index 9df56b73..c4e39f5f 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -9,6 +9,32 @@ DAVEH +## Requirements + +| Name | Version | +| ---- | ------- | +| [terraform](#requirement\_terraform) | >= 1.13 | +| [aws](#requirement\_aws) | >= 6.42 | + +## Providers + +No providers. + +## Modules + +No modules. + +## Resources + +No resources. + +## Inputs + +No inputs. + +## Outputs + +No outputs. diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf new file mode 100644 index 00000000..e69de29b diff --git a/infrastructure/modules/eventbridge/outputs.tf b/infrastructure/modules/eventbridge/outputs.tf new file mode 100644 index 00000000..e69de29b diff --git a/infrastructure/modules/eventbridge/variables.tf b/infrastructure/modules/eventbridge/variables.tf new file mode 100644 index 00000000..e69de29b diff --git a/infrastructure/modules/eventbridge/versions.tf b/infrastructure/modules/eventbridge/versions.tf new file mode 100644 index 00000000..cb30fe5c --- /dev/null +++ b/infrastructure/modules/eventbridge/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.13" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 6.42" + } + } +} From b39c1553da8696126139bebcbf5b531ac09b2566 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Thu, 10 Sep 2026 11:58:08 +0100 Subject: [PATCH 03/35] chore: start main --- infrastructure/modules/eventbridge/README.md | 4 ++- infrastructure/modules/eventbridge/main.tf | 26 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index c4e39f5f..405b89dd 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -22,7 +22,9 @@ No providers. ## Modules -No modules. +| Name | Source | Version | +| ---- | ------ | ------- | +| [eventbridge](#module\_eventbridge) | git::https://github.com/terraform-aws-modules/terraform-aws-eventbridge.git | f9934726324c988f823682884b4fa003586a7b6f | ## Resources diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index e69de29b..dc627bbf 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -0,0 +1,26 @@ +module "eventbridge" { + source = "git::https://github.com/terraform-aws-modules/terraform-aws-eventbridge.git?ref=f9934726324c988f823682884b4fa003586a7b6f" # v4.3.2 + + # Using a separate EventBridge bus per workspace would remove collisions for resources scoped to a bus: + # + # - rules keys and rule names + # - targets associated with those rules + # - archives + # - EventBridge permissions + # - bus-specific log-delivery associations + # + # However, these remain account/region-wide and still need workspace-unique names: + # + # - IAM role role_name + # - Generated IAM policy names + # - EventBridge connections + # - API destinations + # - Scheduler schedule groups and schedules + # - EventBridge Pipes + # - Log-delivery source and destination names + # + # The bus itself also needs a workspace-unique bus_name. + # DAVEH: rm above comment when actioned + + # DAVEH: add attributes +} From 5cf7482d41b5424c3b40ca2e8a01a902e57a8326 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Fri, 11 Sep 2026 11:49:57 +0100 Subject: [PATCH 04/35] docs: start notes --- infrastructure/modules/eventbridge/NOTES.md | 108 ++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 infrastructure/modules/eventbridge/NOTES.md diff --git a/infrastructure/modules/eventbridge/NOTES.md b/infrastructure/modules/eventbridge/NOTES.md new file mode 100644 index 00000000..cd220065 --- /dev/null +++ b/infrastructure/modules/eventbridge/NOTES.md @@ -0,0 +1,108 @@ +# Implementation Notes + +DAVEH: rm or tidy + +These notes are about v4.3.2 of the underlying `terraform-aws-modules/terraform-aws-eventbridge` community module. + +The main on/off switch is called `create`. + +## Underlying resources + +### `aws_cloudwatch_event_bus.this` + +- data/resource +- gated by `var.create_bus`; can otherwise add to an existing bus +- named by `var.bus_name` + - default account bus (created by AWS) is named `default` +- events on the bus are encrypted by `var.kms_key_identifier` + - can be the key ARN, KeyId, key alias, or key alias ARN + +### `aws_cloudwatch_event_api_destination.this` + +### `aws_cloudwatch_event_archive.this` + +### `aws_cloudwatch_event_connection.this` + +### `aws_cloudwatch_event_permission.this` + +### `aws_cloudwatch_event_rule.this` + +### `aws_cloudwatch_event_target.this` + +### `aws_cloudwatch_log_delivery.this` + +### `aws_cloudwatch_log_delivery_destination.this` + +### `aws_cloudwatch_log_delivery_source.this` + +### `aws_iam_policy.additional_inline` + +### `aws_iam_policy.additional_json` + +### `aws_iam_policy.additional_jsons` + +### `aws_iam_policy.api_destination` + +### `aws_iam_policy.cloudwatch` + +### `aws_iam_policy.ecs` + +### `aws_iam_policy.kinesis` + +### `aws_iam_policy.kinesis_firehose` + +### `aws_iam_policy.lambda` + +### `aws_iam_policy.service` + +### `aws_iam_policy.sfn` + +### `aws_iam_policy.sns` + +### `aws_iam_policy.sqs` + +### `aws_iam_policy.tracing` + +### `aws_iam_policy_attachment.additional_inline` + +### `aws_iam_policy_attachment.additional_json` + +### `aws_iam_policy_attachment.additional_jsons` + +### `aws_iam_policy_attachment.api_destination` + +### `aws_iam_policy_attachment.cloudwatch` + +### `aws_iam_policy_attachment.ecs` + +### `aws_iam_policy_attachment.kinesis` + +### `aws_iam_policy_attachment.kinesis_firehose` + +### `aws_iam_policy_attachment.lambda` + +### `aws_iam_policy_attachment.service` + +### `aws_iam_policy_attachment.sfn` + +### `aws_iam_policy_attachment.sns` + +### `aws_iam_policy_attachment.sqs` + +### `aws_iam_policy_attachment.tracing` + +### `aws_iam_role.eventbridge` + +### `aws_iam_role.eventbridge_pipe` + +### `aws_iam_role_policy_attachment.additional_many` + +### `aws_iam_role_policy_attachment.additional_one` + +### `aws_pipes_pipe.this` + +### `aws_scheduler_schedule.this` + +### `aws_scheduler_schedule_group.this` + +### `aws_schemas_discoverer.this` From 9d8531c0df04e62808ecebe3063a7f43f671f8a6 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Tue, 15 Sep 2026 10:58:58 +0100 Subject: [PATCH 05/35] docs: continue notes --- infrastructure/modules/eventbridge/NOTES.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/infrastructure/modules/eventbridge/NOTES.md b/infrastructure/modules/eventbridge/NOTES.md index cd220065..1fd5af0b 100644 --- a/infrastructure/modules/eventbridge/NOTES.md +++ b/infrastructure/modules/eventbridge/NOTES.md @@ -19,8 +19,18 @@ The main on/off switch is called `create`. ### `aws_cloudwatch_event_api_destination.this` +- resource +- gated by `var.create_api_destinations` +- named by `var.api_destinations` keys + - modified if `var.append_destination_postfix` is true + ### `aws_cloudwatch_event_archive.this` +- resource +- gated by `var.create_archives` +- named by `name` field of `var.archives` sub-value, falling back to `var.archives` key +- encrypted using `kms_key_identifier` field of `var.archives` sub-value, falling back to unencrypted + ### `aws_cloudwatch_event_connection.this` ### `aws_cloudwatch_event_permission.this` From 64f35bff6750efdf39246f62aec145cb68eb41e7 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Tue, 15 Sep 2026 13:06:10 +0100 Subject: [PATCH 06/35] docs: more notes --- infrastructure/modules/eventbridge/NOTES.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/infrastructure/modules/eventbridge/NOTES.md b/infrastructure/modules/eventbridge/NOTES.md index 1fd5af0b..5c84a3f2 100644 --- a/infrastructure/modules/eventbridge/NOTES.md +++ b/infrastructure/modules/eventbridge/NOTES.md @@ -33,10 +33,24 @@ The main on/off switch is called `create`. ### `aws_cloudwatch_event_connection.this` +- resource +- gated by `var.create_connections` +- named by `Name` field of `var.connections` sub-value + - modified if `var.append_connection_postfix` is true +- encrypted using `kms_key_identifier` field of `var.archives` sub-value, falling back to unencrypted + ### `aws_cloudwatch_event_permission.this` +- resource +- gated by `var.create_permissions` + ### `aws_cloudwatch_event_rule.this` +- resource +- gated by `var.create_rules` +- named by `var.rules` key + - modified if `var.append_rule_postfix` is true + ### `aws_cloudwatch_event_target.this` ### `aws_cloudwatch_log_delivery.this` From 73f79bd8b59588a043705cccf2b9ec2da400ddb5 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Tue, 15 Sep 2026 13:29:47 +0100 Subject: [PATCH 07/35] docs: document name uniqueness requirements --- infrastructure/modules/eventbridge/NOTES.md | 86 +++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/infrastructure/modules/eventbridge/NOTES.md b/infrastructure/modules/eventbridge/NOTES.md index 5c84a3f2..38967579 100644 --- a/infrastructure/modules/eventbridge/NOTES.md +++ b/infrastructure/modules/eventbridge/NOTES.md @@ -12,6 +12,7 @@ The main on/off switch is called `create`. - data/resource - gated by `var.create_bus`; can otherwise add to an existing bus +- name status: named and must be unique per AWS account and region - named by `var.bus_name` - default account bus (created by AWS) is named `default` - events on the bus are encrypted by `var.kms_key_identifier` @@ -21,6 +22,7 @@ The main on/off switch is called `create`. - resource - gated by `var.create_api_destinations` +- name status: named and must be unique per AWS account and region - named by `var.api_destinations` keys - modified if `var.append_destination_postfix` is true @@ -28,6 +30,7 @@ The main on/off switch is called `create`. - resource - gated by `var.create_archives` +- name status: named and must be unique per event bus - named by `name` field of `var.archives` sub-value, falling back to `var.archives` key - encrypted using `kms_key_identifier` field of `var.archives` sub-value, falling back to unencrypted @@ -35,6 +38,7 @@ The main on/off switch is called `create`. - resource - gated by `var.create_connections` +- name status: named and must be unique per AWS account and region - named by `Name` field of `var.connections` sub-value - modified if `var.append_connection_postfix` is true - encrypted using `kms_key_identifier` field of `var.archives` sub-value, falling back to unencrypted @@ -43,90 +47,172 @@ The main on/off switch is called `create`. - resource - gated by `var.create_permissions` +- name status: unnamed; its statement ID must be unique on the event bus ### `aws_cloudwatch_event_rule.this` - resource - gated by `var.create_rules` +- name status: named and must be unique per event bus - named by `var.rules` key - modified if `var.append_rule_postfix` is true ### `aws_cloudwatch_event_target.this` +- name status: unnamed; its target ID must be unique per rule on an event bus + ### `aws_cloudwatch_log_delivery.this` +- name status: unnamed; one delivery is allowed per source-destination pair + ### `aws_cloudwatch_log_delivery_destination.this` +- name status: named and must be unique per AWS account + ### `aws_cloudwatch_log_delivery_source.this` +- name status: named and must be unique per AWS account + ### `aws_iam_policy.additional_inline` +- name status: named and must be unique per AWS account + ### `aws_iam_policy.additional_json` +- name status: named and must be unique per AWS account + ### `aws_iam_policy.additional_jsons` +- name status: named and must be unique per AWS account + ### `aws_iam_policy.api_destination` +- name status: named and must be unique per AWS account + ### `aws_iam_policy.cloudwatch` +- name status: named and must be unique per AWS account + ### `aws_iam_policy.ecs` +- name status: named and must be unique per AWS account + ### `aws_iam_policy.kinesis` +- name status: named and must be unique per AWS account + ### `aws_iam_policy.kinesis_firehose` +- name status: named and must be unique per AWS account + ### `aws_iam_policy.lambda` +- name status: named and must be unique per AWS account + ### `aws_iam_policy.service` +- name status: named and must be unique per AWS account + ### `aws_iam_policy.sfn` +- name status: named and must be unique per AWS account + ### `aws_iam_policy.sns` +- name status: named and must be unique per AWS account + ### `aws_iam_policy.sqs` +- name status: named and must be unique per AWS account + ### `aws_iam_policy.tracing` +- name status: named and must be unique per AWS account + ### `aws_iam_policy_attachment.additional_inline` +- name status: unnamed; this is an attachment relationship identified by the policy and target ARNs + ### `aws_iam_policy_attachment.additional_json` +- name status: unnamed; this is an attachment relationship identified by the policy and target ARNs + ### `aws_iam_policy_attachment.additional_jsons` +- name status: unnamed; this is an attachment relationship identified by the policy and target ARNs + ### `aws_iam_policy_attachment.api_destination` +- name status: unnamed; this is an attachment relationship identified by the policy and target ARNs + ### `aws_iam_policy_attachment.cloudwatch` +- name status: unnamed; this is an attachment relationship identified by the policy and target ARNs + ### `aws_iam_policy_attachment.ecs` +- name status: unnamed; this is an attachment relationship identified by the policy and target ARNs + ### `aws_iam_policy_attachment.kinesis` +- name status: unnamed; this is an attachment relationship identified by the policy and target ARNs + ### `aws_iam_policy_attachment.kinesis_firehose` +- name status: unnamed; this is an attachment relationship identified by the policy and target ARNs + ### `aws_iam_policy_attachment.lambda` +- name status: unnamed; this is an attachment relationship identified by the policy and target ARNs + ### `aws_iam_policy_attachment.service` +- name status: unnamed; this is an attachment relationship identified by the policy and target ARNs + ### `aws_iam_policy_attachment.sfn` +- name status: unnamed; this is an attachment relationship identified by the policy and target ARNs + ### `aws_iam_policy_attachment.sns` +- name status: unnamed; this is an attachment relationship identified by the policy and target ARNs + ### `aws_iam_policy_attachment.sqs` +- name status: unnamed; this is an attachment relationship identified by the policy and target ARNs + ### `aws_iam_policy_attachment.tracing` +- name status: unnamed; this is an attachment relationship identified by the policy and target ARNs + ### `aws_iam_role.eventbridge` +- name status: named and must be unique per AWS account + ### `aws_iam_role.eventbridge_pipe` +- name status: named and must be unique per AWS account + ### `aws_iam_role_policy_attachment.additional_many` +- name status: unnamed; this is an attachment relationship identified by the role and policy ARNs + ### `aws_iam_role_policy_attachment.additional_one` +- name status: unnamed; this is an attachment relationship identified by the role and policy ARNs + ### `aws_pipes_pipe.this` +- name status: named and must be unique per AWS account and region + ### `aws_scheduler_schedule.this` +- name status: named and must be unique per schedule group + ### `aws_scheduler_schedule_group.this` +- name status: named and must be unique per AWS account and region + ### `aws_schemas_discoverer.this` + +- name status: named and must be unique per AWS account and region From 3bb5cb533f012753d7197bbfbaec54e69250db20 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Tue, 15 Sep 2026 14:51:36 +0100 Subject: [PATCH 08/35] docs: document encryption key inputs --- infrastructure/modules/eventbridge/NOTES.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/infrastructure/modules/eventbridge/NOTES.md b/infrastructure/modules/eventbridge/NOTES.md index 38967579..634239b5 100644 --- a/infrastructure/modules/eventbridge/NOTES.md +++ b/infrastructure/modules/eventbridge/NOTES.md @@ -41,7 +41,7 @@ The main on/off switch is called `create`. - name status: named and must be unique per AWS account and region - named by `Name` field of `var.connections` sub-value - modified if `var.append_connection_postfix` is true -- encrypted using `kms_key_identifier` field of `var.archives` sub-value, falling back to unencrypted +- encrypted using `kms_key_identifier` field of `var.connections` sub-value, falling back to unencrypted ### `aws_cloudwatch_event_permission.this` @@ -204,10 +204,12 @@ The main on/off switch is called `create`. ### `aws_pipes_pipe.this` - name status: named and must be unique per AWS account and region +- encrypted using `kms_key_identifier` field of `var.pipes` sub-value, falling back to unencrypted ### `aws_scheduler_schedule.this` - name status: named and must be unique per schedule group +- encrypted using `kms_key_arn` field of `var.schedules` sub-value, falling back to unencrypted ### `aws_scheduler_schedule_group.this` From abadb899d70c76d95b0820b46c0e3bfc63869c51 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 08:05:42 +0100 Subject: [PATCH 09/35] docs: rm comment that is expanded on by notes --- infrastructure/modules/eventbridge/main.tf | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index dc627bbf..daf911c8 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -1,26 +1,5 @@ module "eventbridge" { source = "git::https://github.com/terraform-aws-modules/terraform-aws-eventbridge.git?ref=f9934726324c988f823682884b4fa003586a7b6f" # v4.3.2 - # Using a separate EventBridge bus per workspace would remove collisions for resources scoped to a bus: - # - # - rules keys and rule names - # - targets associated with those rules - # - archives - # - EventBridge permissions - # - bus-specific log-delivery associations - # - # However, these remain account/region-wide and still need workspace-unique names: - # - # - IAM role role_name - # - Generated IAM policy names - # - EventBridge connections - # - API destinations - # - Scheduler schedule groups and schedules - # - EventBridge Pipes - # - Log-delivery source and destination names - # - # The bus itself also needs a workspace-unique bus_name. - # DAVEH: rm above comment when actioned - # DAVEH: add attributes } From 4d8f182261c18f58de7b0d61ba399408fc2dcaea Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 08:17:27 +0100 Subject: [PATCH 10/35] chore: add context --- infrastructure/modules/eventbridge/README.md | 35 +- infrastructure/modules/eventbridge/context.tf | 376 ++++++++++++++++++ infrastructure/modules/eventbridge/main.tf | 3 + 3 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 infrastructure/modules/eventbridge/context.tf diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index 405b89dd..0de5a75b 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -25,6 +25,7 @@ No providers. | Name | Source | Version | | ---- | ------ | ------- | | [eventbridge](#module\_eventbridge) | git::https://github.com/terraform-aws-modules/terraform-aws-eventbridge.git | f9934726324c988f823682884b4fa003586a7b6f | +| [this](#module\_this) | ../tags | n/a | ## Resources @@ -32,7 +33,39 @@ No resources. ## Inputs -No inputs. +| Name | Description | Type | Default | Required | +| ---- | ----------- | ---- | ------- | :------: | +| [additional\_tag\_map](#input\_additional\_tag\_map) | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.
This is for some rare cases where resources want additional configuration of tags
and therefore take a list of maps with tag key, value, and additional configuration. | `map(string)` | `{}` | no | +| [application\_role](#input\_application\_role) | The role the application is performing | `string` | `"General"` | no | +| [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
in the order they appear in the list. New attributes are appended to the
end of the list. The elements of the list are joined by the `delimiter`
and treated as a single ID element. | `list(string)` | `[]` | no | +| [aws\_region](#input\_aws\_region) | The AWS region | `string` | `"eu-west-2"` | no | +| [context](#input\_context) | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"descriptor_formats": {},
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"labels_as_tags": [
"unset"
],
"name": null,
"project": null,
"regex_replace_chars": null,
"region": null,
"service": null,
"stack": null,
"tags": {},
"terraform_source": null,
"workspace": null
}
| no | +| [data\_classification](#input\_data\_classification) | Used to identify the data classification of the resource, e.g 1-5 | `string` | `"n/a"` | no | +| [data\_type](#input\_data\_type) | The tag data\_type | `string` | `"None"` | no | +| [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no | +| [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| [environment](#input\_environment) | ID element. Usually used to indicate role, e.g. 'prd', 'dev', 'test', 'preprod', 'prod', 'uat' | `string` | `null` | no | +| [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | +| [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no | +| [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`. | `string` | `null` | no | +| [labels\_as\_tags](#input\_labels\_as\_tags) | Set of labels (ID elements) to include as tags in the `tags` output.
Default is to include all labels.
Tags with empty values will not be included in the `tags` output.
Set to `[]` to suppress all generated tags.
**Notes:**
The value of the `name` tag, if included, will be the `id`, not the `name`.
Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be
changed in later chained modules. Attempts to change it will be silently ignored. | `set(string)` |
[
"default"
]
| no | +| [name](#input\_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no | +| [on\_off\_pattern](#input\_on\_off\_pattern) | Used to turn resources on and off based on a time pattern | `string` | `"n/a"` | no | +| [owner](#input\_owner) | The name and or NHS.net email address of the service owner | `string` | `"None"` | no | +| [project](#input\_project) | ID element. A project identifier, indicating the name or role of the project the resource is for, such as `website` or `api` | `string` | `null` | no | +| [public\_facing](#input\_public\_facing) | Whether this resource is public facing | `bool` | `false` | no | +| [regex\_replace\_chars](#input\_regex\_replace\_chars) | Terraform regular expression (regex) string.
Characters matching the regex will be removed from the ID elements.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| [region](#input\_region) | ID element \_(Rarely used, not included by default)\_. Usually an abbreviation of the selected AWS region e.g. 'uw2', 'ew2' or 'gbl' for resources like IAM roles that have no region | `string` | `null` | no | +| [service](#input\_service) | ID element. Usually an abbreviation of your service directorate name, e.g. 'bcss' or 'csms', to help ensure generated IDs are globally unique | `string` | `null` | no | +| [service\_category](#input\_service\_category) | The tag service\_category | `string` | `"n/a"` | no | +| [stack](#input\_stack) | ID element. The name of the stack/component, e.g. `database`, `web`, `waf`, `eks` | `string` | `null` | no | +| [tag\_version](#input\_tag\_version) | Used to identify the tagging version in use | `string` | `"1.0"` | no | +| [tags](#input\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no | +| [terraform\_source](#input\_terraform\_source) | Source location to record in the Terraform\_source tag. Defaults to the caller module path when not set. | `string` | `null` | no | +| [tool](#input\_tool) | The tool used to deploy the resource | `string` | `"Terraform"` | no | +| [workspace](#input\_workspace) | ID element. The Terraform workspace, to help ensure generated IDs are unique across workspaces | `string` | `null` | no | ## Outputs diff --git a/infrastructure/modules/eventbridge/context.tf b/infrastructure/modules/eventbridge/context.tf new file mode 100644 index 00000000..e934a84f --- /dev/null +++ b/infrastructure/modules/eventbridge/context.tf @@ -0,0 +1,376 @@ +# tflint-ignore-file: terraform_standard_module_structure, terraform_unused_declarations +# +# ONLY EDIT THIS FILE IN github.com/NHSDigital/screening-terraform-modules-aws/infrastructure/modules/tags +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/NHSDigital/screening-terraform-modules-aws/blob/master/infrastructure/modules/tags/exports/context.tf +# and then place it in your Terraform module to automatically get +# tag module standard configuration inputs suitable for passing +# to other modules. +# +# curl -sL https://raw.githubusercontent.com/NHSDigital/screening-terraform-modules-aws/master/infrastructure/modules/tags/exports/context.tf -o context.tf +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "../tags" + + enabled = var.enabled + service = var.service + project = var.project + region = var.region + environment = var.environment + stack = var.stack + workspace = var.workspace + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + terraform_source = coalesce(var.terraform_source, path.module) + descriptor_formats = var.descriptor_formats + labels_as_tags = var.labels_as_tags + + context = var.context +} + +# Copy contents of screening-terraform-modules-aws/tags/variables.tf here +# tflint-ignore: terraform_unused_declarations +variable "aws_region" { + type = string + description = "The AWS region" + default = "eu-west-2" + validation { + condition = contains(["eu-west-1", "eu-west-2", "us-east-1"], var.aws_region) + error_message = "AWS Region must be one of eu-west-1, eu-west-2, us-east-1" + } +} + +variable "context" { + type = any + default = { + enabled = true + service = null + project = null + region = null + environment = null + stack = null + workspace = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + terraform_source = null + descriptor_formats = {} + # Note: we have to use [] instead of null for unset lists due to + # https://github.com/hashicorp/terraform/issues/28137 + # which was not fixed until Terraform 1.0.0, + # but we want the default to be all the labels in `label_order` + # and we want users to be able to prevent all tag generation + # by setting `labels_as_tags` to `[]`, so we need + # a different sentinel to indicate "default" + labels_as_tags = ["unset"] + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "terraform_source" { + type = string + default = null + description = "Source location to record in the Terraform_source tag. Defaults to the caller module path when not set." +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "service" { + type = string + default = null + description = "ID element. Usually an abbreviation of your service directorate name, e.g. 'bcss' or 'csms', to help ensure generated IDs are globally unique" +} + +variable "region" { + type = string + default = null + description = "ID element _(Rarely used, not included by default)_. Usually an abbreviation of the selected AWS region e.g. 'uw2', 'ew2' or 'gbl' for resources like IAM roles that have no region" +} + +variable "project" { + type = string + default = null + description = "ID element. A project identifier, indicating the name or role of the project the resource is for, such as `website` or `api`" +} +variable "stack" { + type = string + default = null + description = "ID element. The name of the stack/component, e.g. `database`, `web`, `waf`, `eks`" +} +variable "workspace" { + type = string + default = null + description = "ID element. The Terraform workspace, to help ensure generated IDs are unique across workspaces" +} +variable "environment" { + type = string + default = null + description = "ID element. Usually used to indicate role, e.g. 'prd', 'dev', 'test', 'preprod', 'prod', 'uat'" +} + +variable "name" { + type = string + default = null + description = <<-EOT + ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'. + This is the only ID element not also included as a `tag`. + The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. + EOT +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between ID elements. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = <<-EOT + ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`, + in the order they appear in the list. New attributes are appended to the + end of the list. The elements of the list are joined by the `delimiter` + and treated as a single ID element. + EOT +} + +variable "labels_as_tags" { + type = set(string) + default = ["default"] + description = <<-EOT + Set of labels (ID elements) to include as tags in the `tags` output. + Default is to include all labels. + Tags with empty values will not be included in the `tags` output. + Set to `[]` to suppress all generated tags. + **Notes:** + The value of the `name` tag, if included, will be the `id`, not the `name`. + Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be + changed in later chained modules. Attempts to change it will be silently ignored. + EOT +} + +variable "tags" { + type = map(string) + default = {} + description = <<-EOT + Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`). + Neither the tag keys nor the tag values will be modified by this module. + EOT +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = <<-EOT + Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`. + This is for some rare cases where resources want additional configuration of tags + and therefore take a list of maps with tag key, value, and additional configuration. + EOT +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The order in which the labels (ID elements) appear in the `id`. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Terraform regular expression (regex) string. + Characters matching the regex will be removed from the ID elements. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for keep the existing setting, which defaults to `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + Controls the letter case of the `tags` keys (label names) for tags generated by this module. + Does not affect keys of tags passed in via the `tags` input. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + Controls the letter case of ID elements (labels) as included in `id`, + set as tag values, and output by this module individually. + Does not affect values of tags passed in via the `tags` input. + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs. + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "descriptor_formats" { + type = any + default = {} + description = <<-EOT + Describe additional descriptors to be output in the `descriptors` output map. + Map of maps. Keys are names of descriptors. Values are maps of the form + `{ + format = string + labels = list(string) + }` + (Type is `any` so the map values can later be enhanced to provide additional options.) + `format` is a Terraform format string to be passed to the `format()` function. + `labels` is a list of labels, in order, to pass to `format()` function. + Label values will be normalized before being passed to `format()` so they will be + identical to how they appear in `id`. + Default is `{}` (`descriptors` output will be empty). + EOT +} + +variable "owner" { + type = string + description = "The name and or NHS.net email address of the service owner" + default = "None" +} + +variable "tag_version" { + type = string + description = "Used to identify the tagging version in use" + default = "1.0" +} + +variable "data_classification" { + type = string + description = "Used to identify the data classification of the resource, e.g 1-5" + default = "n/a" + validation { + condition = contains(["n/a", "1", "2", "3", "4", "5"], var.data_classification) + error_message = "Data Classification must be \"n/a\" or between 1-5" + } +} + +variable "data_type" { + type = string + description = "The tag data_type" + default = "None" + validation { + condition = contains(["None", "PCD", "PID", "Anonymised", "UserAccount", "Audit"], var.data_type) + error_message = "Data Type must be one of None, PCD, PID, Anonymised, UserAccount, Audit" + } +} + + +variable "public_facing" { + type = bool + description = "Whether this resource is public facing" + default = false +} + +variable "service_category" { + type = string + description = "The tag service_category" + default = "n/a" + validation { + condition = contains(["n/a", "Bronze", "Silver", "Gold", "Platinum"], var.service_category) + error_message = "The Service Category must be one of n/a, Bronze, Silver, Gold, Platinum" + } +} +variable "on_off_pattern" { + type = string + description = "Used to turn resources on and off based on a time pattern" + default = "n/a" +} + +variable "application_role" { + type = string + description = "The role the application is performing" + default = "General" +} + +variable "tool" { + type = string + description = "The tool used to deploy the resource" + default = "Terraform" +} + +#### End of copy of screening-terraform-modules-aws/tags/variables.tf diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index daf911c8..8cc6c63a 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -1,5 +1,8 @@ module "eventbridge" { source = "git::https://github.com/terraform-aws-modules/terraform-aws-eventbridge.git?ref=f9934726324c988f823682884b4fa003586a7b6f" # v4.3.2 + create = module.this.enabled + tags = module.this.tags + # DAVEH: add attributes } From 9248d0ef5de32055b6bd5eb49e0480e7908e4544 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 08:55:46 +0100 Subject: [PATCH 11/35] feat: copy input variables from underlying module --- infrastructure/modules/eventbridge/README.md | 80 +++ infrastructure/modules/eventbridge/main.tf | 82 ++- .../modules/eventbridge/variables.tf | 494 ++++++++++++++++++ 3 files changed, 655 insertions(+), 1 deletion(-) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index 0de5a75b..7e352b08 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -36,35 +36,115 @@ No resources. | Name | Description | Type | Default | Required | | ---- | ----------- | ---- | ------- | :------: | | [additional\_tag\_map](#input\_additional\_tag\_map) | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.
This is for some rare cases where resources want additional configuration of tags
and therefore take a list of maps with tag key, value, and additional configuration. | `map(string)` | `{}` | no | +| [api\_destinations](#input\_api\_destinations) | A map of objects with EventBridge Destination definitions. | `map(any)` | `{}` | no | +| [append\_connection\_postfix](#input\_append\_connection\_postfix) | Controls whether to append '-connection' to the name of the connection | `bool` | `true` | no | +| [append\_destination\_postfix](#input\_append\_destination\_postfix) | Controls whether to append '-destination' to the name of the destination | `bool` | `true` | no | +| [append\_pipe\_postfix](#input\_append\_pipe\_postfix) | Controls whether to append '-pipe' to the name of the pipe | `bool` | `true` | no | +| [append\_rule\_postfix](#input\_append\_rule\_postfix) | Controls whether to append '-rule' to the name of the rule | `bool` | `true` | no | +| [append\_schedule\_group\_postfix](#input\_append\_schedule\_group\_postfix) | Controls whether to append '-group' to the name of the schedule group | `bool` | `true` | no | +| [append\_schedule\_postfix](#input\_append\_schedule\_postfix) | Controls whether to append '-schedule' to the name of the schedule | `bool` | `true` | no | | [application\_role](#input\_application\_role) | The role the application is performing | `string` | `"General"` | no | +| [archives](#input\_archives) | A map of objects with the EventBridge Archive definitions. | `map(any)` | `{}` | no | +| [attach\_api\_destination\_policy](#input\_attach\_api\_destination\_policy) | Controls whether the API Destination policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | +| [attach\_cloudwatch\_policy](#input\_attach\_cloudwatch\_policy) | Controls whether the Cloudwatch policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | +| [attach\_ecs\_policy](#input\_attach\_ecs\_policy) | Controls whether the ECS policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | +| [attach\_kinesis\_firehose\_policy](#input\_attach\_kinesis\_firehose\_policy) | Controls whether the Kinesis Firehose policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | +| [attach\_kinesis\_policy](#input\_attach\_kinesis\_policy) | Controls whether the Kinesis policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | +| [attach\_lambda\_policy](#input\_attach\_lambda\_policy) | Controls whether the Lambda Function policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | +| [attach\_policies](#input\_attach\_policies) | Controls whether list of policies should be added to IAM role | `bool` | `false` | no | +| [attach\_policy](#input\_attach\_policy) | Controls whether policy should be added to IAM role | `bool` | `false` | no | +| [attach\_policy\_json](#input\_attach\_policy\_json) | Controls whether policy\_json should be added to IAM role | `bool` | `false` | no | +| [attach\_policy\_jsons](#input\_attach\_policy\_jsons) | Controls whether policy\_jsons should be added to IAM role | `bool` | `false` | no | +| [attach\_policy\_statements](#input\_attach\_policy\_statements) | Controls whether policy\_statements should be added to IAM role | `bool` | `false` | no | +| [attach\_sfn\_policy](#input\_attach\_sfn\_policy) | Controls whether the StepFunction policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | +| [attach\_sns\_policy](#input\_attach\_sns\_policy) | Controls whether the SNS policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | +| [attach\_sqs\_policy](#input\_attach\_sqs\_policy) | Controls whether the SQS policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | +| [attach\_tracing\_policy](#input\_attach\_tracing\_policy) | Controls whether X-Ray tracing policy should be added to IAM role for EventBridge | `bool` | `false` | no | | [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
in the order they appear in the list. New attributes are appended to the
end of the list. The elements of the list are joined by the `delimiter`
and treated as a single ID element. | `list(string)` | `[]` | no | | [aws\_region](#input\_aws\_region) | The AWS region | `string` | `"eu-west-2"` | no | +| [bus\_description](#input\_bus\_description) | Event bus description | `string` | `null` | no | +| [bus\_name](#input\_bus\_name) | A unique name for your EventBridge Bus | `string` | `"default"` | no | +| [cloudwatch\_target\_arns](#input\_cloudwatch\_target\_arns) | The Amazon Resource Name (ARN) of the Cloudwatch Log Streams you want to use as EventBridge targets | `list(string)` | `[]` | no | +| [connections](#input\_connections) | A map of objects with EventBridge Connection definitions. | `any` | `{}` | no | | [context](#input\_context) | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"descriptor_formats": {},
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"labels_as_tags": [
"unset"
],
"name": null,
"project": null,
"regex_replace_chars": null,
"region": null,
"service": null,
"stack": null,
"tags": {},
"terraform_source": null,
"workspace": null
}
| no | +| [create\_api\_destinations](#input\_create\_api\_destinations) | Controls whether EventBridge Destination resources should be created | `bool` | `false` | no | +| [create\_archives](#input\_create\_archives) | Controls whether EventBridge Archive resources should be created | `bool` | `false` | no | +| [create\_bus](#input\_create\_bus) | Controls whether EventBridge Bus resource should be created | `bool` | `true` | no | +| [create\_connections](#input\_create\_connections) | Controls whether EventBridge Connection resources should be created | `bool` | `false` | no | +| [create\_log\_delivery](#input\_create\_log\_delivery) | Controls whether EventBridge log delivery resources should be created | `bool` | `true` | no | +| [create\_log\_delivery\_source](#input\_create\_log\_delivery\_source) | Controls whether EventBridge log delivery source resource should be created | `bool` | `true` | no | +| [create\_permissions](#input\_create\_permissions) | Controls whether EventBridge Permission resources should be created | `bool` | `true` | no | +| [create\_pipe\_role\_only](#input\_create\_pipe\_role\_only) | Controls whether an IAM role should be created for the pipes only | `bool` | `false` | no | +| [create\_pipes](#input\_create\_pipes) | Controls whether EventBridge Pipes resources should be created | `bool` | `true` | no | +| [create\_role](#input\_create\_role) | Controls whether IAM roles should be created | `bool` | `true` | no | +| [create\_rules](#input\_create\_rules) | Controls whether EventBridge Rule resources should be created | `bool` | `true` | no | +| [create\_schedule\_groups](#input\_create\_schedule\_groups) | Controls whether EventBridge Schedule Group resources should be created | `bool` | `true` | no | +| [create\_schedules](#input\_create\_schedules) | Controls whether EventBridge Schedule resources should be created | `bool` | `true` | no | +| [create\_schemas\_discoverer](#input\_create\_schemas\_discoverer) | Controls whether default schemas discoverer should be created | `bool` | `false` | no | +| [create\_targets](#input\_create\_targets) | Controls whether EventBridge Target resources should be created | `bool` | `true` | no | | [data\_classification](#input\_data\_classification) | Used to identify the data classification of the resource, e.g 1-5 | `string` | `"n/a"` | no | | [data\_type](#input\_data\_type) | The tag data\_type | `string` | `"None"` | no | +| [dead\_letter\_config](#input\_dead\_letter\_config) | Configuration details of the Amazon SQS queue for EventBridge to use as a dead-letter queue (DLQ) | `any` | `{}` | no | | [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | | [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no | +| [ecs\_pass\_role\_resources](#input\_ecs\_pass\_role\_resources) | List of approved roles to be passed | `list(string)` | `[]` | no | +| [ecs\_target\_arns](#input\_ecs\_target\_arns) | The Amazon Resource Name (ARN) of the AWS ECS Tasks you want to use as EventBridge targets | `list(string)` | `[]` | no | | [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no | | [environment](#input\_environment) | ID element. Usually used to indicate role, e.g. 'prd', 'dev', 'test', 'preprod', 'prod', 'uat' | `string` | `null` | no | +| [event\_source\_name](#input\_event\_source\_name) | The partner event source that the new event bus will be matched with. Must match name. | `string` | `null` | no | | [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | +| [kinesis\_firehose\_target\_arns](#input\_kinesis\_firehose\_target\_arns) | The Amazon Resource Name (ARN) of the Kinesis Firehose Delivery Streams you want to use as EventBridge targets | `list(string)` | `[]` | no | +| [kinesis\_target\_arns](#input\_kinesis\_target\_arns) | The Amazon Resource Name (ARN) of the Kinesis Streams you want to use as EventBridge targets | `list(string)` | `[]` | no | +| [kms\_key\_identifier](#input\_kms\_key\_identifier) | 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. | `string` | `null` | no | | [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | | [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no | | [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`. | `string` | `null` | no | | [labels\_as\_tags](#input\_labels\_as\_tags) | Set of labels (ID elements) to include as tags in the `tags` output.
Default is to include all labels.
Tags with empty values will not be included in the `tags` output.
Set to `[]` to suppress all generated tags.
**Notes:**
The value of the `name` tag, if included, will be the `id`, not the `name`.
Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be
changed in later chained modules. Attempts to change it will be silently ignored. | `set(string)` |
[
"default"
]
| no | +| [lambda\_target\_arns](#input\_lambda\_target\_arns) | The Amazon Resource Name (ARN) of the Lambda Functions you want to use as EventBridge targets | `list(string)` | `[]` | no | +| [log\_config](#input\_log\_config) | The configuration block for the EventBridge bus log config settings |
object({
include_detail = string
level = string
})
| `null` | no | +| [log\_delivery](#input\_log\_delivery) | Map of the configuration block for the EventBridge bus log delivery settings (key is the type of log delivery: cloudwatch\_logs, s3, firehose) |
map(object({
enabled = optional(bool, true)
destination_arn = string
source_name = optional(string)
name = optional(string)
output_format = optional(string)
field_delimiter = optional(string)
record_fields = optional(list(string))
s3_delivery_configuration = optional(object({
enable_hive_compatible_path = optional(bool)
suffix_path = optional(string)
}))
}))
| `{}` | no | +| [log\_delivery\_source\_name](#input\_log\_delivery\_source\_name) | Name of log delivery source | `string` | `null` | no | | [name](#input\_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no | +| [number\_of\_policies](#input\_number\_of\_policies) | Number of policies to attach to IAM role | `number` | `0` | no | +| [number\_of\_policy\_jsons](#input\_number\_of\_policy\_jsons) | Number of policies JSON to attach to IAM role | `number` | `0` | no | | [on\_off\_pattern](#input\_on\_off\_pattern) | Used to turn resources on and off based on a time pattern | `string` | `"n/a"` | no | | [owner](#input\_owner) | The name and or NHS.net email address of the service owner | `string` | `"None"` | no | +| [permissions](#input\_permissions) | A map of objects with EventBridge Permission definitions. | `map(any)` | `{}` | no | +| [pipes](#input\_pipes) | A map of objects with EventBridge Pipe definitions. | `any` | `{}` | no | +| [policies](#input\_policies) | List of policy statements ARN to attach to IAM role | `list(string)` | `[]` | no | +| [policy](#input\_policy) | An additional policy document ARN to attach to IAM role | `string` | `null` | no | +| [policy\_json](#input\_policy\_json) | An additional policy document as JSON to attach to IAM role | `string` | `null` | no | +| [policy\_jsons](#input\_policy\_jsons) | List of additional policy documents as JSON to attach to IAM role | `list(string)` | `[]` | no | +| [policy\_path](#input\_policy\_path) | Path of IAM policy to use for EventBridge | `string` | `null` | no | +| [policy\_statements](#input\_policy\_statements) | Map of dynamic policy statements to attach to IAM role | `any` | `{}` | no | | [project](#input\_project) | ID element. A project identifier, indicating the name or role of the project the resource is for, such as `website` or `api` | `string` | `null` | no | | [public\_facing](#input\_public\_facing) | Whether this resource is public facing | `bool` | `false` | no | | [regex\_replace\_chars](#input\_regex\_replace\_chars) | Terraform regular expression (regex) string.
Characters matching the regex will be removed from the ID elements.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | | [region](#input\_region) | ID element \_(Rarely used, not included by default)\_. Usually an abbreviation of the selected AWS region e.g. 'uw2', 'ew2' or 'gbl' for resources like IAM roles that have no region | `string` | `null` | no | +| [role\_description](#input\_role\_description) | Description of IAM role to use for EventBridge | `string` | `null` | no | +| [role\_force\_detach\_policies](#input\_role\_force\_detach\_policies) | Specifies to force detaching any policies the IAM role has before destroying it. | `bool` | `true` | no | +| [role\_name](#input\_role\_name) | Name of IAM role to use for EventBridge | `string` | `null` | no | +| [role\_path](#input\_role\_path) | Path of IAM role to use for EventBridge | `string` | `null` | no | +| [role\_permissions\_boundary](#input\_role\_permissions\_boundary) | The ARN of the policy that is used to set the permissions boundary for the IAM role used by EventBridge | `string` | `null` | no | +| [role\_tags](#input\_role\_tags) | A map of tags to assign to IAM role | `map(string)` | `{}` | no | +| [rules](#input\_rules) | A map of objects with EventBridge Rule definitions. | `map(any)` | `{}` | no | +| [schedule\_group\_timeouts](#input\_schedule\_group\_timeouts) | A map of objects with EventBridge Schedule Group create and delete timeouts. | `map(string)` | `{}` | no | +| [schedule\_groups](#input\_schedule\_groups) | A map of objects with EventBridge Schedule Group definitions. | `any` | `{}` | no | +| [schedules](#input\_schedules) | A map of objects with EventBridge Schedule definitions. | `map(any)` | `{}` | no | +| [schemas\_discoverer\_description](#input\_schemas\_discoverer\_description) | Default schemas discoverer description | `string` | `"Auto schemas discoverer event"` | no | | [service](#input\_service) | ID element. Usually an abbreviation of your service directorate name, e.g. 'bcss' or 'csms', to help ensure generated IDs are globally unique | `string` | `null` | no | | [service\_category](#input\_service\_category) | The tag service\_category | `string` | `"n/a"` | no | +| [sfn\_target\_arns](#input\_sfn\_target\_arns) | The Amazon Resource Name (ARN) of the StepFunctions you want to use as EventBridge targets | `list(string)` | `[]` | no | +| [sns\_kms\_arns](#input\_sns\_kms\_arns) | The Amazon Resource Name (ARN) of the AWS KMS's configured for AWS SNS you want Decrypt/GenerateDataKey for | `list(string)` |
[
"*"
]
| no | +| [sns\_target\_arns](#input\_sns\_target\_arns) | The Amazon Resource Name (ARN) of the AWS SNS's you want to use as EventBridge targets | `list(string)` | `[]` | no | +| [sqs\_target\_arns](#input\_sqs\_target\_arns) | The Amazon Resource Name (ARN) of the AWS SQS Queues you want to use as EventBridge targets | `list(string)` | `[]` | no | | [stack](#input\_stack) | ID element. The name of the stack/component, e.g. `database`, `web`, `waf`, `eks` | `string` | `null` | no | | [tag\_version](#input\_tag\_version) | Used to identify the tagging version in use | `string` | `"1.0"` | no | | [tags](#input\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no | +| [targets](#input\_targets) | A map of objects with EventBridge Target definitions. | `any` | `{}` | no | | [terraform\_source](#input\_terraform\_source) | Source location to record in the Terraform\_source tag. Defaults to the caller module path when not set. | `string` | `null` | no | | [tool](#input\_tool) | The tool used to deploy the resource | `string` | `"Terraform"` | no | +| [trusted\_entities](#input\_trusted\_entities) | Additional trusted entities for assuming roles (trust relationship) | `list(string)` | `[]` | no | | [workspace](#input\_workspace) | ID element. The Terraform workspace, to help ensure generated IDs are unique across workspaces | `string` | `null` | no | ## Outputs diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index 8cc6c63a..c8ff6cc8 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -4,5 +4,85 @@ module "eventbridge" { create = module.this.enabled tags = module.this.tags - # DAVEH: add attributes + create_role = var.create_role + create_pipe_role_only = var.create_pipe_role_only + append_rule_postfix = var.append_rule_postfix + append_connection_postfix = var.append_connection_postfix + append_destination_postfix = var.append_destination_postfix + append_schedule_group_postfix = var.append_schedule_group_postfix + append_schedule_postfix = var.append_schedule_postfix + append_pipe_postfix = var.append_pipe_postfix + create_bus = var.create_bus + create_rules = var.create_rules + create_targets = var.create_targets + create_permissions = var.create_permissions + create_archives = var.create_archives + create_connections = var.create_connections + create_api_destinations = var.create_api_destinations + create_schemas_discoverer = var.create_schemas_discoverer + create_schedule_groups = var.create_schedule_groups + create_schedules = var.create_schedules + create_pipes = var.create_pipes + create_log_delivery_source = var.create_log_delivery_source + create_log_delivery = var.create_log_delivery + region = var.aws_region + bus_name = var.bus_name + bus_description = var.bus_description + log_config = var.log_config + log_delivery = var.log_delivery + log_delivery_source_name = var.log_delivery_source_name + event_source_name = var.event_source_name + kms_key_identifier = var.kms_key_identifier + dead_letter_config = var.dead_letter_config + schemas_discoverer_description = var.schemas_discoverer_description + rules = var.rules + targets = var.targets + archives = var.archives + permissions = var.permissions + connections = var.connections + api_destinations = var.api_destinations + schedule_groups = var.schedule_groups + schedules = var.schedules + pipes = var.pipes + schedule_group_timeouts = var.schedule_group_timeouts + role_name = var.role_name + role_description = var.role_description + role_path = var.role_path + policy_path = var.policy_path + role_force_detach_policies = var.role_force_detach_policies + role_permissions_boundary = var.role_permissions_boundary + role_tags = var.role_tags + ecs_pass_role_resources = var.ecs_pass_role_resources + attach_kinesis_policy = var.attach_kinesis_policy + attach_kinesis_firehose_policy = var.attach_kinesis_firehose_policy + attach_sqs_policy = var.attach_sqs_policy + attach_sns_policy = var.attach_sns_policy + attach_ecs_policy = var.attach_ecs_policy + attach_lambda_policy = var.attach_lambda_policy + attach_sfn_policy = var.attach_sfn_policy + attach_cloudwatch_policy = var.attach_cloudwatch_policy + attach_api_destination_policy = var.attach_api_destination_policy + attach_tracing_policy = var.attach_tracing_policy + kinesis_target_arns = var.kinesis_target_arns + kinesis_firehose_target_arns = var.kinesis_firehose_target_arns + sqs_target_arns = var.sqs_target_arns + sns_target_arns = var.sns_target_arns + sns_kms_arns = var.sns_kms_arns + ecs_target_arns = var.ecs_target_arns + lambda_target_arns = var.lambda_target_arns + sfn_target_arns = var.sfn_target_arns + cloudwatch_target_arns = var.cloudwatch_target_arns + attach_policy_json = var.attach_policy_json + attach_policy_jsons = var.attach_policy_jsons + attach_policy = var.attach_policy + attach_policies = var.attach_policies + number_of_policy_jsons = var.number_of_policy_jsons + number_of_policies = var.number_of_policies + attach_policy_statements = var.attach_policy_statements + trusted_entities = var.trusted_entities + policy_json = var.policy_json + policy_jsons = var.policy_jsons + policy = var.policy + policies = var.policies + policy_statements = var.policy_statements } diff --git a/infrastructure/modules/eventbridge/variables.tf b/infrastructure/modules/eventbridge/variables.tf index e69de29b..cb6b501b 100644 --- a/infrastructure/modules/eventbridge/variables.tf +++ b/infrastructure/modules/eventbridge/variables.tf @@ -0,0 +1,494 @@ +variable "create_role" { + description = "Controls whether IAM roles should be created" + type = bool + default = true +} + +variable "create_pipe_role_only" { + description = "Controls whether an IAM role should be created for the pipes only" + type = bool + default = false +} + +variable "append_rule_postfix" { + description = "Controls whether to append '-rule' to the name of the rule" + type = bool + default = true +} + +variable "append_connection_postfix" { + description = "Controls whether to append '-connection' to the name of the connection" + type = bool + default = true +} + +variable "append_destination_postfix" { + description = "Controls whether to append '-destination' to the name of the destination" + type = bool + default = true +} + +variable "append_schedule_group_postfix" { + description = "Controls whether to append '-group' to the name of the schedule group" + type = bool + default = true +} + +variable "append_schedule_postfix" { + description = "Controls whether to append '-schedule' to the name of the schedule" + type = bool + default = true +} + +variable "append_pipe_postfix" { + description = "Controls whether to append '-pipe' to the name of the pipe" + type = bool + default = true +} + +variable "create_bus" { + description = "Controls whether EventBridge Bus resource should be created" + type = bool + default = true +} + +variable "create_rules" { + description = "Controls whether EventBridge Rule resources should be created" + type = bool + default = true +} + +variable "create_targets" { + description = "Controls whether EventBridge Target resources should be created" + type = bool + default = true +} + +variable "create_permissions" { + description = "Controls whether EventBridge Permission resources should be created" + type = bool + default = true +} + +variable "create_archives" { + description = "Controls whether EventBridge Archive resources should be created" + type = bool + default = false +} + +variable "create_connections" { + description = "Controls whether EventBridge Connection resources should be created" + type = bool + default = false +} + +variable "create_api_destinations" { + description = "Controls whether EventBridge Destination resources should be created" + type = bool + default = false +} + +variable "create_schemas_discoverer" { + description = "Controls whether default schemas discoverer should be created" + type = bool + default = false +} + +variable "create_schedule_groups" { + description = "Controls whether EventBridge Schedule Group resources should be created" + type = bool + default = true +} + +variable "create_schedules" { + description = "Controls whether EventBridge Schedule resources should be created" + type = bool + default = true +} + +variable "create_pipes" { + description = "Controls whether EventBridge Pipes resources should be created" + type = bool + default = true +} + +variable "create_log_delivery_source" { + description = "Controls whether EventBridge log delivery source resource should be created" + type = bool + default = true +} + +variable "create_log_delivery" { + description = "Controls whether EventBridge log delivery resources should be created" + type = bool + default = true +} + +variable "bus_name" { + description = "A unique name for your EventBridge Bus" + type = string + default = "default" +} + +variable "bus_description" { + description = "Event bus description" + type = string + default = null +} + +variable "log_config" { + description = "The configuration block for the EventBridge bus log config settings" + type = object({ + include_detail = string + level = string + }) + default = null +} + +variable "log_delivery" { + description = "Map of the configuration block for the EventBridge bus log delivery settings (key is the type of log delivery: cloudwatch_logs, s3, firehose)" + type = map(object({ + enabled = optional(bool, true) + destination_arn = string + source_name = optional(string) + name = optional(string) + output_format = optional(string) + field_delimiter = optional(string) + record_fields = optional(list(string)) + s3_delivery_configuration = optional(object({ + enable_hive_compatible_path = optional(bool) + suffix_path = optional(string) + })) + })) + default = {} +} + +variable "log_delivery_source_name" { + description = "Name of log delivery source" + type = string + default = null +} + +variable "event_source_name" { + description = "The partner event source that the new event bus will be matched with. Must match name." + type = string + default = null +} + +variable "kms_key_identifier" { + description = "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." + type = string + default = null +} + +variable "dead_letter_config" { + description = "Configuration details of the Amazon SQS queue for EventBridge to use as a dead-letter queue (DLQ)" + type = any + default = {} +} + +variable "schemas_discoverer_description" { + description = "Default schemas discoverer description" + type = string + default = "Auto schemas discoverer event" +} + +variable "rules" { + description = "A map of objects with EventBridge Rule definitions." + type = map(any) + default = {} +} + +variable "targets" { + description = "A map of objects with EventBridge Target definitions." + type = any + default = {} +} + +variable "archives" { + description = "A map of objects with the EventBridge Archive definitions." + type = map(any) + default = {} +} + +variable "permissions" { + description = "A map of objects with EventBridge Permission definitions." + type = map(any) + default = {} +} + +variable "connections" { + description = "A map of objects with EventBridge Connection definitions." + type = any + default = {} +} + +variable "api_destinations" { + description = "A map of objects with EventBridge Destination definitions." + type = map(any) + default = {} +} + +variable "schedule_groups" { + description = "A map of objects with EventBridge Schedule Group definitions." + type = any + default = {} +} + +variable "schedules" { + description = "A map of objects with EventBridge Schedule definitions." + type = map(any) + default = {} +} + +variable "pipes" { + description = "A map of objects with EventBridge Pipe definitions." + type = any + default = {} +} + +variable "schedule_group_timeouts" { + description = "A map of objects with EventBridge Schedule Group create and delete timeouts." + type = map(string) + default = {} +} + +variable "role_name" { + description = "Name of IAM role to use for EventBridge" + type = string + default = null +} + +variable "role_description" { + description = "Description of IAM role to use for EventBridge" + type = string + default = null +} + +variable "role_path" { + description = "Path of IAM role to use for EventBridge" + type = string + default = null +} + +variable "policy_path" { + description = "Path of IAM policy to use for EventBridge" + type = string + default = null +} + +variable "role_force_detach_policies" { + description = "Specifies to force detaching any policies the IAM role has before destroying it." + type = bool + default = true +} + +variable "role_permissions_boundary" { + description = "The ARN of the policy that is used to set the permissions boundary for the IAM role used by EventBridge" + type = string + default = null +} + +variable "role_tags" { + description = "A map of tags to assign to IAM role" + type = map(string) + default = {} +} + +variable "ecs_pass_role_resources" { + description = "List of approved roles to be passed" + type = list(string) + default = [] +} + +variable "attach_kinesis_policy" { + description = "Controls whether the Kinesis policy should be added to IAM role for EventBridge Target" + type = bool + default = false +} + +variable "attach_kinesis_firehose_policy" { + description = "Controls whether the Kinesis Firehose policy should be added to IAM role for EventBridge Target" + type = bool + default = false +} + +variable "attach_sqs_policy" { + description = "Controls whether the SQS policy should be added to IAM role for EventBridge Target" + type = bool + default = false +} + +variable "attach_sns_policy" { + description = "Controls whether the SNS policy should be added to IAM role for EventBridge Target" + type = bool + default = false +} + +variable "attach_ecs_policy" { + description = "Controls whether the ECS policy should be added to IAM role for EventBridge Target" + type = bool + default = false +} + +variable "attach_lambda_policy" { + description = "Controls whether the Lambda Function policy should be added to IAM role for EventBridge Target" + type = bool + default = false +} + +variable "attach_sfn_policy" { + description = "Controls whether the StepFunction policy should be added to IAM role for EventBridge Target" + type = bool + default = false +} + +variable "attach_cloudwatch_policy" { + description = "Controls whether the Cloudwatch policy should be added to IAM role for EventBridge Target" + type = bool + default = false +} + +variable "attach_api_destination_policy" { + description = "Controls whether the API Destination policy should be added to IAM role for EventBridge Target" + type = bool + default = false +} + +variable "attach_tracing_policy" { + description = "Controls whether X-Ray tracing policy should be added to IAM role for EventBridge" + type = bool + default = false +} + +variable "kinesis_target_arns" { + description = "The Amazon Resource Name (ARN) of the Kinesis Streams you want to use as EventBridge targets" + type = list(string) + default = [] +} + +variable "kinesis_firehose_target_arns" { + description = "The Amazon Resource Name (ARN) of the Kinesis Firehose Delivery Streams you want to use as EventBridge targets" + type = list(string) + default = [] +} + +variable "sqs_target_arns" { + description = "The Amazon Resource Name (ARN) of the AWS SQS Queues you want to use as EventBridge targets" + type = list(string) + default = [] +} + +variable "sns_target_arns" { + description = "The Amazon Resource Name (ARN) of the AWS SNS's you want to use as EventBridge targets" + type = list(string) + default = [] +} + +variable "sns_kms_arns" { + description = "The Amazon Resource Name (ARN) of the AWS KMS's configured for AWS SNS you want Decrypt/GenerateDataKey for" + type = list(string) + default = ["*"] +} + +variable "ecs_target_arns" { + description = "The Amazon Resource Name (ARN) of the AWS ECS Tasks you want to use as EventBridge targets" + type = list(string) + default = [] +} + +variable "lambda_target_arns" { + description = "The Amazon Resource Name (ARN) of the Lambda Functions you want to use as EventBridge targets" + type = list(string) + default = [] +} + +variable "sfn_target_arns" { + description = "The Amazon Resource Name (ARN) of the StepFunctions you want to use as EventBridge targets" + type = list(string) + default = [] +} + +variable "cloudwatch_target_arns" { + description = "The Amazon Resource Name (ARN) of the Cloudwatch Log Streams you want to use as EventBridge targets" + type = list(string) + default = [] +} + +variable "attach_policy_json" { + description = "Controls whether policy_json should be added to IAM role" + type = bool + default = false +} + +variable "attach_policy_jsons" { + description = "Controls whether policy_jsons should be added to IAM role" + type = bool + default = false +} + +variable "attach_policy" { + description = "Controls whether policy should be added to IAM role" + type = bool + default = false +} + +variable "attach_policies" { + description = "Controls whether list of policies should be added to IAM role" + type = bool + default = false +} + +variable "number_of_policy_jsons" { + description = "Number of policies JSON to attach to IAM role" + type = number + default = 0 +} + +variable "number_of_policies" { + description = "Number of policies to attach to IAM role" + type = number + default = 0 +} + +variable "attach_policy_statements" { + description = "Controls whether policy_statements should be added to IAM role" + type = bool + default = false +} + +variable "trusted_entities" { + description = "Additional trusted entities for assuming roles (trust relationship)" + type = list(string) + default = [] +} + +variable "policy_json" { + description = "An additional policy document as JSON to attach to IAM role" + type = string + default = null +} + +variable "policy_jsons" { + description = "List of additional policy documents as JSON to attach to IAM role" + type = list(string) + default = [] +} + +variable "policy" { + description = "An additional policy document ARN to attach to IAM role" + type = string + default = null +} + +variable "policies" { + description = "List of policy statements ARN to attach to IAM role" + type = list(string) + default = [] +} + +variable "policy_statements" { + description = "Map of dynamic policy statements to attach to IAM role" + type = any + default = {} +} From 09b903e0fe8a2bcc097eaa6a69a2867370df17cb Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 09:05:07 +0100 Subject: [PATCH 12/35] feat: copy output variables from underlying module --- infrastructure/modules/eventbridge/README.md | 37 +++- infrastructure/modules/eventbridge/outputs.tf | 170 ++++++++++++++++++ 2 files changed, 206 insertions(+), 1 deletion(-) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index 7e352b08..b7a3338f 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -149,7 +149,42 @@ No resources. ## Outputs -No outputs. +| Name | Description | +| ---- | ----------- | +| [eventbridge\_api\_destination\_arns](#output\_eventbridge\_api\_destination\_arns) | The EventBridge API Destination ARNs | +| [eventbridge\_api\_destinations](#output\_eventbridge\_api\_destinations) | The EventBridge API Destinations created and their attributes | +| [eventbridge\_archive\_arns](#output\_eventbridge\_archive\_arns) | The EventBridge Archive ARNs | +| [eventbridge\_archives](#output\_eventbridge\_archives) | The EventBridge Archives created and their attributes | +| [eventbridge\_bus](#output\_eventbridge\_bus) | The EventBridge Bus created and their attributes | +| [eventbridge\_bus\_arn](#output\_eventbridge\_bus\_arn) | The EventBridge Bus ARN | +| [eventbridge\_bus\_name](#output\_eventbridge\_bus\_name) | The EventBridge Bus Name | +| [eventbridge\_connection\_arns](#output\_eventbridge\_connection\_arns) | The EventBridge Connection Arns | +| [eventbridge\_connection\_ids](#output\_eventbridge\_connection\_ids) | The EventBridge Connection IDs | +| [eventbridge\_connections](#output\_eventbridge\_connections) | The EventBridge Connections created and their attributes | +| [eventbridge\_iam\_roles](#output\_eventbridge\_iam\_roles) | The EventBridge IAM roles created and their attributes | +| [eventbridge\_log\_delivery\_source\_arn](#output\_eventbridge\_log\_delivery\_source\_arn) | The EventBridge Bus CloudWatch Log Delivery Source ARN | +| [eventbridge\_log\_delivery\_source\_name](#output\_eventbridge\_log\_delivery\_source\_name) | The EventBridge Bus CloudWatch Log Delivery Source Name | +| [eventbridge\_permission\_ids](#output\_eventbridge\_permission\_ids) | The EventBridge Permission IDs | +| [eventbridge\_permissions](#output\_eventbridge\_permissions) | The EventBridge Permissions created and their attributes | +| [eventbridge\_pipe\_arns](#output\_eventbridge\_pipe\_arns) | The EventBridge Pipes ARNs | +| [eventbridge\_pipe\_ids](#output\_eventbridge\_pipe\_ids) | The EventBridge Pipes IDs | +| [eventbridge\_pipe\_role\_arns](#output\_eventbridge\_pipe\_role\_arns) | The ARNs of the IAM role created for EventBridge Pipes | +| [eventbridge\_pipe\_role\_names](#output\_eventbridge\_pipe\_role\_names) | The names of the IAM role created for EventBridge Pipes | +| [eventbridge\_pipes](#output\_eventbridge\_pipes) | The EventBridge Pipes created and their attributes | +| [eventbridge\_pipes\_iam\_roles](#output\_eventbridge\_pipes\_iam\_roles) | The EventBridge Pipes IAM roles created and their attributes | +| [eventbridge\_role\_arn](#output\_eventbridge\_role\_arn) | The ARN of the IAM role created for EventBridge | +| [eventbridge\_role\_name](#output\_eventbridge\_role\_name) | The name of the IAM role created for EventBridge | +| [eventbridge\_rule\_arns](#output\_eventbridge\_rule\_arns) | The EventBridge Rule ARNs | +| [eventbridge\_rule\_ids](#output\_eventbridge\_rule\_ids) | The EventBridge Rule IDs | +| [eventbridge\_rules](#output\_eventbridge\_rules) | The EventBridge Rules created and their attributes | +| [eventbridge\_schedule\_arns](#output\_eventbridge\_schedule\_arns) | The EventBridge Schedule ARNs created | +| [eventbridge\_schedule\_group\_arns](#output\_eventbridge\_schedule\_group\_arns) | The EventBridge Schedule Group ARNs | +| [eventbridge\_schedule\_group\_ids](#output\_eventbridge\_schedule\_group\_ids) | The EventBridge Schedule Group IDs | +| [eventbridge\_schedule\_group\_states](#output\_eventbridge\_schedule\_group\_states) | The EventBridge Schedule Group states | +| [eventbridge\_schedule\_groups](#output\_eventbridge\_schedule\_groups) | The EventBridge Schedule Groups created and their attributes | +| [eventbridge\_schedule\_ids](#output\_eventbridge\_schedule\_ids) | The EventBridge Schedule IDs created | +| [eventbridge\_schedules](#output\_eventbridge\_schedules) | The EventBridge Schedules created and their attributes | +| [eventbridge\_targets](#output\_eventbridge\_targets) | The EventBridge Targets created and their attributes | diff --git a/infrastructure/modules/eventbridge/outputs.tf b/infrastructure/modules/eventbridge/outputs.tf index e69de29b..33dfc38f 100644 --- a/infrastructure/modules/eventbridge/outputs.tf +++ b/infrastructure/modules/eventbridge/outputs.tf @@ -0,0 +1,170 @@ +output "eventbridge_bus_name" { + description = "The EventBridge Bus Name" + value = module.eventbridge.eventbridge_bus_name +} + +output "eventbridge_bus_arn" { + description = "The EventBridge Bus ARN" + value = module.eventbridge.eventbridge_bus_arn +} + +output "eventbridge_archive_arns" { + description = "The EventBridge Archive ARNs" + value = module.eventbridge.eventbridge_archive_arns +} + +output "eventbridge_permission_ids" { + description = "The EventBridge Permission IDs" + value = module.eventbridge.eventbridge_permission_ids +} + +output "eventbridge_connection_ids" { + description = "The EventBridge Connection IDs" + value = module.eventbridge.eventbridge_connection_ids +} + +output "eventbridge_connection_arns" { + description = "The EventBridge Connection Arns" + value = module.eventbridge.eventbridge_connection_arns +} + +output "eventbridge_api_destination_arns" { + description = "The EventBridge API Destination ARNs" + value = module.eventbridge.eventbridge_api_destination_arns +} + +output "eventbridge_rule_ids" { + description = "The EventBridge Rule IDs" + value = module.eventbridge.eventbridge_rule_ids +} + +output "eventbridge_rule_arns" { + description = "The EventBridge Rule ARNs" + value = module.eventbridge.eventbridge_rule_arns +} + +output "eventbridge_schedule_group_ids" { + description = "The EventBridge Schedule Group IDs" + value = module.eventbridge.eventbridge_schedule_group_ids +} + +output "eventbridge_schedule_group_arns" { + description = "The EventBridge Schedule Group ARNs" + value = module.eventbridge.eventbridge_schedule_group_arns +} + +output "eventbridge_schedule_group_states" { + description = "The EventBridge Schedule Group states" + value = module.eventbridge.eventbridge_schedule_group_states +} + +output "eventbridge_schedule_ids" { + description = "The EventBridge Schedule IDs created" + value = module.eventbridge.eventbridge_schedule_ids +} + +output "eventbridge_schedule_arns" { + description = "The EventBridge Schedule ARNs created" + value = module.eventbridge.eventbridge_schedule_arns +} + +output "eventbridge_role_arn" { + description = "The ARN of the IAM role created for EventBridge" + value = module.eventbridge.eventbridge_role_arn +} + +output "eventbridge_role_name" { + description = "The name of the IAM role created for EventBridge" + value = module.eventbridge.eventbridge_role_name +} + +output "eventbridge_pipe_ids" { + description = "The EventBridge Pipes IDs" + value = module.eventbridge.eventbridge_pipe_ids +} + +output "eventbridge_pipe_arns" { + description = "The EventBridge Pipes ARNs" + value = module.eventbridge.eventbridge_pipe_arns +} + +output "eventbridge_pipe_role_arns" { + description = "The ARNs of the IAM role created for EventBridge Pipes" + value = module.eventbridge.eventbridge_pipe_role_arns +} + +output "eventbridge_pipe_role_names" { + description = "The names of the IAM role created for EventBridge Pipes" + value = module.eventbridge.eventbridge_pipe_role_names +} + +output "eventbridge_bus" { + description = "The EventBridge Bus created and their attributes" + value = module.eventbridge.eventbridge_bus +} + +output "eventbridge_archives" { + description = "The EventBridge Archives created and their attributes" + value = module.eventbridge.eventbridge_archives +} + +output "eventbridge_permissions" { + description = "The EventBridge Permissions created and their attributes" + value = module.eventbridge.eventbridge_permissions +} + +output "eventbridge_connections" { + description = "The EventBridge Connections created and their attributes" + value = module.eventbridge.eventbridge_connections + sensitive = true +} + +output "eventbridge_api_destinations" { + description = "The EventBridge API Destinations created and their attributes" + value = module.eventbridge.eventbridge_api_destinations +} + +output "eventbridge_targets" { + description = "The EventBridge Targets created and their attributes" + value = module.eventbridge.eventbridge_targets +} + +output "eventbridge_rules" { + description = "The EventBridge Rules created and their attributes" + value = module.eventbridge.eventbridge_rules +} + +output "eventbridge_schedule_groups" { + description = "The EventBridge Schedule Groups created and their attributes" + value = module.eventbridge.eventbridge_schedule_groups +} + +output "eventbridge_schedules" { + description = "The EventBridge Schedules created and their attributes" + value = module.eventbridge.eventbridge_schedules +} + +output "eventbridge_pipes" { + description = "The EventBridge Pipes created and their attributes" + value = module.eventbridge.eventbridge_pipes +} + +output "eventbridge_log_delivery_source_arn" { + description = "The EventBridge Bus CloudWatch Log Delivery Source ARN" + value = module.eventbridge.eventbridge_log_delivery_source_arn +} + +output "eventbridge_log_delivery_source_name" { + description = "The EventBridge Bus CloudWatch Log Delivery Source Name" + value = module.eventbridge.eventbridge_log_delivery_source_name +} + +output "eventbridge_pipes_iam_roles" { + description = "The EventBridge Pipes IAM roles created and their attributes" + value = module.eventbridge.eventbridge_pipes_iam_roles +} + +output "eventbridge_iam_roles" { + description = "The EventBridge IAM roles created and their attributes" + value = module.eventbridge.eventbridge_iam_roles +} From 685d564ea021daaf7d85da07dddc6ed06f1b4e0b Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 10:53:57 +0100 Subject: [PATCH 13/35] docs: add notes about where names are obtained from where uniqueness is required --- infrastructure/modules/eventbridge/NOTES.md | 23 ++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/infrastructure/modules/eventbridge/NOTES.md b/infrastructure/modules/eventbridge/NOTES.md index 634239b5..cbca218a 100644 --- a/infrastructure/modules/eventbridge/NOTES.md +++ b/infrastructure/modules/eventbridge/NOTES.md @@ -39,7 +39,7 @@ The main on/off switch is called `create`. - resource - gated by `var.create_connections` - name status: named and must be unique per AWS account and region -- named by `Name` field of `var.connections` sub-value +- named by the key of `var.connections` - modified if `var.append_connection_postfix` is true - encrypted using `kms_key_identifier` field of `var.connections` sub-value, falling back to unencrypted @@ -68,66 +68,82 @@ The main on/off switch is called `create`. ### `aws_cloudwatch_log_delivery_destination.this` - name status: named and must be unique per AWS account +- name is obtained from the `name` field of each `var.log_delivery` sub-value, falling back to `var.bus_name` and the `var.log_delivery` map key ### `aws_cloudwatch_log_delivery_source.this` - name status: named and must be unique per AWS account +- name is obtained from `var.log_delivery_source_name`, falling back to `var.bus_name` ### `aws_iam_policy.additional_inline` - name status: named and must be unique per AWS account +- name is derived from `var.role_name`, falling back to `var.bus_name`, with `-inline` appended ### `aws_iam_policy.additional_json` - name status: named and must be unique per AWS account +- name is derived from `var.role_name`, falling back to `var.bus_name` ### `aws_iam_policy.additional_jsons` - name status: named and must be unique per AWS account +- name is derived from `var.role_name`, falling back to `var.bus_name`, with `-` appended ### `aws_iam_policy.api_destination` - name status: named and must be unique per AWS account +- name is derived from `var.role_name`, falling back to `var.bus_name`, with `-api-destination` appended ### `aws_iam_policy.cloudwatch` - name status: named and must be unique per AWS account +- name is derived from `var.role_name`, falling back to `var.bus_name`, with `-cloudwatch` appended ### `aws_iam_policy.ecs` - name status: named and must be unique per AWS account +- name is derived from `var.role_name`, falling back to `var.bus_name`, with `-ecs` appended ### `aws_iam_policy.kinesis` - name status: named and must be unique per AWS account +- name is derived from `var.role_name`, falling back to `var.bus_name`, with `-kinesis` appended ### `aws_iam_policy.kinesis_firehose` - name status: named and must be unique per AWS account +- name is derived from `var.role_name`, falling back to `var.bus_name`, with `-kinesis-firehose` appended ### `aws_iam_policy.lambda` - name status: named and must be unique per AWS account +- name is derived from `var.role_name`, falling back to `var.bus_name`, with `-lambda` appended ### `aws_iam_policy.service` - name status: named and must be unique per AWS account +- name is derived from the generated Pipe role name and the key of `var.pipes`; the role name uses `role_name_prefix` from each `var.pipes` sub-value, falling back to its map key ### `aws_iam_policy.sfn` - name status: named and must be unique per AWS account +- name is derived from `var.role_name`, falling back to `var.bus_name`, with `-sfn` appended ### `aws_iam_policy.sns` - name status: named and must be unique per AWS account +- name is derived from `var.role_name`, falling back to `var.bus_name`, with `-sns` appended ### `aws_iam_policy.sqs` - name status: named and must be unique per AWS account +- name is derived from `var.role_name`, falling back to `var.bus_name`, with `-sqs` appended ### `aws_iam_policy.tracing` - name status: named and must be unique per AWS account +- name is derived from `var.role_name`, falling back to `var.bus_name`, with `-tracing` appended ### `aws_iam_policy_attachment.additional_inline` @@ -188,10 +204,12 @@ The main on/off switch is called `create`. ### `aws_iam_role.eventbridge` - name status: named and must be unique per AWS account +- name is obtained from `var.role_name`, falling back to `var.bus_name` ### `aws_iam_role.eventbridge_pipe` - name status: named and must be unique per AWS account +- name uses `role_name_prefix` from each `var.pipes` sub-value, falling back to its map key ### `aws_iam_role_policy_attachment.additional_many` @@ -204,6 +222,7 @@ The main on/off switch is called `create`. ### `aws_pipes_pipe.this` - name status: named and must be unique per AWS account and region +- name is obtained from the key of `var.pipes`, with the optional postfix controlled by `var.append_pipe_postfix` - encrypted using `kms_key_identifier` field of `var.pipes` sub-value, falling back to unencrypted ### `aws_scheduler_schedule.this` @@ -214,7 +233,9 @@ The main on/off switch is called `create`. ### `aws_scheduler_schedule_group.this` - name status: named and must be unique per AWS account and region +- name is obtained from the `name` or `name_prefix` field of each `var.schedule_groups` sub-value, falling back to its map key ### `aws_schemas_discoverer.this` - name status: named and must be unique per AWS account and region +- name is generated by AWS; it is not obtained from a module input variable From cf77d3aa5f58d864f46a1f33624dce141e4db5ba Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 11:25:50 +0100 Subject: [PATCH 14/35] chore: add todos for inputs that need to be unique names --- infrastructure/modules/eventbridge/main.tf | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index c8ff6cc8..c1d84eff 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -26,11 +26,11 @@ module "eventbridge" { create_log_delivery_source = var.create_log_delivery_source create_log_delivery = var.create_log_delivery region = var.aws_region - bus_name = var.bus_name + bus_name = var.bus_name # DAVEH: unique per AWS account and region; the event bus name is taken from var.bus_name bus_description = var.bus_description log_config = var.log_config - log_delivery = var.log_delivery - log_delivery_source_name = var.log_delivery_source_name + log_delivery = var.log_delivery # DAVEH: unique per AWS account; the destination name comes from var.log_delivery..name, falling back to var.bus_name and the map key + log_delivery_source_name = var.log_delivery_source_name # DAVEH: unique per AWS account; the source name is taken from var.log_delivery_source_name, falling back to var.bus_name event_source_name = var.event_source_name kms_key_identifier = var.kms_key_identifier dead_letter_config = var.dead_letter_config @@ -39,13 +39,13 @@ module "eventbridge" { targets = var.targets archives = var.archives permissions = var.permissions - connections = var.connections - api_destinations = var.api_destinations - schedule_groups = var.schedule_groups + connections = var.connections # DAVEH: unique per AWS account and region; the connection name is taken from the key of var.connections + api_destinations = var.api_destinations # DAVEH: unique per AWS account and region; the API destination name is taken from the key of var.api_destinations + schedule_groups = var.schedule_groups # DAVEH: unique per AWS account and region; the schedule group name is taken from var.schedule_groups..name or .name_prefix, falling back to the map key schedules = var.schedules - pipes = var.pipes + pipes = var.pipes # DAVEH: unique per AWS account and region; the pipe name is taken from the key of var.pipes, and the related IAM role names derive from role_name_prefix in each entry schedule_group_timeouts = var.schedule_group_timeouts - role_name = var.role_name + role_name = var.role_name # DAVEH: unique per AWS account; the EventBridge role and related IAM policy names are derived from var.role_name, falling back to var.bus_name role_description = var.role_description role_path = var.role_path policy_path = var.policy_path From b57717b702ac42d9086de3fd905f6b157f6d41b3 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 11:42:26 +0100 Subject: [PATCH 15/35] docs: todo --- infrastructure/modules/eventbridge/main.tf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index c1d84eff..03285319 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -1,6 +1,8 @@ module "eventbridge" { source = "git::https://github.com/terraform-aws-modules/terraform-aws-eventbridge.git?ref=f9934726324c988f823682884b4fa003586a7b6f" # v4.3.2 + # DAVEH: force enable encryption + create = module.this.enabled tags = module.this.tags From 3ec2891d4afcd6942a4a2fdaaaf77d5ae3af2e25 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 13:42:32 +0100 Subject: [PATCH 16/35] feat: allow overriding bus name --- infrastructure/modules/eventbridge/README.md | 4 +++- infrastructure/modules/eventbridge/locals.tf | 4 ++++ infrastructure/modules/eventbridge/main.tf | 2 +- infrastructure/modules/eventbridge/variables.tf | 5 +++-- 4 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 infrastructure/modules/eventbridge/locals.tf diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index b7a3338f..05106246 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -6,6 +6,8 @@ module that consumes the shared `context.tf` for naming and tagging. DAVEH +DAVEH: document var.bus_name + @@ -63,7 +65,7 @@ No resources. | [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
in the order they appear in the list. New attributes are appended to the
end of the list. The elements of the list are joined by the `delimiter`
and treated as a single ID element. | `list(string)` | `[]` | no | | [aws\_region](#input\_aws\_region) | The AWS region | `string` | `"eu-west-2"` | no | | [bus\_description](#input\_bus\_description) | Event bus description | `string` | `null` | no | -| [bus\_name](#input\_bus\_name) | A unique name for your EventBridge Bus | `string` | `"default"` | no | +| [bus\_name](#input\_bus\_name) | A unique name for your EventBridge Bus. Must be unique per AWS account and region. Defaults to whatever the tags module produces | `string` | `null` | no | | [cloudwatch\_target\_arns](#input\_cloudwatch\_target\_arns) | The Amazon Resource Name (ARN) of the Cloudwatch Log Streams you want to use as EventBridge targets | `list(string)` | `[]` | no | | [connections](#input\_connections) | A map of objects with EventBridge Connection definitions. | `any` | `{}` | no | | [context](#input\_context) | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"descriptor_formats": {},
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"labels_as_tags": [
"unset"
],
"name": null,
"project": null,
"regex_replace_chars": null,
"region": null,
"service": null,
"stack": null,
"tags": {},
"terraform_source": null,
"workspace": null
}
| no | diff --git a/infrastructure/modules/eventbridge/locals.tf b/infrastructure/modules/eventbridge/locals.tf new file mode 100644 index 00000000..6152e044 --- /dev/null +++ b/infrastructure/modules/eventbridge/locals.tf @@ -0,0 +1,4 @@ +locals { + # allow bus name to be overridden without touching tags + bus_name = coalesce(var.bus_name, module.this.id) +} diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index 03285319..4937ab37 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -28,7 +28,7 @@ module "eventbridge" { create_log_delivery_source = var.create_log_delivery_source create_log_delivery = var.create_log_delivery region = var.aws_region - bus_name = var.bus_name # DAVEH: unique per AWS account and region; the event bus name is taken from var.bus_name + bus_name = local.bus_name bus_description = var.bus_description log_config = var.log_config log_delivery = var.log_delivery # DAVEH: unique per AWS account; the destination name comes from var.log_delivery..name, falling back to var.bus_name and the map key diff --git a/infrastructure/modules/eventbridge/variables.tf b/infrastructure/modules/eventbridge/variables.tf index cb6b501b..094bed16 100644 --- a/infrastructure/modules/eventbridge/variables.tf +++ b/infrastructure/modules/eventbridge/variables.tf @@ -125,9 +125,10 @@ variable "create_log_delivery" { } variable "bus_name" { - description = "A unique name for your EventBridge Bus" + description = "A unique name for your EventBridge Bus. Must be unique per AWS account and region. Defaults to whatever the tags module produces" type = string - default = "default" + nullable = true + default = null } variable "bus_description" { From 41bfc6336b3ed4edd44be06fd9bfbc04d74f5032 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 14:05:21 +0100 Subject: [PATCH 17/35] =?UTF-8?q?docs:=20log=5Fdelivery=5Fsource=5Fname=20?= =?UTF-8?q?defaults=20to=20bus=20name,=20so=20doesn=E2=80=99t=20need=20to?= =?UTF-8?q?=20explicitly=20be=20made=20unique?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infrastructure/modules/eventbridge/README.md | 2 +- infrastructure/modules/eventbridge/main.tf | 4 ++-- infrastructure/modules/eventbridge/variables.tf | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index 05106246..e1020452 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -105,7 +105,7 @@ No resources. | [lambda\_target\_arns](#input\_lambda\_target\_arns) | The Amazon Resource Name (ARN) of the Lambda Functions you want to use as EventBridge targets | `list(string)` | `[]` | no | | [log\_config](#input\_log\_config) | The configuration block for the EventBridge bus log config settings |
object({
include_detail = string
level = string
})
| `null` | no | | [log\_delivery](#input\_log\_delivery) | Map of the configuration block for the EventBridge bus log delivery settings (key is the type of log delivery: cloudwatch\_logs, s3, firehose) |
map(object({
enabled = optional(bool, true)
destination_arn = string
source_name = optional(string)
name = optional(string)
output_format = optional(string)
field_delimiter = optional(string)
record_fields = optional(list(string))
s3_delivery_configuration = optional(object({
enable_hive_compatible_path = optional(bool)
suffix_path = optional(string)
}))
}))
| `{}` | no | -| [log\_delivery\_source\_name](#input\_log\_delivery\_source\_name) | Name of log delivery source | `string` | `null` | no | +| [log\_delivery\_source\_name](#input\_log\_delivery\_source\_name) | Name of log delivery source; defaults to the name we use for the bus | `string` | `null` | no | | [name](#input\_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no | | [number\_of\_policies](#input\_number\_of\_policies) | Number of policies to attach to IAM role | `number` | `0` | no | | [number\_of\_policy\_jsons](#input\_number\_of\_policy\_jsons) | Number of policies JSON to attach to IAM role | `number` | `0` | no | diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index 4937ab37..dcb11a56 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -31,8 +31,8 @@ module "eventbridge" { bus_name = local.bus_name bus_description = var.bus_description log_config = var.log_config - log_delivery = var.log_delivery # DAVEH: unique per AWS account; the destination name comes from var.log_delivery..name, falling back to var.bus_name and the map key - log_delivery_source_name = var.log_delivery_source_name # DAVEH: unique per AWS account; the source name is taken from var.log_delivery_source_name, falling back to var.bus_name + log_delivery = var.log_delivery # DAVEH: unique per AWS account; the destination name comes from var.log_delivery..name, falling back to var.bus_name and the map key + log_delivery_source_name = var.log_delivery_source_name event_source_name = var.event_source_name kms_key_identifier = var.kms_key_identifier dead_letter_config = var.dead_letter_config diff --git a/infrastructure/modules/eventbridge/variables.tf b/infrastructure/modules/eventbridge/variables.tf index 094bed16..29ad8956 100644 --- a/infrastructure/modules/eventbridge/variables.tf +++ b/infrastructure/modules/eventbridge/variables.tf @@ -165,7 +165,7 @@ variable "log_delivery" { } variable "log_delivery_source_name" { - description = "Name of log delivery source" + description = "Name of log delivery source; defaults to the name we use for the bus" type = string default = null } From c01e6c2920f3c3f11eabacd49dd641e97f6d4eda Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 14:18:37 +0100 Subject: [PATCH 18/35] feat: provide default unique log delivery names --- infrastructure/modules/eventbridge/README.md | 2 ++ infrastructure/modules/eventbridge/locals.tf | 11 +++++++++++ infrastructure/modules/eventbridge/main.tf | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index e1020452..56300957 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -8,6 +8,8 @@ DAVEH DAVEH: document var.bus_name +DAVEH: document var.log_delivery + diff --git a/infrastructure/modules/eventbridge/locals.tf b/infrastructure/modules/eventbridge/locals.tf index 6152e044..b7da598f 100644 --- a/infrastructure/modules/eventbridge/locals.tf +++ b/infrastructure/modules/eventbridge/locals.tf @@ -1,4 +1,15 @@ locals { # allow bus name to be overridden without touching tags bus_name = coalesce(var.bus_name, module.this.id) + + # log delivery names must be unique per AWS account + # provide a default name based on the module ID + log_delivery = { + for k, v in var.log_delivery : k => merge( + { + name = "${module.this.id}-${k}" + }, + v + ) + } } diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index dcb11a56..96f50c1c 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -31,7 +31,7 @@ module "eventbridge" { bus_name = local.bus_name bus_description = var.bus_description log_config = var.log_config - log_delivery = var.log_delivery # DAVEH: unique per AWS account; the destination name comes from var.log_delivery..name, falling back to var.bus_name and the map key + log_delivery = local.log_delivery log_delivery_source_name = var.log_delivery_source_name event_source_name = var.event_source_name kms_key_identifier = var.kms_key_identifier From 0e7c8eb80f2aa9a37b71c74f23b999066c968052 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 14:29:53 +0100 Subject: [PATCH 19/35] feat: enforce unique connection names --- infrastructure/modules/eventbridge/README.md | 2 ++ infrastructure/modules/eventbridge/locals.tf | 6 ++++++ infrastructure/modules/eventbridge/main.tf | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index 56300957..d277b3c8 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -10,6 +10,8 @@ DAVEH: document var.bus_name DAVEH: document var.log_delivery +DAVEH: document var.connections + diff --git a/infrastructure/modules/eventbridge/locals.tf b/infrastructure/modules/eventbridge/locals.tf index b7da598f..15300b23 100644 --- a/infrastructure/modules/eventbridge/locals.tf +++ b/infrastructure/modules/eventbridge/locals.tf @@ -12,4 +12,10 @@ locals { v ) } + + # connection names must be unique per AWS account and region + # prefix provided names with the module ID to ensure uniqueness + connections = { + for k, v in var.connections : "${module.this.id}-${k}" => v + } } diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index 96f50c1c..565db737 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -41,7 +41,7 @@ module "eventbridge" { targets = var.targets archives = var.archives permissions = var.permissions - connections = var.connections # DAVEH: unique per AWS account and region; the connection name is taken from the key of var.connections + connections = local.connections api_destinations = var.api_destinations # DAVEH: unique per AWS account and region; the API destination name is taken from the key of var.api_destinations schedule_groups = var.schedule_groups # DAVEH: unique per AWS account and region; the schedule group name is taken from var.schedule_groups..name or .name_prefix, falling back to the map key schedules = var.schedules From 964581110d75db02899eb4554fcf0086d841df54 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 14:32:22 +0100 Subject: [PATCH 20/35] feat: enforce unique API destination names --- infrastructure/modules/eventbridge/README.md | 2 ++ infrastructure/modules/eventbridge/locals.tf | 6 ++++++ infrastructure/modules/eventbridge/main.tf | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index d277b3c8..c65ed820 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -12,6 +12,8 @@ DAVEH: document var.log_delivery DAVEH: document var.connections +DAVEH: document var.api_destinations + diff --git a/infrastructure/modules/eventbridge/locals.tf b/infrastructure/modules/eventbridge/locals.tf index 15300b23..927f6f72 100644 --- a/infrastructure/modules/eventbridge/locals.tf +++ b/infrastructure/modules/eventbridge/locals.tf @@ -18,4 +18,10 @@ locals { connections = { for k, v in var.connections : "${module.this.id}-${k}" => v } + + # API destination names must be unique per AWS account and region + # prefix provided names with the module ID to ensure uniqueness + api_destinations = { + for k, v in var.api_destinations : "${module.this.id}-${k}" => v + } } diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index 565db737..ebcbcc05 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -42,8 +42,8 @@ module "eventbridge" { archives = var.archives permissions = var.permissions connections = local.connections - api_destinations = var.api_destinations # DAVEH: unique per AWS account and region; the API destination name is taken from the key of var.api_destinations - schedule_groups = var.schedule_groups # DAVEH: unique per AWS account and region; the schedule group name is taken from var.schedule_groups..name or .name_prefix, falling back to the map key + api_destinations = local.api_destinations + schedule_groups = var.schedule_groups # DAVEH: unique per AWS account and region; the schedule group name is taken from var.schedule_groups..name or .name_prefix, falling back to the map key schedules = var.schedules pipes = var.pipes # DAVEH: unique per AWS account and region; the pipe name is taken from the key of var.pipes, and the related IAM role names derive from role_name_prefix in each entry schedule_group_timeouts = var.schedule_group_timeouts From 0c78a359351d162e5882fcdf94754d9c47f38ddb Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 15:24:11 +0100 Subject: [PATCH 21/35] feat: enforce unique schedule group names --- infrastructure/modules/eventbridge/README.md | 2 ++ infrastructure/modules/eventbridge/locals.tf | 16 ++++++++++++++++ infrastructure/modules/eventbridge/main.tf | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index c65ed820..8fbf5a0c 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -14,6 +14,8 @@ DAVEH: document var.connections DAVEH: document var.api_destinations +DAVEH: document var.schedule_groups + diff --git a/infrastructure/modules/eventbridge/locals.tf b/infrastructure/modules/eventbridge/locals.tf index 927f6f72..808af12b 100644 --- a/infrastructure/modules/eventbridge/locals.tf +++ b/infrastructure/modules/eventbridge/locals.tf @@ -24,4 +24,20 @@ locals { api_destinations = { for k, v in var.api_destinations : "${module.this.id}-${k}" => v } + + # schedule group names must be unique per AWS account and region + # respect `name` and `name_prefix` if given + # otherwise include module ID and key in `name_prefix` + schedule_groups = { + for k, v in var.schedule_groups : k => ( + contains(keys(v), "name") || contains(keys(v), "name_prefix") + ? v + : merge( + { + name_prefix = "${module.this.id}-${k}" + }, + v + ) + ) + } } diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index ebcbcc05..6a2ce959 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -43,7 +43,7 @@ module "eventbridge" { permissions = var.permissions connections = local.connections api_destinations = local.api_destinations - schedule_groups = var.schedule_groups # DAVEH: unique per AWS account and region; the schedule group name is taken from var.schedule_groups..name or .name_prefix, falling back to the map key + schedule_groups = local.schedule_groups schedules = var.schedules pipes = var.pipes # DAVEH: unique per AWS account and region; the pipe name is taken from the key of var.pipes, and the related IAM role names derive from role_name_prefix in each entry schedule_group_timeouts = var.schedule_group_timeouts From 3c3133070eb7db73ca2e957c6758336109f64e45 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 15:27:24 +0100 Subject: [PATCH 22/35] feat: enforce unique pipe names --- infrastructure/modules/eventbridge/README.md | 2 ++ infrastructure/modules/eventbridge/locals.tf | 6 ++++++ infrastructure/modules/eventbridge/main.tf | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index 8fbf5a0c..f0a29fe7 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -16,6 +16,8 @@ DAVEH: document var.api_destinations DAVEH: document var.schedule_groups +DAVEH: document var.pipes + diff --git a/infrastructure/modules/eventbridge/locals.tf b/infrastructure/modules/eventbridge/locals.tf index 808af12b..a27fd54b 100644 --- a/infrastructure/modules/eventbridge/locals.tf +++ b/infrastructure/modules/eventbridge/locals.tf @@ -40,4 +40,10 @@ locals { ) ) } + + # pipe names must be unique per AWS account and region + # prefix keys with the module ID to ensure uniqueness + pipes = { + for k, v in var.pipes : "${module.this.id}-${k}" => v + } } diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index 6a2ce959..d2785852 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -45,7 +45,7 @@ module "eventbridge" { api_destinations = local.api_destinations schedule_groups = local.schedule_groups schedules = var.schedules - pipes = var.pipes # DAVEH: unique per AWS account and region; the pipe name is taken from the key of var.pipes, and the related IAM role names derive from role_name_prefix in each entry + pipes = local.pipes schedule_group_timeouts = var.schedule_group_timeouts role_name = var.role_name # DAVEH: unique per AWS account; the EventBridge role and related IAM policy names are derived from var.role_name, falling back to var.bus_name role_description = var.role_description From c13cc6d0f7e5033a67c74619eacfae70c6207e3f Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 15:28:57 +0100 Subject: [PATCH 23/35] =?UTF-8?q?docs:=20role=5Fname=20defaults=20to=20bus?= =?UTF-8?q?=20name,=20so=20doesn=E2=80=99t=20need=20to=20explicitly=20be?= =?UTF-8?q?=20made=20unique?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infrastructure/modules/eventbridge/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index d2785852..eabdcbd6 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -47,7 +47,7 @@ module "eventbridge" { schedules = var.schedules pipes = local.pipes schedule_group_timeouts = var.schedule_group_timeouts - role_name = var.role_name # DAVEH: unique per AWS account; the EventBridge role and related IAM policy names are derived from var.role_name, falling back to var.bus_name + role_name = var.role_name role_description = var.role_description role_path = var.role_path policy_path = var.policy_path From db4b2d6c33569452a3fd7b55272806378377ee16 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 15:36:03 +0100 Subject: [PATCH 24/35] docs: todos --- infrastructure/modules/eventbridge/main.tf | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index eabdcbd6..22fff8b5 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -1,8 +1,6 @@ module "eventbridge" { source = "git::https://github.com/terraform-aws-modules/terraform-aws-eventbridge.git?ref=f9934726324c988f823682884b4fa003586a7b6f" # v4.3.2 - # DAVEH: force enable encryption - create = module.this.enabled tags = module.this.tags @@ -31,21 +29,21 @@ module "eventbridge" { bus_name = local.bus_name bus_description = var.bus_description log_config = var.log_config - log_delivery = local.log_delivery + log_delivery = local.log_delivery # DAVEH: per-destination KMS keys can come from var.log_delivery..kms_key_identifier or fall back to unencrypted log_delivery_source_name = var.log_delivery_source_name event_source_name = var.event_source_name - kms_key_identifier = var.kms_key_identifier + kms_key_identifier = var.kms_key_identifier # DAVEH: KMS key for the event bus comes from var.kms_key_identifier dead_letter_config = var.dead_letter_config schemas_discoverer_description = var.schemas_discoverer_description rules = var.rules targets = var.targets archives = var.archives permissions = var.permissions - connections = local.connections + connections = local.connections # DAVEH: per-connection KMS keys can come from var.connections..kms_key_identifier or fall back to unencrypted api_destinations = local.api_destinations schedule_groups = local.schedule_groups - schedules = var.schedules - pipes = local.pipes + schedules = var.schedules # DAVEH: per-schedule KMS keys can come from var.schedules..kms_key_arn or fall back to unencrypted + pipes = local.pipes # DAVEH: per-pipe KMS keys can come from var.pipes..kms_key_identifier or fall back to unencrypted schedule_group_timeouts = var.schedule_group_timeouts role_name = var.role_name role_description = var.role_description From c2a68f03c2f59528b58347cff3bd3c7bffa7e16f Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 15:53:23 +0100 Subject: [PATCH 25/35] feat: enforce encryption of events on the event bus --- infrastructure/modules/eventbridge/README.md | 8 +++++++- infrastructure/modules/eventbridge/variables.tf | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index f0a29fe7..53699547 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -8,6 +8,8 @@ DAVEH DAVEH: document var.bus_name +---- + DAVEH: document var.log_delivery DAVEH: document var.connections @@ -18,6 +20,10 @@ DAVEH: document var.schedule_groups DAVEH: document var.pipes +---- + +DAVEH: document var.kms_key_identifier + @@ -107,7 +113,7 @@ No resources. | [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | | [kinesis\_firehose\_target\_arns](#input\_kinesis\_firehose\_target\_arns) | The Amazon Resource Name (ARN) of the Kinesis Firehose Delivery Streams you want to use as EventBridge targets | `list(string)` | `[]` | no | | [kinesis\_target\_arns](#input\_kinesis\_target\_arns) | The Amazon Resource Name (ARN) of the Kinesis Streams you want to use as EventBridge targets | `list(string)` | `[]` | no | -| [kms\_key\_identifier](#input\_kms\_key\_identifier) | 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. | `string` | `null` | no | +| [kms\_key\_identifier](#input\_kms\_key\_identifier) | The identifier of the AWS KMS customer managed key for EventBridge to use, to encrypt events on this event bus. The identifier can be the key Amazon Resource Name (ARN), KeyId, key alias, or key alias ARN. | `string` | n/a | yes | | [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | | [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no | | [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`. | `string` | `null` | no | diff --git a/infrastructure/modules/eventbridge/variables.tf b/infrastructure/modules/eventbridge/variables.tf index 29ad8956..2cdabc4f 100644 --- a/infrastructure/modules/eventbridge/variables.tf +++ b/infrastructure/modules/eventbridge/variables.tf @@ -177,9 +177,9 @@ variable "event_source_name" { } variable "kms_key_identifier" { - description = "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." + description = "The identifier of the AWS KMS customer managed key for EventBridge to use, to encrypt events on this event bus. The identifier can be the key Amazon Resource Name (ARN), KeyId, key alias, or key alias ARN." type = string - default = null + nullable = false } variable "dead_letter_config" { From 49cddcaa19c5b613fa93371de95fb3a1491abc5a Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 15:53:53 +0100 Subject: [PATCH 26/35] feat: enforce encryption of events on the event bus --- infrastructure/modules/eventbridge/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index 22fff8b5..dae111e1 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -32,7 +32,7 @@ module "eventbridge" { log_delivery = local.log_delivery # DAVEH: per-destination KMS keys can come from var.log_delivery..kms_key_identifier or fall back to unencrypted log_delivery_source_name = var.log_delivery_source_name event_source_name = var.event_source_name - kms_key_identifier = var.kms_key_identifier # DAVEH: KMS key for the event bus comes from var.kms_key_identifier + kms_key_identifier = var.kms_key_identifier dead_letter_config = var.dead_letter_config schemas_discoverer_description = var.schemas_discoverer_description rules = var.rules From 634d8a96ac1ef64e7ec219fda7e2fd5c5a8e790e Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 16:47:35 +0100 Subject: [PATCH 27/35] docs: comment was inaccurate: per-destination KMS keys are configured by the destination, not by these delivery rules --- infrastructure/modules/eventbridge/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index dae111e1..37cf4584 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -29,7 +29,7 @@ module "eventbridge" { bus_name = local.bus_name bus_description = var.bus_description log_config = var.log_config - log_delivery = local.log_delivery # DAVEH: per-destination KMS keys can come from var.log_delivery..kms_key_identifier or fall back to unencrypted + log_delivery = local.log_delivery log_delivery_source_name = var.log_delivery_source_name event_source_name = var.event_source_name kms_key_identifier = var.kms_key_identifier From 41c16553106ff0a0ff21f6efcf8f65714f4154be Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 17:02:55 +0100 Subject: [PATCH 28/35] feat: force connections to use explicit KMS keys for encryption --- infrastructure/modules/eventbridge/README.md | 2 +- infrastructure/modules/eventbridge/main.tf | 2 +- .../modules/eventbridge/variables.tf | 20 +++++++++++++++++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index 53699547..b1dc8079 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -83,7 +83,7 @@ No resources. | [bus\_description](#input\_bus\_description) | Event bus description | `string` | `null` | no | | [bus\_name](#input\_bus\_name) | A unique name for your EventBridge Bus. Must be unique per AWS account and region. Defaults to whatever the tags module produces | `string` | `null` | no | | [cloudwatch\_target\_arns](#input\_cloudwatch\_target\_arns) | The Amazon Resource Name (ARN) of the Cloudwatch Log Streams you want to use as EventBridge targets | `list(string)` | `[]` | no | -| [connections](#input\_connections) | A map of objects with EventBridge Connection definitions. | `any` | `{}` | no | +| [connections](#input\_connections) | A map of objects with EventBridge Connection definitions. |
map(object({
authorization_type = string
auth_parameters = any
kms_key_identifier = string
description = optional(string)
invocation_connectivity_parameters = optional(any)
}))
| `{}` | no | | [context](#input\_context) | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"descriptor_formats": {},
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"labels_as_tags": [
"unset"
],
"name": null,
"project": null,
"regex_replace_chars": null,
"region": null,
"service": null,
"stack": null,
"tags": {},
"terraform_source": null,
"workspace": null
}
| no | | [create\_api\_destinations](#input\_create\_api\_destinations) | Controls whether EventBridge Destination resources should be created | `bool` | `false` | no | | [create\_archives](#input\_create\_archives) | Controls whether EventBridge Archive resources should be created | `bool` | `false` | no | diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index 37cf4584..a08b2003 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -39,7 +39,7 @@ module "eventbridge" { targets = var.targets archives = var.archives permissions = var.permissions - connections = local.connections # DAVEH: per-connection KMS keys can come from var.connections..kms_key_identifier or fall back to unencrypted + connections = local.connections api_destinations = local.api_destinations schedule_groups = local.schedule_groups schedules = var.schedules # DAVEH: per-schedule KMS keys can come from var.schedules..kms_key_arn or fall back to unencrypted diff --git a/infrastructure/modules/eventbridge/variables.tf b/infrastructure/modules/eventbridge/variables.tf index 2cdabc4f..18657cff 100644 --- a/infrastructure/modules/eventbridge/variables.tf +++ b/infrastructure/modules/eventbridge/variables.tf @@ -220,8 +220,24 @@ variable "permissions" { variable "connections" { description = "A map of objects with EventBridge Connection definitions." - type = any - default = {} + type = map(object({ + authorization_type = string + auth_parameters = any + kms_key_identifier = string + description = optional(string) + invocation_connectivity_parameters = optional(any) + })) + default = {} + + validation { + condition = alltrue([ + for connection in var.connections : + connection.kms_key_identifier != null && + trimspace(connection.kms_key_identifier) != "" + ]) + + error_message = "Each connection must specify a non-empty kms_key_identifier." + } } variable "api_destinations" { From 7ca4e0bece8cf4802fb49c4bcc1b8f98ec582381 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 17:25:40 +0100 Subject: [PATCH 29/35] feat: force schedules to use explicit KMS keys for encryption --- infrastructure/modules/eventbridge/README.md | 2 +- infrastructure/modules/eventbridge/main.tf | 4 +-- .../modules/eventbridge/variables.tf | 36 +++++++++++++++++-- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index b1dc8079..0929ebd4 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -148,7 +148,7 @@ No resources. | [rules](#input\_rules) | A map of objects with EventBridge Rule definitions. | `map(any)` | `{}` | no | | [schedule\_group\_timeouts](#input\_schedule\_group\_timeouts) | A map of objects with EventBridge Schedule Group create and delete timeouts. | `map(string)` | `{}` | no | | [schedule\_groups](#input\_schedule\_groups) | A map of objects with EventBridge Schedule Group definitions. | `any` | `{}` | no | -| [schedules](#input\_schedules) | A map of objects with EventBridge Schedule definitions. | `map(any)` | `{}` | no | +| [schedules](#input\_schedules) | A map of objects with EventBridge Schedule definitions. |
map(object({
arn = string
schedule_expression = string
name_prefix = optional(string)
description = optional(string)
group_name = optional(string)
start_date = optional(string)
end_date = optional(string)
kms_key_arn = string
timezone = optional(string)
state = optional(bool, true)
maximum_window_in_minutes = optional(number)
use_flexible_time_window = optional(bool, false)
role_arn = optional(string)
input = optional(string)
dead_letter_arn = optional(string)
ecs_parameters = optional(any)
eventbridge_parameters = optional(any)
partition_key = optional(string)
sagemaker_pipeline_parameters = optional(any)
message_group_id = optional(string)
retry_policy = optional(any)
}))
| `{}` | no | | [schemas\_discoverer\_description](#input\_schemas\_discoverer\_description) | Default schemas discoverer description | `string` | `"Auto schemas discoverer event"` | no | | [service](#input\_service) | ID element. Usually an abbreviation of your service directorate name, e.g. 'bcss' or 'csms', to help ensure generated IDs are globally unique | `string` | `null` | no | | [service\_category](#input\_service\_category) | The tag service\_category | `string` | `"n/a"` | no | diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index a08b2003..e8258b6a 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -42,8 +42,8 @@ module "eventbridge" { connections = local.connections api_destinations = local.api_destinations schedule_groups = local.schedule_groups - schedules = var.schedules # DAVEH: per-schedule KMS keys can come from var.schedules..kms_key_arn or fall back to unencrypted - pipes = local.pipes # DAVEH: per-pipe KMS keys can come from var.pipes..kms_key_identifier or fall back to unencrypted + schedules = var.schedules + pipes = local.pipes # DAVEH: per-pipe KMS keys can come from var.pipes..kms_key_identifier or fall back to unencrypted schedule_group_timeouts = var.schedule_group_timeouts role_name = var.role_name role_description = var.role_description diff --git a/infrastructure/modules/eventbridge/variables.tf b/infrastructure/modules/eventbridge/variables.tf index 18657cff..dc571316 100644 --- a/infrastructure/modules/eventbridge/variables.tf +++ b/infrastructure/modules/eventbridge/variables.tf @@ -254,8 +254,40 @@ variable "schedule_groups" { variable "schedules" { description = "A map of objects with EventBridge Schedule definitions." - type = map(any) - default = {} + type = map(object({ + arn = string + schedule_expression = string + name_prefix = optional(string) + description = optional(string) + group_name = optional(string) + start_date = optional(string) + end_date = optional(string) + kms_key_arn = string + timezone = optional(string) + state = optional(bool, true) + maximum_window_in_minutes = optional(number) + use_flexible_time_window = optional(bool, false) + role_arn = optional(string) + input = optional(string) + dead_letter_arn = optional(string) + ecs_parameters = optional(any) + eventbridge_parameters = optional(any) + partition_key = optional(string) + sagemaker_pipeline_parameters = optional(any) + message_group_id = optional(string) + retry_policy = optional(any) + })) + default = {} + + validation { + condition = alltrue([ + for schedule in var.schedules : + schedule.kms_key_arn != null && + trimspace(schedule.kms_key_arn) != "" + ]) + + error_message = "Each schedule must specify a non-empty kms_key_arn." + } } variable "pipes" { From 53f32de9ea619ace5c20462f6b72256ea8c8f208 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 17:38:26 +0100 Subject: [PATCH 30/35] feat: force pipes to use explicit KMS keys for encryption --- infrastructure/modules/eventbridge/README.md | 4 ++- infrastructure/modules/eventbridge/locals.tf | 4 ++- infrastructure/modules/eventbridge/main.tf | 2 +- .../modules/eventbridge/variables.tf | 29 +++++++++++++++++-- 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index 0929ebd4..da07c059 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -24,6 +24,8 @@ DAVEH: document var.pipes DAVEH: document var.kms_key_identifier +DAVEH: document var.pipes + @@ -128,7 +130,7 @@ No resources. | [on\_off\_pattern](#input\_on\_off\_pattern) | Used to turn resources on and off based on a time pattern | `string` | `"n/a"` | no | | [owner](#input\_owner) | The name and or NHS.net email address of the service owner | `string` | `"None"` | no | | [permissions](#input\_permissions) | A map of objects with EventBridge Permission definitions. | `map(any)` | `{}` | no | -| [pipes](#input\_pipes) | A map of objects with EventBridge Pipe definitions. | `any` | `{}` | no | +| [pipes](#input\_pipes) | A map of EventBridge Pipe definitions. |
map(object({
role_arn = optional(string)
source = string
target = string
kms_key_identifier = string
description = optional(string)
desired_state = optional(string)
source_parameters = optional(any)
target_parameters = optional(any)
enrichment = optional(string)
enrichment_parameters = optional(any)
log_configuration = optional(any)
tags = optional(map(string), {})
}))
| `{}` | no | | [policies](#input\_policies) | List of policy statements ARN to attach to IAM role | `list(string)` | `[]` | no | | [policy](#input\_policy) | An additional policy document ARN to attach to IAM role | `string` | `null` | no | | [policy\_json](#input\_policy\_json) | An additional policy document as JSON to attach to IAM role | `string` | `null` | no | diff --git a/infrastructure/modules/eventbridge/locals.tf b/infrastructure/modules/eventbridge/locals.tf index a27fd54b..10122cb8 100644 --- a/infrastructure/modules/eventbridge/locals.tf +++ b/infrastructure/modules/eventbridge/locals.tf @@ -44,6 +44,8 @@ locals { # pipe names must be unique per AWS account and region # prefix keys with the module ID to ensure uniqueness pipes = { - for k, v in var.pipes : "${module.this.id}-${k}" => v + for k, v in var.pipes : "${module.this.id}-${k}" => { + for attribute, value in v : attribute => value if value != null + } } } diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index e8258b6a..87b4b486 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -43,7 +43,7 @@ module "eventbridge" { api_destinations = local.api_destinations schedule_groups = local.schedule_groups schedules = var.schedules - pipes = local.pipes # DAVEH: per-pipe KMS keys can come from var.pipes..kms_key_identifier or fall back to unencrypted + pipes = local.pipes schedule_group_timeouts = var.schedule_group_timeouts role_name = var.role_name role_description = var.role_description diff --git a/infrastructure/modules/eventbridge/variables.tf b/infrastructure/modules/eventbridge/variables.tf index dc571316..91c25c33 100644 --- a/infrastructure/modules/eventbridge/variables.tf +++ b/infrastructure/modules/eventbridge/variables.tf @@ -291,9 +291,32 @@ variable "schedules" { } variable "pipes" { - description = "A map of objects with EventBridge Pipe definitions." - type = any - default = {} + description = "A map of EventBridge Pipe definitions." + type = map(object({ + role_arn = optional(string) + source = string + target = string + kms_key_identifier = string + description = optional(string) + desired_state = optional(string) + source_parameters = optional(any) + target_parameters = optional(any) + enrichment = optional(string) + enrichment_parameters = optional(any) + log_configuration = optional(any) + tags = optional(map(string), {}) + })) + default = {} + + validation { + condition = alltrue([ + for pipe in var.pipes : + pipe.kms_key_identifier != null && + trimspace(pipe.kms_key_identifier) != "" + ]) + + error_message = "Each pipe must specify a non-empty kms_key_identifier." + } } variable "schedule_group_timeouts" { From 6fbd3c371a29f84a170076aa6f4d41ec70c0663e Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Wed, 16 Sep 2026 17:43:08 +0100 Subject: [PATCH 31/35] docs: update todos --- infrastructure/modules/eventbridge/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index da07c059..0e6466cb 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -24,6 +24,10 @@ DAVEH: document var.pipes DAVEH: document var.kms_key_identifier +DAVEH: document var.connections + +DAVEH: document var.schedules + DAVEH: document var.pipes From 4162a03a748295b3ee725cece237b618b1c7ffb3 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Mon, 21 Sep 2026 08:39:40 +0100 Subject: [PATCH 32/35] chore: use more precise type+validation for schedule_groups --- infrastructure/modules/eventbridge/README.md | 2 +- infrastructure/modules/eventbridge/variables.tf | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index 0e6466cb..66f12749 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -153,7 +153,7 @@ No resources. | [role\_tags](#input\_role\_tags) | A map of tags to assign to IAM role | `map(string)` | `{}` | no | | [rules](#input\_rules) | A map of objects with EventBridge Rule definitions. | `map(any)` | `{}` | no | | [schedule\_group\_timeouts](#input\_schedule\_group\_timeouts) | A map of objects with EventBridge Schedule Group create and delete timeouts. | `map(string)` | `{}` | no | -| [schedule\_groups](#input\_schedule\_groups) | A map of objects with EventBridge Schedule Group definitions. | `any` | `{}` | no | +| [schedule\_groups](#input\_schedule\_groups) | A map of objects with EventBridge Schedule Group definitions. |
map(object({
name = optional(string)
name_prefix = optional(string)
tags = optional(map(string), {})
}))
| `{}` | no | | [schedules](#input\_schedules) | A map of objects with EventBridge Schedule definitions. |
map(object({
arn = string
schedule_expression = string
name_prefix = optional(string)
description = optional(string)
group_name = optional(string)
start_date = optional(string)
end_date = optional(string)
kms_key_arn = string
timezone = optional(string)
state = optional(bool, true)
maximum_window_in_minutes = optional(number)
use_flexible_time_window = optional(bool, false)
role_arn = optional(string)
input = optional(string)
dead_letter_arn = optional(string)
ecs_parameters = optional(any)
eventbridge_parameters = optional(any)
partition_key = optional(string)
sagemaker_pipeline_parameters = optional(any)
message_group_id = optional(string)
retry_policy = optional(any)
}))
| `{}` | no | | [schemas\_discoverer\_description](#input\_schemas\_discoverer\_description) | Default schemas discoverer description | `string` | `"Auto schemas discoverer event"` | no | | [service](#input\_service) | ID element. Usually an abbreviation of your service directorate name, e.g. 'bcss' or 'csms', to help ensure generated IDs are globally unique | `string` | `null` | no | diff --git a/infrastructure/modules/eventbridge/variables.tf b/infrastructure/modules/eventbridge/variables.tf index 91c25c33..b49f9815 100644 --- a/infrastructure/modules/eventbridge/variables.tf +++ b/infrastructure/modules/eventbridge/variables.tf @@ -248,8 +248,21 @@ variable "api_destinations" { variable "schedule_groups" { description = "A map of objects with EventBridge Schedule Group definitions." - type = any - default = {} + type = map(object({ + name = optional(string) + name_prefix = optional(string) + tags = optional(map(string), {}) + })) + default = {} + + validation { + condition = alltrue([ + for schedule_group in var.schedule_groups : + schedule_group.name == null || schedule_group.name_prefix == null + ]) + + error_message = "Each schedule group may specify either name or name_prefix, but not both." + } } variable "schedules" { From 5366a13911253a284823792e18ae3d1abba50937 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Mon, 21 Sep 2026 10:14:26 +0100 Subject: [PATCH 33/35] feat: fix group names in schedules to match names in schedule groups --- infrastructure/modules/eventbridge/README.md | 2 +- infrastructure/modules/eventbridge/locals.tf | 24 ++++++++++++------- infrastructure/modules/eventbridge/main.tf | 2 +- .../modules/eventbridge/variables.tf | 15 ++---------- 4 files changed, 20 insertions(+), 23 deletions(-) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index 66f12749..e54d9f0f 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -153,7 +153,7 @@ No resources. | [role\_tags](#input\_role\_tags) | A map of tags to assign to IAM role | `map(string)` | `{}` | no | | [rules](#input\_rules) | A map of objects with EventBridge Rule definitions. | `map(any)` | `{}` | no | | [schedule\_group\_timeouts](#input\_schedule\_group\_timeouts) | A map of objects with EventBridge Schedule Group create and delete timeouts. | `map(string)` | `{}` | no | -| [schedule\_groups](#input\_schedule\_groups) | A map of objects with EventBridge Schedule Group definitions. |
map(object({
name = optional(string)
name_prefix = optional(string)
tags = optional(map(string), {})
}))
| `{}` | no | +| [schedule\_groups](#input\_schedule\_groups) | A map of objects with EventBridge Schedule Group definitions. Names are derived from the object keys and cannot be overridden. |
map(object({
tags = optional(map(string), {})
}))
| `{}` | no | | [schedules](#input\_schedules) | A map of objects with EventBridge Schedule definitions. |
map(object({
arn = string
schedule_expression = string
name_prefix = optional(string)
description = optional(string)
group_name = optional(string)
start_date = optional(string)
end_date = optional(string)
kms_key_arn = string
timezone = optional(string)
state = optional(bool, true)
maximum_window_in_minutes = optional(number)
use_flexible_time_window = optional(bool, false)
role_arn = optional(string)
input = optional(string)
dead_letter_arn = optional(string)
ecs_parameters = optional(any)
eventbridge_parameters = optional(any)
partition_key = optional(string)
sagemaker_pipeline_parameters = optional(any)
message_group_id = optional(string)
retry_policy = optional(any)
}))
| `{}` | no | | [schemas\_discoverer\_description](#input\_schemas\_discoverer\_description) | Default schemas discoverer description | `string` | `"Auto schemas discoverer event"` | no | | [service](#input\_service) | ID element. Usually an abbreviation of your service directorate name, e.g. 'bcss' or 'csms', to help ensure generated IDs are globally unique | `string` | `null` | no | diff --git a/infrastructure/modules/eventbridge/locals.tf b/infrastructure/modules/eventbridge/locals.tf index 10122cb8..8b60dc6f 100644 --- a/infrastructure/modules/eventbridge/locals.tf +++ b/infrastructure/modules/eventbridge/locals.tf @@ -26,18 +26,26 @@ locals { } # schedule group names must be unique per AWS account and region - # respect `name` and `name_prefix` if given - # otherwise include module ID and key in `name_prefix` + # prefix provided names with the module ID to ensure uniqueness + # disallow explicitly setting `name` or `name_prefix` schedule_groups = { for k, v in var.schedule_groups : k => ( - contains(keys(v), "name") || contains(keys(v), "name_prefix") - ? v - : merge( + merge(v, { name = "${module.this.id}-${k}" }) + ) + } + + # if a schedule gives a group_name, fix it to match the corresponding + # name in schedule_groups + schedules = { + for k, v in var.schedules : k => ( + contains(keys(v), "group_name") && local.schedule_groups[v.group_name] != null + ? merge( + v, { - name_prefix = "${module.this.id}-${k}" - }, - v + group_name = local.schedule_groups[v.group_name].name + } ) + : v ) } diff --git a/infrastructure/modules/eventbridge/main.tf b/infrastructure/modules/eventbridge/main.tf index 87b4b486..f8f34fe3 100644 --- a/infrastructure/modules/eventbridge/main.tf +++ b/infrastructure/modules/eventbridge/main.tf @@ -42,7 +42,7 @@ module "eventbridge" { connections = local.connections api_destinations = local.api_destinations schedule_groups = local.schedule_groups - schedules = var.schedules + schedules = local.schedules pipes = local.pipes schedule_group_timeouts = var.schedule_group_timeouts role_name = var.role_name diff --git a/infrastructure/modules/eventbridge/variables.tf b/infrastructure/modules/eventbridge/variables.tf index b49f9815..c1c42ac5 100644 --- a/infrastructure/modules/eventbridge/variables.tf +++ b/infrastructure/modules/eventbridge/variables.tf @@ -247,22 +247,11 @@ variable "api_destinations" { } variable "schedule_groups" { - description = "A map of objects with EventBridge Schedule Group definitions." + description = "A map of objects with EventBridge Schedule Group definitions. Names are derived from the object keys and cannot be overridden." type = map(object({ - name = optional(string) - name_prefix = optional(string) - tags = optional(map(string), {}) + tags = optional(map(string), {}) })) default = {} - - validation { - condition = alltrue([ - for schedule_group in var.schedule_groups : - schedule_group.name == null || schedule_group.name_prefix == null - ]) - - error_message = "Each schedule group may specify either name or name_prefix, but not both." - } } variable "schedules" { From b521bd2acb527d7eaac6cd231c2041e279373eb8 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Tue, 22 Sep 2026 11:42:34 +0100 Subject: [PATCH 34/35] chore: todos --- infrastructure/modules/eventbridge/locals.tf | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/infrastructure/modules/eventbridge/locals.tf b/infrastructure/modules/eventbridge/locals.tf index 8b60dc6f..e73d03ab 100644 --- a/infrastructure/modules/eventbridge/locals.tf +++ b/infrastructure/modules/eventbridge/locals.tf @@ -24,6 +24,9 @@ locals { api_destinations = { for k, v in var.api_destinations : "${module.this.id}-${k}" => v } + # DAVEH: API destination → connection + # The wrapper prefixes connections keys in locals.tf:18-21, but does + # not update api_destinations[*].connection_name. # schedule group names must be unique per AWS account and region # prefix provided names with the module ID to ensure uniqueness @@ -56,4 +59,10 @@ locals { for attribute, value in v : attribute => value if value != null } } + # DAVEH: Pipe → API destination enrichment + # The wrapper prefixes API-destination keys, but leaves pipes[*].enrichment unchanged. + + # DAVEH: EventBridge target → API destination + # The wrapper prefixes api_destinations keys in locals.tf:23-26, but + # leaves targets[*].destination unchanged. } From 59a7b58b05034f08b93d71c3dbd8eb4a0f9171e6 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Tue, 22 Sep 2026 11:54:30 +0100 Subject: [PATCH 35/35] feat: more precise types for inputs --- infrastructure/modules/eventbridge/README.md | 14 +-- .../modules/eventbridge/variables.tf | 85 ++++++++++++++++--- 2 files changed, 78 insertions(+), 21 deletions(-) diff --git a/infrastructure/modules/eventbridge/README.md b/infrastructure/modules/eventbridge/README.md index e54d9f0f..623c119a 100644 --- a/infrastructure/modules/eventbridge/README.md +++ b/infrastructure/modules/eventbridge/README.md @@ -60,7 +60,7 @@ No resources. | Name | Description | Type | Default | Required | | ---- | ----------- | ---- | ------- | :------: | | [additional\_tag\_map](#input\_additional\_tag\_map) | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.
This is for some rare cases where resources want additional configuration of tags
and therefore take a list of maps with tag key, value, and additional configuration. | `map(string)` | `{}` | no | -| [api\_destinations](#input\_api\_destinations) | A map of objects with EventBridge Destination definitions. | `map(any)` | `{}` | no | +| [api\_destinations](#input\_api\_destinations) | A map of objects with EventBridge Destination definitions. |
map(object({
description = optional(string)
invocation_endpoint = string
http_method = string
invocation_rate_limit_per_second = optional(number)
connection_name = optional(string)
}))
| `{}` | no | | [append\_connection\_postfix](#input\_append\_connection\_postfix) | Controls whether to append '-connection' to the name of the connection | `bool` | `true` | no | | [append\_destination\_postfix](#input\_append\_destination\_postfix) | Controls whether to append '-destination' to the name of the destination | `bool` | `true` | no | | [append\_pipe\_postfix](#input\_append\_pipe\_postfix) | Controls whether to append '-pipe' to the name of the pipe | `bool` | `true` | no | @@ -68,7 +68,7 @@ No resources. | [append\_schedule\_group\_postfix](#input\_append\_schedule\_group\_postfix) | Controls whether to append '-group' to the name of the schedule group | `bool` | `true` | no | | [append\_schedule\_postfix](#input\_append\_schedule\_postfix) | Controls whether to append '-schedule' to the name of the schedule | `bool` | `true` | no | | [application\_role](#input\_application\_role) | The role the application is performing | `string` | `"General"` | no | -| [archives](#input\_archives) | A map of objects with the EventBridge Archive definitions. | `map(any)` | `{}` | no | +| [archives](#input\_archives) | A map of objects with the EventBridge Archive definitions. |
map(object({
name = optional(string)
event_source_arn = optional(string)
description = optional(string)
event_pattern = optional(string)
retention_days = optional(number)
kms_key_identifier = optional(string)
}))
| `{}` | no | | [attach\_api\_destination\_policy](#input\_attach\_api\_destination\_policy) | Controls whether the API Destination policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | | [attach\_cloudwatch\_policy](#input\_attach\_cloudwatch\_policy) | Controls whether the Cloudwatch policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | | [attach\_ecs\_policy](#input\_attach\_ecs\_policy) | Controls whether the ECS policy should be added to IAM role for EventBridge Target | `bool` | `false` | no | @@ -108,7 +108,7 @@ No resources. | [create\_targets](#input\_create\_targets) | Controls whether EventBridge Target resources should be created | `bool` | `true` | no | | [data\_classification](#input\_data\_classification) | Used to identify the data classification of the resource, e.g 1-5 | `string` | `"n/a"` | no | | [data\_type](#input\_data\_type) | The tag data\_type | `string` | `"None"` | no | -| [dead\_letter\_config](#input\_dead\_letter\_config) | Configuration details of the Amazon SQS queue for EventBridge to use as a dead-letter queue (DLQ) | `any` | `{}` | no | +| [dead\_letter\_config](#input\_dead\_letter\_config) | Configuration details of the Amazon SQS queue for EventBridge to use as a dead-letter queue (DLQ) |
object({
arn = optional(string)
})
| `{}` | no | | [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | | [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no | | [ecs\_pass\_role\_resources](#input\_ecs\_pass\_role\_resources) | List of approved roles to be passed | `list(string)` | `[]` | no | @@ -133,14 +133,14 @@ No resources. | [number\_of\_policy\_jsons](#input\_number\_of\_policy\_jsons) | Number of policies JSON to attach to IAM role | `number` | `0` | no | | [on\_off\_pattern](#input\_on\_off\_pattern) | Used to turn resources on and off based on a time pattern | `string` | `"n/a"` | no | | [owner](#input\_owner) | The name and or NHS.net email address of the service owner | `string` | `"None"` | no | -| [permissions](#input\_permissions) | A map of objects with EventBridge Permission definitions. | `map(any)` | `{}` | no | +| [permissions](#input\_permissions) | A map of objects with EventBridge Permission definitions. |
map(object({
action = optional(string)
event_bus_name = optional(string)
condition_org = optional(string)
}))
| `{}` | no | | [pipes](#input\_pipes) | A map of EventBridge Pipe definitions. |
map(object({
role_arn = optional(string)
source = string
target = string
kms_key_identifier = string
description = optional(string)
desired_state = optional(string)
source_parameters = optional(any)
target_parameters = optional(any)
enrichment = optional(string)
enrichment_parameters = optional(any)
log_configuration = optional(any)
tags = optional(map(string), {})
}))
| `{}` | no | | [policies](#input\_policies) | List of policy statements ARN to attach to IAM role | `list(string)` | `[]` | no | | [policy](#input\_policy) | An additional policy document ARN to attach to IAM role | `string` | `null` | no | | [policy\_json](#input\_policy\_json) | An additional policy document as JSON to attach to IAM role | `string` | `null` | no | | [policy\_jsons](#input\_policy\_jsons) | List of additional policy documents as JSON to attach to IAM role | `list(string)` | `[]` | no | | [policy\_path](#input\_policy\_path) | Path of IAM policy to use for EventBridge | `string` | `null` | no | -| [policy\_statements](#input\_policy\_statements) | Map of dynamic policy statements to attach to IAM role | `any` | `{}` | no | +| [policy\_statements](#input\_policy\_statements) | Map of dynamic policy statements to attach to IAM role |
map(object({
sid = optional(string)
effect = optional(string)
actions = optional(list(string))
not_actions = optional(list(string))
resources = optional(list(string))
not_resources = optional(list(string))
principals = optional(any)
not_principals = optional(any)
condition = optional(any)
}))
| `{}` | no | | [project](#input\_project) | ID element. A project identifier, indicating the name or role of the project the resource is for, such as `website` or `api` | `string` | `null` | no | | [public\_facing](#input\_public\_facing) | Whether this resource is public facing | `bool` | `false` | no | | [regex\_replace\_chars](#input\_regex\_replace\_chars) | Terraform regular expression (regex) string.
Characters matching the regex will be removed from the ID elements.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | @@ -151,7 +151,7 @@ No resources. | [role\_path](#input\_role\_path) | Path of IAM role to use for EventBridge | `string` | `null` | no | | [role\_permissions\_boundary](#input\_role\_permissions\_boundary) | The ARN of the policy that is used to set the permissions boundary for the IAM role used by EventBridge | `string` | `null` | no | | [role\_tags](#input\_role\_tags) | A map of tags to assign to IAM role | `map(string)` | `{}` | no | -| [rules](#input\_rules) | A map of objects with EventBridge Rule definitions. | `map(any)` | `{}` | no | +| [rules](#input\_rules) | A map of objects with EventBridge Rule definitions. |
map(object({
name_prefix = optional(string)
description = optional(string)
event_pattern = optional(string)
schedule_expression = optional(string)
role_arn = optional(bool)
enabled = optional(bool)
state = optional(string)
force_destroy = optional(bool)
}))
| `{}` | no | | [schedule\_group\_timeouts](#input\_schedule\_group\_timeouts) | A map of objects with EventBridge Schedule Group create and delete timeouts. | `map(string)` | `{}` | no | | [schedule\_groups](#input\_schedule\_groups) | A map of objects with EventBridge Schedule Group definitions. Names are derived from the object keys and cannot be overridden. |
map(object({
tags = optional(map(string), {})
}))
| `{}` | no | | [schedules](#input\_schedules) | A map of objects with EventBridge Schedule definitions. |
map(object({
arn = string
schedule_expression = string
name_prefix = optional(string)
description = optional(string)
group_name = optional(string)
start_date = optional(string)
end_date = optional(string)
kms_key_arn = string
timezone = optional(string)
state = optional(bool, true)
maximum_window_in_minutes = optional(number)
use_flexible_time_window = optional(bool, false)
role_arn = optional(string)
input = optional(string)
dead_letter_arn = optional(string)
ecs_parameters = optional(any)
eventbridge_parameters = optional(any)
partition_key = optional(string)
sagemaker_pipeline_parameters = optional(any)
message_group_id = optional(string)
retry_policy = optional(any)
}))
| `{}` | no | @@ -165,7 +165,7 @@ No resources. | [stack](#input\_stack) | ID element. The name of the stack/component, e.g. `database`, `web`, `waf`, `eks` | `string` | `null` | no | | [tag\_version](#input\_tag\_version) | Used to identify the tagging version in use | `string` | `"1.0"` | no | | [tags](#input\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no | -| [targets](#input\_targets) | A map of objects with EventBridge Target definitions. | `any` | `{}` | no | +| [targets](#input\_targets) | A map of objects with EventBridge Target definitions. |
map(list(object({
name = string
arn = optional(string)
destination = optional(string)
target_id = optional(string)
input = optional(string)
input_path = optional(string)
force_destroy = optional(bool)
attach_role_arn = optional(bool)
run_command_targets = optional(any)
ecs_target = optional(any)
batch_target = optional(any)
partition_key_path = optional(string)
message_group_id = optional(string)
http_target = optional(any)
appsync_target = optional(any)
input_transformer = optional(any)
dead_letter_arn = optional(string)
retry_policy = optional(any)
})))
| `{}` | no | | [terraform\_source](#input\_terraform\_source) | Source location to record in the Terraform\_source tag. Defaults to the caller module path when not set. | `string` | `null` | no | | [tool](#input\_tool) | The tool used to deploy the resource | `string` | `"Terraform"` | no | | [trusted\_entities](#input\_trusted\_entities) | Additional trusted entities for assuming roles (trust relationship) | `list(string)` | `[]` | no | diff --git a/infrastructure/modules/eventbridge/variables.tf b/infrastructure/modules/eventbridge/variables.tf index c1c42ac5..c199c298 100644 --- a/infrastructure/modules/eventbridge/variables.tf +++ b/infrastructure/modules/eventbridge/variables.tf @@ -184,8 +184,10 @@ variable "kms_key_identifier" { variable "dead_letter_config" { description = "Configuration details of the Amazon SQS queue for EventBridge to use as a dead-letter queue (DLQ)" - type = any - default = {} + type = object({ + arn = optional(string) + }) + default = {} } variable "schemas_discoverer_description" { @@ -196,26 +198,65 @@ variable "schemas_discoverer_description" { variable "rules" { description = "A map of objects with EventBridge Rule definitions." - type = map(any) - default = {} + type = map(object({ + name_prefix = optional(string) + description = optional(string) + event_pattern = optional(string) + schedule_expression = optional(string) + role_arn = optional(bool) + enabled = optional(bool) + state = optional(string) + force_destroy = optional(bool) + })) + default = {} } variable "targets" { description = "A map of objects with EventBridge Target definitions." - type = any - default = {} + type = map(list(object({ + name = string + arn = optional(string) + destination = optional(string) + target_id = optional(string) + input = optional(string) + input_path = optional(string) + force_destroy = optional(bool) + attach_role_arn = optional(bool) + run_command_targets = optional(any) + ecs_target = optional(any) + batch_target = optional(any) + partition_key_path = optional(string) + message_group_id = optional(string) + http_target = optional(any) + appsync_target = optional(any) + input_transformer = optional(any) + dead_letter_arn = optional(string) + retry_policy = optional(any) + }))) + default = {} } variable "archives" { description = "A map of objects with the EventBridge Archive definitions." - type = map(any) - default = {} + type = map(object({ + name = optional(string) + event_source_arn = optional(string) + description = optional(string) + event_pattern = optional(string) + retention_days = optional(number) + kms_key_identifier = optional(string) + })) + default = {} } variable "permissions" { description = "A map of objects with EventBridge Permission definitions." - type = map(any) - default = {} + type = map(object({ + action = optional(string) + event_bus_name = optional(string) + condition_org = optional(string) + })) + default = {} } variable "connections" { @@ -242,8 +283,14 @@ variable "connections" { variable "api_destinations" { description = "A map of objects with EventBridge Destination definitions." - type = map(any) - default = {} + type = map(object({ + description = optional(string) + invocation_endpoint = string + http_method = string + invocation_rate_limit_per_second = optional(number) + connection_name = optional(string) + })) + default = {} } variable "schedule_groups" { @@ -563,6 +610,16 @@ variable "policies" { variable "policy_statements" { description = "Map of dynamic policy statements to attach to IAM role" - type = any - default = {} + type = map(object({ + sid = optional(string) + effect = optional(string) + actions = optional(list(string)) + not_actions = optional(list(string)) + resources = optional(list(string)) + not_resources = optional(list(string)) + principals = optional(any) + not_principals = optional(any) + condition = optional(any) + })) + default = {} }