From 6a20a0ce4265aa8b8686188a595092e7e169d0bf Mon Sep 17 00:00:00 2001 From: aidenvaines-cgi Date: Wed, 29 Apr 2026 15:43:19 +0100 Subject: [PATCH 1/2] CCM-16073 ComponentShuffle Co-authored-by: Copilot --- .tool-versions | 2 +- .../callback-clients/.tool-versions | 1 + .../components/callback-clients/README.md | 29 +++++++ .../callback-clients/cloudwatch_event_rule.tf | 16 ++++ .../callback-clients/locals_remote_state.tf | 21 +++++ .../callback-clients/locals_tfscaffold.tf | 46 +++++++++++ .../components/callback-clients/outputs.tf | 1 + .../callback-clients/pre.sh.disabled | 81 +++++++++++++++++++ .../components/callback-clients/variables.tf | 65 +++++++++++++++ .../components/callbacks/.tool-versions | 2 +- .../terraform/components/callbacks/README.md | 2 +- .../terraform/components/callbacks/locals.tf | 2 +- .../components/callbacks/locals_tfscaffold.tf | 8 +- .../callbacks/module_client_destination.tf | 2 +- .../components/callbacks/module_kms.tf | 2 +- .../callbacks/module_mock_webhook_lambda.tf | 2 +- .../callbacks/module_sqs_inbound_event.tf | 4 +- .../module_transform_filter_lambda.tf | 2 +- .../terraform/components/callbacks/outputs.tf | 15 +++- .../callbacks/s3_bucket_client_config.tf | 2 +- .../components/callbacks/variables.tf | 6 +- 21 files changed, 291 insertions(+), 20 deletions(-) create mode 100644 infrastructure/terraform/components/callback-clients/.tool-versions create mode 100644 infrastructure/terraform/components/callback-clients/README.md create mode 100644 infrastructure/terraform/components/callback-clients/cloudwatch_event_rule.tf create mode 100644 infrastructure/terraform/components/callback-clients/locals_remote_state.tf create mode 100644 infrastructure/terraform/components/callback-clients/locals_tfscaffold.tf create mode 100644 infrastructure/terraform/components/callback-clients/outputs.tf create mode 100755 infrastructure/terraform/components/callback-clients/pre.sh.disabled create mode 100644 infrastructure/terraform/components/callback-clients/variables.tf diff --git a/.tool-versions b/.tool-versions index 4ca52a65..f098ca89 100644 --- a/.tool-versions +++ b/.tool-versions @@ -5,7 +5,7 @@ nodejs 24.14.1 pnpm 10.33.0 pre-commit 3.6.0 ruby 3.3.6 -terraform 1.10.1 +terraform 1.14.3 terraform-docs 0.19.0 #trivy 0.61.0 - TODO - Re-visit Trivy usage https://nhsd-jira.digital.nhs.uk/browse/CCM-15549 vale 3.6.0 diff --git a/infrastructure/terraform/components/callback-clients/.tool-versions b/infrastructure/terraform/components/callback-clients/.tool-versions new file mode 100644 index 00000000..52428ded --- /dev/null +++ b/infrastructure/terraform/components/callback-clients/.tool-versions @@ -0,0 +1 @@ +terraform 1.14.3 diff --git a/infrastructure/terraform/components/callback-clients/README.md b/infrastructure/terraform/components/callback-clients/README.md new file mode 100644 index 00000000..ebb2ba89 --- /dev/null +++ b/infrastructure/terraform/components/callback-clients/README.md @@ -0,0 +1,29 @@ + + + + +## Requirements + +No requirements. +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [aws\_account\_id](#input\_aws\_account\_id) | The AWS Account ID (numeric) | `string` | n/a | yes | +| [default\_tags](#input\_default\_tags) | A map of default tags to apply to all taggable resources within the component | `map(string)` | `{}` | no | +| [environment](#input\_environment) | The name of the tfscaffold environment | `string` | n/a | yes | +| [force\_lambda\_code\_deploy](#input\_force\_lambda\_code\_deploy) | If the lambda package in s3 has the same commit id tag as the terraform build branch, the lambda will not update automatically. Set to True if making changes to Lambda code from on the same commit for example during development | `bool` | `false` | no | +| [group](#input\_group) | The group variables are being inherited from (often synonmous with account short-name) | `string` | n/a | yes | +| [log\_retention\_in\_days](#input\_log\_retention\_in\_days) | The retention period in days for the Cloudwatch Logs events to be retained, default of 0 is indefinite | `number` | `0` | no | +| [parent\_callbacks\_environment](#input\_parent\_callbacks\_environment) | The name of the environment which deployed the parent Amplify resource. Used to identify the appropriate state file. | `string` | `"main"` | no | +| [project](#input\_project) | The name of the tfscaffold project | `string` | n/a | yes | +| [region](#input\_region) | The AWS Region | `string` | n/a | yes | +## Modules + +No modules. +## Outputs + +No outputs. + + + diff --git a/infrastructure/terraform/components/callback-clients/cloudwatch_event_rule.tf b/infrastructure/terraform/components/callback-clients/cloudwatch_event_rule.tf new file mode 100644 index 00000000..6d36322a --- /dev/null +++ b/infrastructure/terraform/components/callback-clients/cloudwatch_event_rule.tf @@ -0,0 +1,16 @@ +resource "aws_cloudwatch_event_rule" "main" { + name = "${local.csi}-callback-rule" + event_bus_name = local.callbacks.eventbus_name.name # Reference the event bus from callbacks component + + event_pattern = jsonencode({ + source = [{ prefix = "" }] # Your event pattern here this is effectively "*" + }) +} + +# resource "aws_cloudwatch_event_target" "main" { +# rule = aws_cloudwatch_event_rule.main.name +# event_bus_name = local.callbacks.eventbus_name.name # Same event bus reference +# target_id = "callback-target" +# arn = # Your target ARN (Lambda, SNS, etc.) +# # Additional target configuration... +# } diff --git a/infrastructure/terraform/components/callback-clients/locals_remote_state.tf b/infrastructure/terraform/components/callback-clients/locals_remote_state.tf new file mode 100644 index 00000000..bc81cbf4 --- /dev/null +++ b/infrastructure/terraform/components/callback-clients/locals_remote_state.tf @@ -0,0 +1,21 @@ +locals { + callbacks = data.terraform_remote_state.callbacks.outputs +} + +data "terraform_remote_state" "callbacks" { + backend = "s3" + + config = { + bucket = local.terraform_state_bucket + + key = format( + "%s/%s/%s/%s/callbacks.tfstate", + var.project, + var.aws_account_id, + "eu-west-2", + var.parent_callbacks_environment + ) + + region = "eu-west-2" + } +} diff --git a/infrastructure/terraform/components/callback-clients/locals_tfscaffold.tf b/infrastructure/terraform/components/callback-clients/locals_tfscaffold.tf new file mode 100644 index 00000000..5c28416c --- /dev/null +++ b/infrastructure/terraform/components/callback-clients/locals_tfscaffold.tf @@ -0,0 +1,46 @@ +locals { + component = "cbc" + + terraform_state_bucket = format( + "%s-tfscaffold-%s-%s", + var.project, + var.aws_account_id, + var.region, + ) + + csi = replace( + format( + "%s-%s-%s", + var.project, + var.environment, + local.component, + ), + "_", + "", + ) + + # CSI for use in resources with a global namespace, i.e. S3 Buckets + csi_global = replace( + format( + "%s-%s-%s-%s-%s", + var.project, + var.aws_account_id, + var.region, + var.environment, + local.component, + ), + "_", + "", + ) + + default_tags = merge( + var.default_tags, + { + Project = var.project + Environment = var.environment + Component = local.component + Group = var.group + Name = local.csi + }, + ) +} diff --git a/infrastructure/terraform/components/callback-clients/outputs.tf b/infrastructure/terraform/components/callback-clients/outputs.tf new file mode 100644 index 00000000..9dcc2f39 --- /dev/null +++ b/infrastructure/terraform/components/callback-clients/outputs.tf @@ -0,0 +1 @@ +# Define the outputs for the component. The outputs may well be referenced by other component in the same or different environments using terraform_remote_state data sources... diff --git a/infrastructure/terraform/components/callback-clients/pre.sh.disabled b/infrastructure/terraform/components/callback-clients/pre.sh.disabled new file mode 100755 index 00000000..f34040cf --- /dev/null +++ b/infrastructure/terraform/components/callback-clients/pre.sh.disabled @@ -0,0 +1,81 @@ +#!/bin/bash + +## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## +## This script is currently disabled (renamed to pre.sh.disabled) as it is only needed for +## Terraform components that need build and publish container images or lambda packageses. +## +## It is left in place for reference and future use when adding new components that require this functionality. +## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## + + +# This script is run before Terraform executable commands. +# It ensures all Node.js dependencies are installed, generates any required dependencies, +# and builds all Lambda functions in the workspace before Terraform provisions infrastructure. +# pre.sh runs in the same shell as terraform.sh, not in a subshell + +: "${PROJECT:?PROJECT is required}" +: "${REGION:?REGION is required}" +: "${COMPONENT:?COMPONENT is required}" +: "${ENVIRONMENT:?ENVIRONMENT is required}" +: "${AWS_ACCOUNT_ID:?AWS_ACCOUNT_ID is required}" +: "${ACTION:?ACTION is required}" + +echo "Running app pre.sh" +echo "ENVIRONMENT=$ENVIRONMENT" +echo "ACTION=$ACTION" +echo "PROJECT=$PROJECT" +echo "COMPONENT=$COMPONENT" +echo "AWS_REGION=$REGION" +echo "AWS_ACCOUNT_ID=$AWS_ACCOUNT_ID" + +# Calculate container image prefix from PROJECT, ENVIRONMENT, COMPONENT +CONTAINER_IMAGE_PREFIX="${PROJECT}-${ENVIRONMENT}-${COMPONENT}" +echo "CONTAINER_IMAGE_PREFIX: ${CONTAINER_IMAGE_PREFIX}" + +# Translate ACTION to PUBLISH_CONTAINER_IMAGE (build) +if [ "${ACTION}" = "plan" ]; then + PUBLISH_CONTAINER_IMAGE="false" +else + PUBLISH_CONTAINER_IMAGE="true" +fi + +# Helper function for error handling +run_or_fail() { + "$@" + if [ $? -ne 0 ]; then + echo "$* failed!" >&2 + exit 1 + fi +} + +# Switch to repo root +pushd "$(git rev-parse --show-toplevel)" || exit 1 + +# Calculate git-based version suffix +SHORT_SHA="$(git rev-parse --short HEAD)" +GIT_TAG="$(git describe --tags --exact-match 2>/dev/null || true)" + +if [ -n "${GIT_TAG}" ]; then + RELEASE_VERSION="${GIT_TAG#v}" + CONTAINER_IMAGE_SUFFIX="release-${RELEASE_VERSION}-${SHORT_SHA}" + echo "On tag: $GIT_TAG, image suffix: ${CONTAINER_IMAGE_SUFFIX}" +else + CONTAINER_IMAGE_SUFFIX="sha-${SHORT_SHA}" + echo "Not on a tag, image suffix: ${CONTAINER_IMAGE_SUFFIX}" +fi + +# Export for Terraform +export TF_VAR_container_image_tag_suffix="${CONTAINER_IMAGE_SUFFIX}" + +run_or_fail pnpm install --frozen-lockfile +run_or_fail pnpm -r run --if-present generate-dependencies +run_or_fail pnpm -r run --if-present build:archive +run_or_fail env \ + CONTAINER_IMAGE_PREFIX="${CONTAINER_IMAGE_PREFIX}" \ + CONTAINER_IMAGE_SUFFIX="${CONTAINER_IMAGE_SUFFIX}" \ + AWS_ACCOUNT_ID="${AWS_ACCOUNT_ID}" \ + AWS_REGION="${REGION}" \ + PUBLISH_CONTAINER_IMAGE="${PUBLISH_CONTAINER_IMAGE}" \ + pnpm -r run --if-present build:container + +popd || exit 1 # Return to working directory diff --git a/infrastructure/terraform/components/callback-clients/variables.tf b/infrastructure/terraform/components/callback-clients/variables.tf new file mode 100644 index 00000000..51c06517 --- /dev/null +++ b/infrastructure/terraform/components/callback-clients/variables.tf @@ -0,0 +1,65 @@ +## +# Basic Required Variables for tfscaffold Components +## + +variable "project" { + type = string + description = "The name of the tfscaffold project" +} + +variable "environment" { + type = string + description = "The name of the tfscaffold environment" +} + +variable "aws_account_id" { + type = string + description = "The AWS Account ID (numeric)" +} + +variable "region" { + type = string + description = "The AWS Region" +} + +variable "group" { + type = string + description = "The group variables are being inherited from (often synonmous with account short-name)" +} + +## +# tfscaffold variables specific to this component +## + +# This is the only primary variable to have its value defined as +# a default within its declaration in this file, because the variables +# purpose is as an identifier unique to this component, rather +# then to the environment from where all other variables come. + +variable "default_tags" { + type = map(string) + description = "A map of default tags to apply to all taggable resources within the component" + default = {} +} + +## +# Variables specific to the component +## + +variable "log_retention_in_days" { + type = number + description = "The retention period in days for the Cloudwatch Logs events to be retained, default of 0 is indefinite" + default = 0 +} + +variable "force_lambda_code_deploy" { + type = bool + description = "If the lambda package in s3 has the same commit id tag as the terraform build branch, the lambda will not update automatically. Set to True if making changes to Lambda code from on the same commit for example during development" + default = false +} + +variable "parent_callbacks_environment" { + type = string + description = "The name of the environment which deployed the parent Amplify resource. Used to identify the appropriate state file." + default = "main" +} diff --git a/infrastructure/terraform/components/callbacks/.tool-versions b/infrastructure/terraform/components/callbacks/.tool-versions index 3dd74c72..52428ded 100644 --- a/infrastructure/terraform/components/callbacks/.tool-versions +++ b/infrastructure/terraform/components/callbacks/.tool-versions @@ -1 +1 @@ -terraform 1.10.1 +terraform 1.14.3 diff --git a/infrastructure/terraform/components/callbacks/README.md b/infrastructure/terraform/components/callbacks/README.md index b1587725..d3b9949c 100644 --- a/infrastructure/terraform/components/callbacks/README.md +++ b/infrastructure/terraform/components/callbacks/README.md @@ -15,7 +15,6 @@ |------|-------------|------|---------|:--------:| | [applications\_map\_parameter\_name](#input\_applications\_map\_parameter\_name) | SSM Parameter Store path for the clientId-to-applicationData map, where applicationData is currently only the applicationId | `string` | `null` | no | | [aws\_account\_id](#input\_aws\_account\_id) | The AWS Account ID (numeric) | `string` | n/a | yes | -| [component](#input\_component) | The variable encapsulating the name of this component | `string` | `"callbacks"` | no | | [default\_tags](#input\_default\_tags) | A map of default tags to apply to all taggable resources within the component | `map(string)` | `{}` | no | | [deploy\_mock\_clients](#input\_deploy\_mock\_clients) | Flag to deploy mock webhook lambda for integration testing (test/dev environments only) | `bool` | `false` | no | | [enable\_event\_anomaly\_detection](#input\_enable\_event\_anomaly\_detection) | Enable CloudWatch anomaly detection alarm for inbound event queue message reception | `bool` | `true` | no | @@ -55,6 +54,7 @@ | Name | Description | |------|-------------| | [deployment](#output\_deployment) | Deployment details used for post-deployment scripts | +| [eventbus\_name](#output\_eventbus\_name) | Name of the EventBridge event bus for callback events | | [mock\_webhook\_lambda\_log\_group\_name](#output\_mock\_webhook\_lambda\_log\_group\_name) | CloudWatch log group name for mock webhook lambda (for integration test queries) | diff --git a/infrastructure/terraform/components/callbacks/locals.tf b/infrastructure/terraform/components/callbacks/locals.tf index f4707154..dff65db0 100644 --- a/infrastructure/terraform/components/callbacks/locals.tf +++ b/infrastructure/terraform/components/callbacks/locals.tf @@ -62,5 +62,5 @@ locals { } ]...) - applications_map_parameter_name = coalesce(var.applications_map_parameter_name, "/${var.project}/${var.environment}/${var.component}/applications-map") + applications_map_parameter_name = coalesce(var.applications_map_parameter_name, "/${var.project}/${var.environment}/${local.component}/applications-map") } diff --git a/infrastructure/terraform/components/callbacks/locals_tfscaffold.tf b/infrastructure/terraform/components/callbacks/locals_tfscaffold.tf index b7cf3217..4d68787a 100644 --- a/infrastructure/terraform/components/callbacks/locals_tfscaffold.tf +++ b/infrastructure/terraform/components/callbacks/locals_tfscaffold.tf @@ -1,4 +1,6 @@ locals { + component = "cb" + terraform_state_bucket = format( "%s-tfscaffold-%s-%s", var.project, @@ -11,7 +13,7 @@ locals { "%s-%s-%s", var.project, var.environment, - var.component, + local.component, ), "_", "", @@ -25,7 +27,7 @@ locals { var.aws_account_id, var.region, var.environment, - var.component, + local.component, ), "_", "", @@ -36,7 +38,7 @@ locals { { Project = var.project Environment = var.environment - Component = var.component + Component = local.component Group = var.group Name = local.csi }, diff --git a/infrastructure/terraform/components/callbacks/module_client_destination.tf b/infrastructure/terraform/components/callbacks/module_client_destination.tf index 21800e94..7be7545e 100644 --- a/infrastructure/terraform/components/callbacks/module_client_destination.tf +++ b/infrastructure/terraform/components/callbacks/module_client_destination.tf @@ -4,7 +4,7 @@ module "client_destination" { project = var.project aws_account_id = var.aws_account_id region = var.region - component = var.component + component = local.component environment = var.environment client_bus_name = aws_cloudwatch_event_bus.main.name diff --git a/infrastructure/terraform/components/callbacks/module_kms.tf b/infrastructure/terraform/components/callbacks/module_kms.tf index 327b5641..117a0106 100644 --- a/infrastructure/terraform/components/callbacks/module_kms.tf +++ b/infrastructure/terraform/components/callbacks/module_kms.tf @@ -2,7 +2,7 @@ module "kms" { source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.0.7/terraform-kms.zip" aws_account_id = var.aws_account_id - component = var.component + component = local.component environment = var.environment project = var.project region = var.region diff --git a/infrastructure/terraform/components/callbacks/module_mock_webhook_lambda.tf b/infrastructure/terraform/components/callbacks/module_mock_webhook_lambda.tf index b951351e..9d5ac0bd 100644 --- a/infrastructure/terraform/components/callbacks/module_mock_webhook_lambda.tf +++ b/infrastructure/terraform/components/callbacks/module_mock_webhook_lambda.tf @@ -6,7 +6,7 @@ module "mock_webhook_lambda" { description = "Mock webhook endpoint for integration testing - logs received callbacks to CloudWatch" aws_account_id = var.aws_account_id - component = var.component + component = local.component environment = var.environment project = var.project region = var.region diff --git a/infrastructure/terraform/components/callbacks/module_sqs_inbound_event.tf b/infrastructure/terraform/components/callbacks/module_sqs_inbound_event.tf index 2e3080fe..2a15e357 100644 --- a/infrastructure/terraform/components/callbacks/module_sqs_inbound_event.tf +++ b/infrastructure/terraform/components/callbacks/module_sqs_inbound_event.tf @@ -2,7 +2,7 @@ module "sqs_inbound_event" { source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.0.7/terraform-sqs.zip" aws_account_id = var.aws_account_id - component = var.component + component = local.component environment = var.environment project = var.project region = var.region @@ -33,7 +33,7 @@ data "aws_iam_policy_document" "sqs_inbound_event" { ] resources = [ - "arn:aws:sqs:${var.region}:${var.aws_account_id}:${var.project}-${var.environment}-${var.component}-inbound-event-queue" + "arn:aws:sqs:${var.region}:${var.aws_account_id}:${var.project}-${var.environment}-${local.component}-inbound-event-queue" ] condition { diff --git a/infrastructure/terraform/components/callbacks/module_transform_filter_lambda.tf b/infrastructure/terraform/components/callbacks/module_transform_filter_lambda.tf index fb1313f8..e6c0f20e 100644 --- a/infrastructure/terraform/components/callbacks/module_transform_filter_lambda.tf +++ b/infrastructure/terraform/components/callbacks/module_transform_filter_lambda.tf @@ -5,7 +5,7 @@ module "client_transform_filter_lambda" { description = "Lambda function that transforms and filters events coming to through the eventpipe" aws_account_id = var.aws_account_id - component = var.component + component = local.component environment = var.environment project = var.project region = var.region diff --git a/infrastructure/terraform/components/callbacks/outputs.tf b/infrastructure/terraform/components/callbacks/outputs.tf index 1ca00df8..88cbcb59 100644 --- a/infrastructure/terraform/components/callbacks/outputs.tf +++ b/infrastructure/terraform/components/callbacks/outputs.tf @@ -10,10 +10,23 @@ output "deployment" { project = var.project environment = var.environment group = var.group - component = var.component + component = local.component } } +## +# EventBridge Event Bus Outputs +## + +output "eventbus_name" { + description = "Name of the EventBridge event bus for callback events" + value = { + name = aws_cloudwatch_event_bus.main.name + arn = aws_cloudwatch_event_bus.main.arn + } +} + + ## # Mock Webhook Lambda Outputs (test/dev environments only). ## diff --git a/infrastructure/terraform/components/callbacks/s3_bucket_client_config.tf b/infrastructure/terraform/components/callbacks/s3_bucket_client_config.tf index 8bf25c83..dabc95d1 100644 --- a/infrastructure/terraform/components/callbacks/s3_bucket_client_config.tf +++ b/infrastructure/terraform/components/callbacks/s3_bucket_client_config.tf @@ -17,7 +17,7 @@ module "client_config_bucket" { name = "subscription-config" aws_account_id = var.aws_account_id - component = var.component + component = local.component environment = var.environment project = var.project region = var.region diff --git a/infrastructure/terraform/components/callbacks/variables.tf b/infrastructure/terraform/components/callbacks/variables.tf index 74a72d24..59b858bc 100644 --- a/infrastructure/terraform/components/callbacks/variables.tf +++ b/infrastructure/terraform/components/callbacks/variables.tf @@ -35,11 +35,7 @@ variable "group" { # a default within its declaration in this file, because the variables # purpose is as an identifier unique to this component, rather # then to the environment from where all other variables come. -variable "component" { - type = string - description = "The variable encapsulating the name of this component" - default = "callbacks" -} + variable "default_tags" { type = map(string) From 37f96aba5807354f35dd8bcc1460a892d821d5dd Mon Sep 17 00:00:00 2001 From: aidenvaines-cgi Date: Thu, 30 Apr 2026 15:21:15 +0100 Subject: [PATCH 2/2] CCM-16073 ComponentShuffle Co-authored-by: Copilot --- .../callback-clients/.tool-versions | 1 - .../callback-clients/locals_remote_state.tf | 21 ----- .../callback-clients/locals_tfscaffold.tf | 46 ----------- .../components/callback-clients/outputs.tf | 1 - .../callback-clients/pre.sh.disabled | 81 ------------------- .../terraform/components/callbacks/README.md | 2 +- .../callbacks/module_callback_clients.tf | 22 +++++ .../terraform/components/callbacks/outputs.tf | 13 --- .../callback-clients/README.md | 12 ++- .../cloudwatch_event_rule_main.tf} | 4 +- .../modules/callback-clients/locals.tf | 13 +++ .../modules/callback-clients/outputs.tf | 9 +++ .../callback-clients/variables.tf | 40 ++++----- .../terraform/modules/clients/README.md | 19 ----- 14 files changed, 70 insertions(+), 214 deletions(-) delete mode 100644 infrastructure/terraform/components/callback-clients/.tool-versions delete mode 100644 infrastructure/terraform/components/callback-clients/locals_remote_state.tf delete mode 100644 infrastructure/terraform/components/callback-clients/locals_tfscaffold.tf delete mode 100644 infrastructure/terraform/components/callback-clients/outputs.tf delete mode 100755 infrastructure/terraform/components/callback-clients/pre.sh.disabled create mode 100644 infrastructure/terraform/components/callbacks/module_callback_clients.tf rename infrastructure/terraform/{components => modules}/callback-clients/README.md (63%) rename infrastructure/terraform/{components/callback-clients/cloudwatch_event_rule.tf => modules/callback-clients/cloudwatch_event_rule_main.tf} (71%) create mode 100644 infrastructure/terraform/modules/callback-clients/locals.tf create mode 100644 infrastructure/terraform/modules/callback-clients/outputs.tf rename infrastructure/terraform/{components => modules}/callback-clients/variables.tf (54%) delete mode 100644 infrastructure/terraform/modules/clients/README.md diff --git a/infrastructure/terraform/components/callback-clients/.tool-versions b/infrastructure/terraform/components/callback-clients/.tool-versions deleted file mode 100644 index 52428ded..00000000 --- a/infrastructure/terraform/components/callback-clients/.tool-versions +++ /dev/null @@ -1 +0,0 @@ -terraform 1.14.3 diff --git a/infrastructure/terraform/components/callback-clients/locals_remote_state.tf b/infrastructure/terraform/components/callback-clients/locals_remote_state.tf deleted file mode 100644 index bc81cbf4..00000000 --- a/infrastructure/terraform/components/callback-clients/locals_remote_state.tf +++ /dev/null @@ -1,21 +0,0 @@ -locals { - callbacks = data.terraform_remote_state.callbacks.outputs -} - -data "terraform_remote_state" "callbacks" { - backend = "s3" - - config = { - bucket = local.terraform_state_bucket - - key = format( - "%s/%s/%s/%s/callbacks.tfstate", - var.project, - var.aws_account_id, - "eu-west-2", - var.parent_callbacks_environment - ) - - region = "eu-west-2" - } -} diff --git a/infrastructure/terraform/components/callback-clients/locals_tfscaffold.tf b/infrastructure/terraform/components/callback-clients/locals_tfscaffold.tf deleted file mode 100644 index 5c28416c..00000000 --- a/infrastructure/terraform/components/callback-clients/locals_tfscaffold.tf +++ /dev/null @@ -1,46 +0,0 @@ -locals { - component = "cbc" - - terraform_state_bucket = format( - "%s-tfscaffold-%s-%s", - var.project, - var.aws_account_id, - var.region, - ) - - csi = replace( - format( - "%s-%s-%s", - var.project, - var.environment, - local.component, - ), - "_", - "", - ) - - # CSI for use in resources with a global namespace, i.e. S3 Buckets - csi_global = replace( - format( - "%s-%s-%s-%s-%s", - var.project, - var.aws_account_id, - var.region, - var.environment, - local.component, - ), - "_", - "", - ) - - default_tags = merge( - var.default_tags, - { - Project = var.project - Environment = var.environment - Component = local.component - Group = var.group - Name = local.csi - }, - ) -} diff --git a/infrastructure/terraform/components/callback-clients/outputs.tf b/infrastructure/terraform/components/callback-clients/outputs.tf deleted file mode 100644 index 9dcc2f39..00000000 --- a/infrastructure/terraform/components/callback-clients/outputs.tf +++ /dev/null @@ -1 +0,0 @@ -# Define the outputs for the component. The outputs may well be referenced by other component in the same or different environments using terraform_remote_state data sources... diff --git a/infrastructure/terraform/components/callback-clients/pre.sh.disabled b/infrastructure/terraform/components/callback-clients/pre.sh.disabled deleted file mode 100755 index f34040cf..00000000 --- a/infrastructure/terraform/components/callback-clients/pre.sh.disabled +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash - -## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## -## This script is currently disabled (renamed to pre.sh.disabled) as it is only needed for -## Terraform components that need build and publish container images or lambda packageses. -## -## It is left in place for reference and future use when adding new components that require this functionality. -## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## - - -# This script is run before Terraform executable commands. -# It ensures all Node.js dependencies are installed, generates any required dependencies, -# and builds all Lambda functions in the workspace before Terraform provisions infrastructure. -# pre.sh runs in the same shell as terraform.sh, not in a subshell - -: "${PROJECT:?PROJECT is required}" -: "${REGION:?REGION is required}" -: "${COMPONENT:?COMPONENT is required}" -: "${ENVIRONMENT:?ENVIRONMENT is required}" -: "${AWS_ACCOUNT_ID:?AWS_ACCOUNT_ID is required}" -: "${ACTION:?ACTION is required}" - -echo "Running app pre.sh" -echo "ENVIRONMENT=$ENVIRONMENT" -echo "ACTION=$ACTION" -echo "PROJECT=$PROJECT" -echo "COMPONENT=$COMPONENT" -echo "AWS_REGION=$REGION" -echo "AWS_ACCOUNT_ID=$AWS_ACCOUNT_ID" - -# Calculate container image prefix from PROJECT, ENVIRONMENT, COMPONENT -CONTAINER_IMAGE_PREFIX="${PROJECT}-${ENVIRONMENT}-${COMPONENT}" -echo "CONTAINER_IMAGE_PREFIX: ${CONTAINER_IMAGE_PREFIX}" - -# Translate ACTION to PUBLISH_CONTAINER_IMAGE (build) -if [ "${ACTION}" = "plan" ]; then - PUBLISH_CONTAINER_IMAGE="false" -else - PUBLISH_CONTAINER_IMAGE="true" -fi - -# Helper function for error handling -run_or_fail() { - "$@" - if [ $? -ne 0 ]; then - echo "$* failed!" >&2 - exit 1 - fi -} - -# Switch to repo root -pushd "$(git rev-parse --show-toplevel)" || exit 1 - -# Calculate git-based version suffix -SHORT_SHA="$(git rev-parse --short HEAD)" -GIT_TAG="$(git describe --tags --exact-match 2>/dev/null || true)" - -if [ -n "${GIT_TAG}" ]; then - RELEASE_VERSION="${GIT_TAG#v}" - CONTAINER_IMAGE_SUFFIX="release-${RELEASE_VERSION}-${SHORT_SHA}" - echo "On tag: $GIT_TAG, image suffix: ${CONTAINER_IMAGE_SUFFIX}" -else - CONTAINER_IMAGE_SUFFIX="sha-${SHORT_SHA}" - echo "Not on a tag, image suffix: ${CONTAINER_IMAGE_SUFFIX}" -fi - -# Export for Terraform -export TF_VAR_container_image_tag_suffix="${CONTAINER_IMAGE_SUFFIX}" - -run_or_fail pnpm install --frozen-lockfile -run_or_fail pnpm -r run --if-present generate-dependencies -run_or_fail pnpm -r run --if-present build:archive -run_or_fail env \ - CONTAINER_IMAGE_PREFIX="${CONTAINER_IMAGE_PREFIX}" \ - CONTAINER_IMAGE_SUFFIX="${CONTAINER_IMAGE_SUFFIX}" \ - AWS_ACCOUNT_ID="${AWS_ACCOUNT_ID}" \ - AWS_REGION="${REGION}" \ - PUBLISH_CONTAINER_IMAGE="${PUBLISH_CONTAINER_IMAGE}" \ - pnpm -r run --if-present build:container - -popd || exit 1 # Return to working directory diff --git a/infrastructure/terraform/components/callbacks/README.md b/infrastructure/terraform/components/callbacks/README.md index d3b9949c..ad7f496e 100644 --- a/infrastructure/terraform/components/callbacks/README.md +++ b/infrastructure/terraform/components/callbacks/README.md @@ -43,6 +43,7 @@ | Name | Source | Version | |------|--------|---------| +| [callback\_clients](#module\_callback\_clients) | ../../modules/callback-clients | n/a | | [client\_config\_bucket](#module\_client\_config\_bucket) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.0.7/terraform-s3bucket.zip | n/a | | [client\_destination](#module\_client\_destination) | ../../modules/client-destination | n/a | | [client\_transform\_filter\_lambda](#module\_client\_transform\_filter\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.0.7/terraform-lambda.zip | n/a | @@ -54,7 +55,6 @@ | Name | Description | |------|-------------| | [deployment](#output\_deployment) | Deployment details used for post-deployment scripts | -| [eventbus\_name](#output\_eventbus\_name) | Name of the EventBridge event bus for callback events | | [mock\_webhook\_lambda\_log\_group\_name](#output\_mock\_webhook\_lambda\_log\_group\_name) | CloudWatch log group name for mock webhook lambda (for integration test queries) | diff --git a/infrastructure/terraform/components/callbacks/module_callback_clients.tf b/infrastructure/terraform/components/callbacks/module_callback_clients.tf new file mode 100644 index 00000000..d0f83011 --- /dev/null +++ b/infrastructure/terraform/components/callbacks/module_callback_clients.tf @@ -0,0 +1,22 @@ +locals { + clients = toset(["alpha", "beta", "gamma"]) +} + +module "callback_clients" { + source = "../../modules/callback-clients" + + for_each = local.clients + + project = var.project + aws_account_id = var.aws_account_id + region = var.region + component = local.component + client_id = each.key + environment = var.environment + client_bus_name = aws_cloudwatch_event_bus.main.name + + kms_key_arn = module.kms.key_arn + + log_retention_in_days = var.log_retention_in_days + force_lambda_code_deploy = var.force_lambda_code_deploy +} diff --git a/infrastructure/terraform/components/callbacks/outputs.tf b/infrastructure/terraform/components/callbacks/outputs.tf index 88cbcb59..457a37de 100644 --- a/infrastructure/terraform/components/callbacks/outputs.tf +++ b/infrastructure/terraform/components/callbacks/outputs.tf @@ -14,19 +14,6 @@ output "deployment" { } } -## -# EventBridge Event Bus Outputs -## - -output "eventbus_name" { - description = "Name of the EventBridge event bus for callback events" - value = { - name = aws_cloudwatch_event_bus.main.name - arn = aws_cloudwatch_event_bus.main.arn - } -} - - ## # Mock Webhook Lambda Outputs (test/dev environments only). ## diff --git a/infrastructure/terraform/components/callback-clients/README.md b/infrastructure/terraform/modules/callback-clients/README.md similarity index 63% rename from infrastructure/terraform/components/callback-clients/README.md rename to infrastructure/terraform/modules/callback-clients/README.md index ebb2ba89..99753c6c 100644 --- a/infrastructure/terraform/components/callback-clients/README.md +++ b/infrastructure/terraform/modules/callback-clients/README.md @@ -10,12 +10,13 @@ No requirements. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [aws\_account\_id](#input\_aws\_account\_id) | The AWS Account ID (numeric) | `string` | n/a | yes | -| [default\_tags](#input\_default\_tags) | A map of default tags to apply to all taggable resources within the component | `map(string)` | `{}` | no | +| [client\_bus\_name](#input\_client\_bus\_name) | The name of the event bus to create rules on | `string` | n/a | yes | +| [client\_id](#input\_client\_id) | Unique identifier for the client | `string` | n/a | yes | +| [component](#input\_component) | Component name | `string` | n/a | yes | | [environment](#input\_environment) | The name of the tfscaffold environment | `string` | n/a | yes | | [force\_lambda\_code\_deploy](#input\_force\_lambda\_code\_deploy) | If the lambda package in s3 has the same commit id tag as the terraform build branch, the lambda will not update automatically. Set to True if making changes to Lambda code from on the same commit for example during development | `bool` | `false` | no | -| [group](#input\_group) | The group variables are being inherited from (often synonmous with account short-name) | `string` | n/a | yes | +| [kms\_key\_arn](#input\_kms\_key\_arn) | KMS Key ARN | `string` | n/a | yes | | [log\_retention\_in\_days](#input\_log\_retention\_in\_days) | The retention period in days for the Cloudwatch Logs events to be retained, default of 0 is indefinite | `number` | `0` | no | -| [parent\_callbacks\_environment](#input\_parent\_callbacks\_environment) | The name of the environment which deployed the parent Amplify resource. Used to identify the appropriate state file. | `string` | `"main"` | no | | [project](#input\_project) | The name of the tfscaffold project | `string` | n/a | yes | | [region](#input\_region) | The AWS Region | `string` | n/a | yes | ## Modules @@ -23,7 +24,10 @@ No requirements. No modules. ## Outputs -No outputs. +| Name | Description | +|------|-------------| +| [callback\_rule\_arn](#output\_callback\_rule\_arn) | ARN of the callback event rule | +| [callback\_rule\_name](#output\_callback\_rule\_name) | Name of the callback event rule | diff --git a/infrastructure/terraform/components/callback-clients/cloudwatch_event_rule.tf b/infrastructure/terraform/modules/callback-clients/cloudwatch_event_rule_main.tf similarity index 71% rename from infrastructure/terraform/components/callback-clients/cloudwatch_event_rule.tf rename to infrastructure/terraform/modules/callback-clients/cloudwatch_event_rule_main.tf index 6d36322a..88f1f3cb 100644 --- a/infrastructure/terraform/components/callback-clients/cloudwatch_event_rule.tf +++ b/infrastructure/terraform/modules/callback-clients/cloudwatch_event_rule_main.tf @@ -1,6 +1,6 @@ resource "aws_cloudwatch_event_rule" "main" { name = "${local.csi}-callback-rule" - event_bus_name = local.callbacks.eventbus_name.name # Reference the event bus from callbacks component + event_bus_name = var.client_bus_name event_pattern = jsonencode({ source = [{ prefix = "" }] # Your event pattern here this is effectively "*" @@ -9,7 +9,7 @@ resource "aws_cloudwatch_event_rule" "main" { # resource "aws_cloudwatch_event_target" "main" { # rule = aws_cloudwatch_event_rule.main.name -# event_bus_name = local.callbacks.eventbus_name.name # Same event bus reference +# event_bus_name = var.client_bus_name # target_id = "callback-target" # arn = # Your target ARN (Lambda, SNS, etc.) # # Additional target configuration... diff --git a/infrastructure/terraform/modules/callback-clients/locals.tf b/infrastructure/terraform/modules/callback-clients/locals.tf new file mode 100644 index 00000000..7b19292b --- /dev/null +++ b/infrastructure/terraform/modules/callback-clients/locals.tf @@ -0,0 +1,13 @@ +locals { + csi = replace( + format( + "%s-%s-%s-%s", + var.project, + var.environment, + var.component, + var.client_id, + ), + "_", + "", + ) +} diff --git a/infrastructure/terraform/modules/callback-clients/outputs.tf b/infrastructure/terraform/modules/callback-clients/outputs.tf new file mode 100644 index 00000000..1095a2e4 --- /dev/null +++ b/infrastructure/terraform/modules/callback-clients/outputs.tf @@ -0,0 +1,9 @@ +output "callback_rule_arn" { + description = "ARN of the callback event rule" + value = aws_cloudwatch_event_rule.main.arn +} + +output "callback_rule_name" { + description = "Name of the callback event rule" + value = aws_cloudwatch_event_rule.main.name +} diff --git a/infrastructure/terraform/components/callback-clients/variables.tf b/infrastructure/terraform/modules/callback-clients/variables.tf similarity index 54% rename from infrastructure/terraform/components/callback-clients/variables.tf rename to infrastructure/terraform/modules/callback-clients/variables.tf index 51c06517..70c8d47f 100644 --- a/infrastructure/terraform/components/callback-clients/variables.tf +++ b/infrastructure/terraform/modules/callback-clients/variables.tf @@ -12,6 +12,16 @@ variable "environment" { description = "The name of the tfscaffold environment" } +variable "component" { + type = string + description = "Component name" +} + +variable "client_id" { + type = string + description = "Unique identifier for the client" +} + variable "aws_account_id" { type = string description = "The AWS Account ID (numeric)" @@ -22,30 +32,16 @@ variable "region" { description = "The AWS Region" } -variable "group" { +variable "kms_key_arn" { type = string - description = "The group variables are being inherited from (often synonmous with account short-name)" + description = "KMS Key ARN" } -## -# tfscaffold variables specific to this component -## - -# This is the only primary variable to have its value defined as -# a default within its declaration in this file, because the variables -# purpose is as an identifier unique to this component, rather -# then to the environment from where all other variables come. - -variable "default_tags" { - type = map(string) - description = "A map of default tags to apply to all taggable resources within the component" - default = {} +variable "client_bus_name" { + type = string + description = "The name of the event bus to create rules on" } -## -# Variables specific to the component -## - variable "log_retention_in_days" { type = number description = "The retention period in days for the Cloudwatch Logs events to be retained, default of 0 is indefinite" @@ -57,9 +53,3 @@ variable "force_lambda_code_deploy" { description = "If the lambda package in s3 has the same commit id tag as the terraform build branch, the lambda will not update automatically. Set to True if making changes to Lambda code from on the same commit for example during development" default = false } - -variable "parent_callbacks_environment" { - type = string - description = "The name of the environment which deployed the parent Amplify resource. Used to identify the appropriate state file." - default = "main" -} diff --git a/infrastructure/terraform/modules/clients/README.md b/infrastructure/terraform/modules/clients/README.md deleted file mode 100644 index df8c1f5c..00000000 --- a/infrastructure/terraform/modules/clients/README.md +++ /dev/null @@ -1,19 +0,0 @@ - - - - -## Requirements - -No requirements. -## Inputs - -No inputs. -## Modules - -No modules. -## Outputs - -No outputs. - - -