https://github.com/launchbynttdata/tf-aws-module_collection-eventbridge
https://github.com/launchbynttdata/tf-aws-module_collection-eventbridge
Last synced: 13 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/launchbynttdata/tf-aws-module_collection-eventbridge
- Owner: launchbynttdata
- License: apache-2.0
- Created: 2026-03-17T13:04:34.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-04-08T17:44:37.000Z (3 months ago)
- Last Synced: 2026-04-08T18:35:31.992Z (3 months ago)
- Language: HCL
- Size: 102 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Codeowners: CODEOWNERS
- Notice: NOTICE
Awesome Lists containing this project
README
# tf-aws-module_collection-eventbridge
[](https://opensource.org/licenses/Apache-2.0)
[](https://creativecommons.org/licenses/by-nc-nd/4.0/)
## Overview
Terraform collection module for AWS EventBridge: custom or existing event buses, rules and targets, archives, EventBridge Scheduler schedules and groups, Pipes, and API destinations. It composes Launch primitive modules from `terraform.registry.launch.nttdata.com` (pinned versions). Root data sources (`aws_caller_identity`, `aws_region`, `aws_cloudwatch_event_bus`) remain direct provider reads.
- **Provider:** AWS `~> 5.0`, Terraform `~> 1.9`
- **Tags:** `tags` is required (non-empty). Optional `required_tag_keys` enforces organizational keys.
- **Example:** [`examples/complete`](examples/complete) (uses `test.tfvars` for Terratest).
## Resource name overrides
**`name_override`** (`pipes[*]`, `schedules[*]`): When set, this exact string becomes the
deployed AWS resource name, bypassing the `{standard}-{logical_name}` Launch naming convention.
Use when an external naming system (e.g. an ADO resource-names module) pre-computes the full AWS
name and callers need to preserve existing resource identities across refactors.
The field is optional; omitting it retains the existing naming behavior unchanged.
Length validation: 1–64 characters (AWS pipe and schedule name limit).
## Upgrading (breaking changes)
- **`advanced_config`:** Removed. It was unused in resource logic; see [Future improvement: optional passthrough / escape hatches](#future-improvement-optional-passthrough--escape-hatches) for how to extend the module instead. Drop the argument and any outputs that referenced it.
- **Rule names:** Rules are created with the same naming prefix pattern as archives, pipes, and schedules (`resource_names["event_rule"]` + logical `rules[*].name`). The `rule_names` output returns those **deployed** AWS names (in input order), not the bare logical names. Update external references, metric filters, and Terratest expectations accordingly.
- **`archives`:** The `kms_key_arn` argument was removed from the object type until the archive primitive supports KMS.
- **`rules`:** Each rule must declare at least one target; duplicate logical rule names, invalid event patterns, and unsupported target types for generated IAM are rejected at plan time via variable validation.
- **`bus.policies`:** Policy attachments use **`sha256(policy)`** as the `for_each` key so reordering the policy list does not destroy and recreate resources.
## IAM policies
Roles created when `create_role = true` (EventBridge targets, Scheduler, Pipes) use **`module_primitive/iam_role`**, **`module_primitive/iam_policy`**, and **`module_primitive/iam_role_policy_attachment`** with trust policies for the relevant service principal (`events.amazonaws.com`, `scheduler.amazonaws.com`, `pipes.amazonaws.com`). Trust policies always include **`aws:SourceAccount`**. **Scheduler** roles use **SourceAccount only** so `CreateSchedule` can validate assume-role (a schedule-scoped `aws:SourceArn` condition is often rejected before the schedule exists). **EventBridge rule targets** and **Pipes** also add **`aws:SourceArn`** for the specific rule or pipe ARN. Permission statements use **specific resource ARNs** (targets, queues, topics, etc.). This module does **not** emit `Resource: "*"` in generated policies.
**Pipes execution logging:** When you set `pipes[*].log_configuration` and/or `managed_execution_logging`, and `create_role = true`, generated pipe policies include CloudWatch Logs (`logs:CreateLogStream`, `logs:PutLogEvents` on the log group), optional Firehose and S3 actions for those destinations, and KMS decrypt/generate for `execution_logs_kms_key_arn` (or the CMK on a managed log group) when encryption applies. If `create_role = false`, attach the same permissions to your `role_arn`. See [Amazon EventBridge Pipes logging](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-pipes-logs.html).
Scheduler, pipe, and rule-target IAM for `create_role = true` only covers **documented** target and enrichment ARN patterns; unsupported ARNs fail variable validation instead of producing empty policy actions.
If a future change requires a wildcard `Resource` for a particular AWS action, that statement must be isolated, commented in Terraform with **why** it is required, and documented here with a link to the relevant **AWS documentation** (for example [IAM policy elements](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html) and the service’s permissions reference).
## API destinations and connections
Connections and API destinations use **`module_primitive/cloudwatch_event_connection`** (1.0.0) and **`module_primitive/cloudwatch_event_api_destination`** (0.1.0). The connection module is called with `description = ""` and `kms_key_identifier = ""` instead of `null` so Terraform does not evaluate `length(null)` in that primitive’s variable validations.
## Tests
- `tests/post_deploy_functional` — deploy, SDK checks, `PutEvents` mutating test
- `tests/post_deploy_functional_readonly` — `RunNonDestructiveTest`, read-only SDK checks only
- `tests/review_plan` — plan-only regressions (schedule groups, pipe IAM, pipe execution logging IAM, API destination naming, duplicate-name validation, Firehose scheduler IAM, stable bus policy keys)
**CI vs local:** When `CI=true` (e.g. GitHub Actions), `post_deploy_functional` still runs **Terraform apply/destroy** and all SDK checks except the long **PutEvents→SNS→SQS sink** subtest (that subtest is skipped to avoid multi-minute SQS drain/long-poll in workflows). Run the full functional suite locally with AWS credentials:
```bash
go test -v -timeout 30m ./tests/post_deploy_functional/...
go test -v -timeout 15m ./tests/post_deploy_functional_readonly/... # requires examples/complete already applied
```
Local functional runs use verbose Terraform stdout logging and progress logs during the long SQS drain/long-poll step.
Configure AWS credentials and run from the repo root with `mise`/`asdf` Go and Terraform as appropriate.
## Future improvement: optional passthrough / escape hatches
This module intentionally avoids a generic `any`-typed “advanced config” input: it implied behavior without implementing it, encouraged opaque merges that are hard to review, and complicated static analysis. If a real need appears—for example, wiring a new argument on a primitive before the collection’s typed object model catches up—a better path is:
1. **Prefer explicit variables** on the collection module that map to documented primitive arguments, with validation and README notes.
2. **If many optional knobs are needed**, introduce a **narrowly typed** `optional(object({ ... }))` per concern (e.g. scheduler-only overrides) rather than one global bag.
3. **Last resort:** document any merge semantics, forbid bypassing tagging and IAM controls in module policy, and add review-plan or contract tests so passthrough cannot silently widen blast radius.
Until then, callers should extend via separate resources or upstream module changes rather than an unused placeholder variable.
## Requirements
| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | ~> 1.9 |
| [aws](#requirement\_aws) | ~> 5.0 |
## Providers
| Name | Version |
|------|---------|
| [aws](#provider\_aws) | 5.100.0 |
## Modules
| Name | Source | Version |
|------|--------|---------|
| [event\_api\_destination](#module\_event\_api\_destination) | terraform.registry.launch.nttdata.com/module_primitive/cloudwatch_event_api_destination/aws | ~> 0.0 |
| [event\_archive](#module\_event\_archive) | terraform.registry.launch.nttdata.com/module_primitive/cloudwatch_event_archive/aws | ~> 0.0 |
| [event\_bus](#module\_event\_bus) | terraform.registry.launch.nttdata.com/module_primitive/cloudwatch_event_bus/aws | ~> 0.0 |
| [event\_bus\_policy](#module\_event\_bus\_policy) | terraform.registry.launch.nttdata.com/module_primitive/cloudwatch_event_bus_policy/aws | ~> 0.0 |
| [event\_connection](#module\_event\_connection) | terraform.registry.launch.nttdata.com/module_primitive/cloudwatch_event_connection/aws | ~> 1.0 |
| [event\_rule](#module\_event\_rule) | terraform.registry.launch.nttdata.com/module_primitive/cloudwatch_event_rule/aws | ~> 0.0 |
| [event\_target](#module\_event\_target) | terraform.registry.launch.nttdata.com/module_primitive/cloudwatch_event_target/aws | ~> 0.0 |
| [iam\_policy\_event\_target](#module\_iam\_policy\_event\_target) | terraform.registry.launch.nttdata.com/module_primitive/iam_policy/aws | ~> 0.0 |
| [iam\_policy\_pipe](#module\_iam\_policy\_pipe) | terraform.registry.launch.nttdata.com/module_primitive/iam_policy/aws | ~> 0.0 |
| [iam\_policy\_scheduler](#module\_iam\_policy\_scheduler) | terraform.registry.launch.nttdata.com/module_primitive/iam_policy/aws | ~> 0.0 |
| [iam\_role\_event\_target](#module\_iam\_role\_event\_target) | terraform.registry.launch.nttdata.com/module_primitive/iam_role/aws | ~> 0.0 |
| [iam\_role\_pipe](#module\_iam\_role\_pipe) | terraform.registry.launch.nttdata.com/module_primitive/iam_role/aws | ~> 0.0 |
| [iam\_role\_policy\_attachment\_event\_target](#module\_iam\_role\_policy\_attachment\_event\_target) | terraform.registry.launch.nttdata.com/module_primitive/iam_role_policy_attachment/aws | ~> 0.0 |
| [iam\_role\_policy\_attachment\_pipe](#module\_iam\_role\_policy\_attachment\_pipe) | terraform.registry.launch.nttdata.com/module_primitive/iam_role_policy_attachment/aws | ~> 0.0 |
| [iam\_role\_policy\_attachment\_scheduler](#module\_iam\_role\_policy\_attachment\_scheduler) | terraform.registry.launch.nttdata.com/module_primitive/iam_role_policy_attachment/aws | ~> 0.0 |
| [iam\_role\_scheduler](#module\_iam\_role\_scheduler) | terraform.registry.launch.nttdata.com/module_primitive/iam_role/aws | ~> 0.0 |
| [pipe\_execution\_log\_group](#module\_pipe\_execution\_log\_group) | terraform.registry.launch.nttdata.com/module_primitive/cloudwatch_log_group/aws | ~> 0.0 |
| [pipes\_pipe](#module\_pipes\_pipe) | terraform.registry.launch.nttdata.com/module_primitive/pipes_pipe/aws | ~> 0.0 |
| [resource\_names](#module\_resource\_names) | terraform.registry.launch.nttdata.com/module_library/resource_name/launch | ~> 2.0 |
| [scheduler\_schedule](#module\_scheduler\_schedule) | terraform.registry.launch.nttdata.com/module_primitive/scheduler_schedule/aws | ~> 0.0 |
| [scheduler\_schedule\_group](#module\_scheduler\_schedule\_group) | terraform.registry.launch.nttdata.com/module_primitive/scheduler_schedule_group/aws | ~> 0.0 |
## Resources
| Name | Type |
|------|------|
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_cloudwatch_event_bus.existing](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/cloudwatch_event_bus) | data source |
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
## Inputs
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| [api\_destinations](#input\_api\_destinations) | API destinations (connection + destination). When rate\_limit\_per\_second is null, the module uses 300 invocations per second (AWS default-style cap). |
list(object({
connection_name = string
authorization_type = string
auth_parameters = any
destination_name = string
invocation_endpoint = string
http_method = string
rate_limit_per_second = optional(number)
})) | `[]` | no |
| [archives](#input\_archives) | Event archives on the effective event bus. KMS encryption on archives is not supported until the cloudwatch\_event\_archive primitive exposes a KMS argument. | list(object({
name = string
event_pattern_json = optional(string)
retention_days = optional(number)
})) | `[]` | no |
| [bus](#input\_bus) | Event bus configuration: create a custom bus or use an existing bus. | object({
create = bool
name = optional(string)
existing_bus_name = optional(string)
existing_bus_arn = optional(string)
policies = optional(list(string), [])
}) | n/a | yes |
| [class\_env](#input\_class\_env) | Environment class (e.g. dev, qa, prod) for resource naming. | `string` | `"dev"` | no |
| [instance\_env](#input\_instance\_env) | Numeric instance of the environment for resource naming. | `number` | `0` | no |
| [instance\_resource](#input\_instance\_resource) | Numeric instance of the resource for resource naming. | `number` | `0` | no |
| [logical\_product\_family](#input\_logical\_product\_family) | Product family name used by the resource naming module. | `string` | `"launch"` | no |
| [logical\_product\_service](#input\_logical\_product\_service) | Product service name used by the resource naming module. | `string` | `"eventbridge"` | no |
| [pipes](#input\_pipes) | EventBridge Pipes. `name_override`: when set, used verbatim as the AWS pipe name instead of the Launch `{standard}-{name}` prefix (1–64 chars). Optional `log_configuration` (execution logs; `level` required when set), `managed_execution_logging` (creates a CloudWatch log group; mutually exclusive with `log_configuration.cloudwatch_logs_log_destination`), and `execution_logs_kms_key_arn` for encrypted logs. | list(object({
name = string
name_override = optional(string)
source_arn = string
source_parameters = optional(any)
filter_criteria = optional(any)
enrichment_arn = optional(string)
enrichment_parameters = optional(any)
target_arn = string
target_parameters = optional(any)
role_arn = optional(string)
create_role = optional(bool, false)
source_kms_key_arn = optional(string)
log_configuration = optional(any)
managed_execution_logging = optional(any)
execution_logs_kms_key_arn = optional(string)
})) | `[]` | no |
| [required\_tag\_keys](#input\_required\_tag\_keys) | If non-empty, every key listed here must exist in tags. | `list(string)` | `[]` | no |
| [resource\_names\_map](#input\_resource\_names\_map) | Map consumed by the resource naming module (for\_each key -> { name, max\_length }). | map(object({
name = string
max_length = optional(number, 60)
})) | {
"api_destination": {
"max_length": 64,
"name": "apid"
},
"event_archive": {
"max_length": 48,
"name": "arc"
},
"event_bus": {
"max_length": 256,
"name": "ebus"
},
"event_connection": {
"max_length": 64,
"name": "conn"
},
"event_rule": {
"max_length": 64,
"name": "rule"
},
"pipe": {
"max_length": 64,
"name": "pipe"
},
"schedule": {
"max_length": 64,
"name": "sched"
},
"schedule_group": {
"max_length": 64,
"name": "sgrp"
}
} | no |
| [rules](#input\_rules) | EventBridge rules and targets on the effective event bus. | list(object({
name = string
description = optional(string)
state = optional(string, "ENABLED")
event_pattern_json = string
targets = list(object({
name = string
arn = string
type = string
role_arn = optional(string)
create_role = optional(bool, false)
dlq_arn = optional(string)
retry_policy = optional(any)
input_json = optional(string)
input_path = optional(string)
input_transformer = optional(any)
service_specific_overrides = optional(any)
}))
})) | `[]` | no |
| [schedule\_groups](#input\_schedule\_groups) | Scheduler schedule groups to create. Map keys must be static strings in configuration (Terraform for\_each keys).
Values.name is the AWS group name and may depend on apply-time values (e.g. random\_id). Schedules that use a
custom group must set group\_name to the same name string; schedules using only the built-in "default" group
can omit group\_name. | map(object({
name = string
})) | `{}` | no |
| [schedules](#input\_schedules) | EventBridge Scheduler schedules. `name_override`: when set, used verbatim as the AWS schedule name instead of the Launch `{standard}-{name}` prefix (1–64 chars). | list(object({
name = string
name_override = optional(string)
group_name = optional(string)
schedule_expression = string
schedule_expression_timezone = optional(string)
start_date = optional(string)
end_date = optional(string)
flexible_time_window = optional(any)
target_arn = string
target_input_json = optional(string)
retry_policy = optional(any)
dead_letter_arn = optional(string)
role_arn = optional(string)
create_role = optional(bool, false)
ecs_parameters = optional(any)
})) | `[]` | no |
| [tags](#input\_tags) | Required organizational tags applied to all taggable resources. | `map(string)` | n/a | yes |
## Outputs
| Name | Description |
|------|-------------|
| [api\_destination\_arns](#output\_api\_destination\_arns) | API destination ARNs sorted by composite key. |
| [archive\_arns](#output\_archive\_arns) | Archive ARNs sorted by archive key. |
| [archive\_names](#output\_archive\_names) | Archive names sorted by key. |
| [bus\_arn](#output\_bus\_arn) | Effective event bus ARN. |
| [bus\_name](#output\_bus\_name) | Effective event bus name. |
| [connection\_arns](#output\_connection\_arns) | Event connection ARNs sorted by connection\_name (one connection per distinct name). |
| [event\_target\_iam\_role\_names](#output\_event\_target\_iam\_role\_names) | Names of IAM roles created for EventBridge targets (create\_role = true), keyed by rule:target. |
| [pipe\_arns](#output\_pipe\_arns) | Pipe ARNs sorted by pipe name. |
| [pipe\_execution\_log\_group\_arns](#output\_pipe\_execution\_log\_group\_arns) | CloudWatch log group ARNs created for pipes with managed\_execution\_logging, keyed by logical pipe name. |
| [pipe\_execution\_log\_group\_names](#output\_pipe\_execution\_log\_group\_names) | CloudWatch log group names created for pipes with managed\_execution\_logging, keyed by logical pipe name. |
| [pipe\_iam\_role\_names](#output\_pipe\_iam\_role\_names) | Names of IAM roles created for Pipes (create\_role = true). |
| [required\_tag\_keys](#output\_required\_tag\_keys) | Echo of var.required\_tag\_keys after validation (for policy and composition). |
| [rule\_arns](#output\_rule\_arns) | Rule ARNs sorted by rule name for stable ordering. |
| [rule\_names](#output\_rule\_names) | Deployed EventBridge rule names (prefixed), in the same order as var.rules. |
| [schedule\_arns](#output\_schedule\_arns) | Schedule ARNs sorted by schedule name. |
| [scheduler\_iam\_role\_names](#output\_scheduler\_iam\_role\_names) | Names of IAM roles created for Scheduler targets (create\_role = true). |