From 3cc7a03fea8e39eee05a4ac2a4b55f8471ffa25f Mon Sep 17 00:00:00 2001 From: Mark Slowey Date: Thu, 3 Sep 2026 14:13:48 +0100 Subject: [PATCH 1/5] add DL variable feed for pdf perms --- infrastructure/terraform/components/api/README.md | 2 ++ infrastructure/terraform/components/api/locals.tf | 4 ++++ .../components/api/module_lambda_get_letter_data.tf | 4 +++- infrastructure/terraform/components/api/variables.tf | 11 +++++++++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/infrastructure/terraform/components/api/README.md b/infrastructure/terraform/components/api/README.md index b269caeb3..e11c097f4 100644 --- a/infrastructure/terraform/components/api/README.md +++ b/infrastructure/terraform/components/api/README.md @@ -19,6 +19,8 @@ No requirements. | [csoc\_log\_forwarding](#input\_csoc\_log\_forwarding) | Enable forwarding of API Gateway logs to CSOC | `bool` | `true` | no | | [default\_tags](#input\_default\_tags) | A map of default tags to apply to all taggable resources within the component | `map(string)` | `{}` | no | | [deploy\_supplier\_mock\_scheduler](#input\_deploy\_supplier\_mock\_scheduler) | Deploy EventBridge Scheduler trigger for supplier mock lambda | `bool` | `false` | no | +| [digital\_letters\_account\_id](#input\_digital\_letters\_account\_id) | AWS Account ID for Digital Letters | `string` | `"000000000000"` | no | +| [digital\_letters\_environment](#input\_digital\_letters\_environment) | Environment of Digital Letters | `string` | `"main"` | no | | [disable\_gateway\_execute\_endpoint](#input\_disable\_gateway\_execute\_endpoint) | Disable the execution endpoint for the API Gateway | `bool` | `true` | no | | [download\_url\_ttl\_seconds](#input\_download\_url\_ttl\_seconds) | TTL in seconds for generated download URLs | `number` | `60` | no | | [enable\_alarms](#input\_enable\_alarms) | Enable CloudWatch alarms for this deployed environment | `bool` | `true` | no | diff --git a/infrastructure/terraform/components/api/locals.tf b/infrastructure/terraform/components/api/locals.tf index da1e61630..5f7f0e887 100644 --- a/infrastructure/terraform/components/api/locals.tf +++ b/infrastructure/terraform/components/api/locals.tf @@ -40,6 +40,10 @@ locals { core_pdf_bucket_arn = "arn:aws:s3:::comms-${var.core_account_id}-eu-west-2-${var.core_environment}-api-stg-pdf-pipeline" core_s3_kms_key_alias_name = "alias/comms-${var.core_environment}-api-s3" + digital_letters_pdf_bucket_arn = "arn:aws:s3:::nhs-${var.digital_letters_account_id}-eu-west-2-${var.digital_letters_environment}-dl-file-safe" + digital_letters_s3_kms_key_alias_name = "alias/nhs-${var.digital_letters_environment}-dl" + + event_cache_bucket_name = lookup(module.eventpub.s3_bucket_event_cache, "bucket", null) eventsub_event_cache_bucket_name = lookup(module.eventsub.s3_bucket_event_cache, "bucket", null) diff --git a/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf b/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf index 1129c6040..daac50d23 100644 --- a/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf +++ b/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf @@ -74,7 +74,8 @@ data "aws_iam_policy_document" "get_letter_data_lambda" { ] resources = [ module.s3bucket_test_letters.arn, - local.core_pdf_bucket_arn + local.core_pdf_bucket_arn, + local.digital_letters_pdf_bucket_arn, ] } @@ -87,6 +88,7 @@ data "aws_iam_policy_document" "get_letter_data_lambda" { resources = [ "${module.s3bucket_test_letters.arn}/*", "${local.core_pdf_bucket_arn}/*", + "${local.digital_letters_pdf_bucket_arn}/*", ] } diff --git a/infrastructure/terraform/components/api/variables.tf b/infrastructure/terraform/components/api/variables.tf index 3d16b8465..bb85cbe3f 100644 --- a/infrastructure/terraform/components/api/variables.tf +++ b/infrastructure/terraform/components/api/variables.tf @@ -181,7 +181,18 @@ variable "core_environment" { type = string description = "Environment of Core" default = "prod" +} +variable "digital_letters_account_id" { + type = string + description = "AWS Account ID for Digital Letters" + default = "000000000000" +} + +variable "digital_letters_environment" { + type = string + description = "Environment of Digital Letters" + default = "main" } variable "enable_backups" { From b68a9c5c73246a0693eab7325293bba962582c0b Mon Sep 17 00:00:00 2001 From: Mark Slowey Date: Fri, 4 Sep 2026 08:55:16 +0100 Subject: [PATCH 2/5] remove unneeded put permission --- .../terraform/components/api/module_lambda_get_letter_data.tf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf b/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf index daac50d23..24ad0aafb 100644 --- a/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf +++ b/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf @@ -82,8 +82,7 @@ data "aws_iam_policy_document" "get_letter_data_lambda" { statement { sid = "S3GetObjectForPresign" actions = [ - "s3:GetObject", - "s3:PutObject", + "s3:GetObject" ] # allows 404 response instead of 403 if object missing resources = [ "${module.s3bucket_test_letters.arn}/*", From cb9a8fe5c982bc837ee651abe36ea76f860b08a5 Mon Sep 17 00:00:00 2001 From: Mark Slowey Date: Fri, 4 Sep 2026 09:00:55 +0100 Subject: [PATCH 3/5] missing KMS --- .../terraform/components/api/README.md | 6 +++--- .../api/module_lambda_get_letter_data.tf | 17 +++++++++++++++++ .../terraform/modules/alarms-ddb/README.md | 4 ++-- .../terraform/modules/alarms-lambda/README.md | 4 ++-- .../terraform/modules/alarms-sqs/README.md | 4 ++-- .../terraform/modules/eventsub/README.md | 8 ++++---- 6 files changed, 30 insertions(+), 13 deletions(-) diff --git a/infrastructure/terraform/components/api/README.md b/infrastructure/terraform/components/api/README.md index e11c097f4..b21ae6675 100644 --- a/infrastructure/terraform/components/api/README.md +++ b/infrastructure/terraform/components/api/README.md @@ -8,7 +8,7 @@ No requirements. ## Inputs | Name | Description | Type | Default | Required | -|------|-------------|------|---------|:--------:| +| ---- | ----------- | ---- | ------- | :------: | | [aws\_account\_id](#input\_aws\_account\_id) | The AWS Account ID (numeric) | `string` | n/a | yes | | [ca\_pem\_filename](#input\_ca\_pem\_filename) | Filename for the CA truststore file within the s3 bucket | `string` | `null` | no | | [commit\_id](#input\_commit\_id) | The commit to deploy. Must be in the tree for branch\_name | `string` | `"HEAD"` | no | @@ -59,7 +59,7 @@ No requirements. ## Modules | Name | Source | Version | -|------|--------|---------| +| ---- | ------ | ------- | | [amendment\_event\_transformer](#module\_amendment\_event\_transformer) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.2/terraform-lambda.zip | n/a | | [amendments\_queue](#module\_amendments\_queue) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.1.5/terraform-sqs.zip | n/a | | [authorizer\_lambda](#module\_authorizer\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.2/terraform-lambda.zip | n/a | @@ -98,7 +98,7 @@ No requirements. ## Outputs | Name | Description | -|------|-------------| +| ---- | ----------- | | [api\_urll](#output\_api\_urll) | n/a | | [deployment](#output\_deployment) | Deployment details used for post-deployment scripts | diff --git a/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf b/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf index 24ad0aafb..a60cfa4e7 100644 --- a/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf +++ b/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf @@ -107,4 +107,21 @@ data "aws_iam_policy_document" "get_letter_data_lambda" { values = [local.core_s3_kms_key_alias_name] } } + + statement { + sid = "KMSForDigitalLettersS3Access" + actions = [ + "kms:Decrypt", + "kms:GenerateDataKey", + "kms:DescribeKey" + ] + resources = [ + "arn:aws:kms:${var.region}:${var.digital_letters_account_id}:key/*" + ] + condition { + test = "ForAnyValue:StringEquals" + variable = "kms:ResourceAliases" + values = [local.digital_letters_s3_kms_key_alias_name] + } + } } diff --git a/infrastructure/terraform/modules/alarms-ddb/README.md b/infrastructure/terraform/modules/alarms-ddb/README.md index ed912741c..02ff7ca39 100644 --- a/infrastructure/terraform/modules/alarms-ddb/README.md +++ b/infrastructure/terraform/modules/alarms-ddb/README.md @@ -5,12 +5,12 @@ ## Requirements | Name | Version | -|------|---------| +| ---- | ------- | | [terraform](#requirement\_terraform) | >= 1.9.0 | ## Inputs | Name | Description | Type | Default | Required | -|------|-------------|------|---------|:--------:| +| ---- | ----------- | ---- | ------- | :------: | | [alarm\_prefix](#input\_alarm\_prefix) | n/a | `string` | n/a | yes | | [evaluation\_periods](#input\_evaluation\_periods) | n/a | `number` | `1` | no | | [period\_seconds](#input\_period\_seconds) | n/a | `number` | `60` | no | diff --git a/infrastructure/terraform/modules/alarms-lambda/README.md b/infrastructure/terraform/modules/alarms-lambda/README.md index 5b47d9195..72ed2d4f8 100644 --- a/infrastructure/terraform/modules/alarms-lambda/README.md +++ b/infrastructure/terraform/modules/alarms-lambda/README.md @@ -5,12 +5,12 @@ ## Requirements | Name | Version | -|------|---------| +| ---- | ------- | | [terraform](#requirement\_terraform) | >= 1.9.0 | ## Inputs | Name | Description | Type | Default | Required | -|------|-------------|------|---------|:--------:| +| ---- | ----------- | ---- | ------- | :------: | | [alarm\_prefix](#input\_alarm\_prefix) | n/a | `string` | n/a | yes | | [enable\_error\_log\_metric](#input\_enable\_error\_log\_metric) | n/a | `bool` | `true` | no | | [error\_log\_evaluation\_periods](#input\_error\_log\_evaluation\_periods) | n/a | `number` | `1` | no | diff --git a/infrastructure/terraform/modules/alarms-sqs/README.md b/infrastructure/terraform/modules/alarms-sqs/README.md index 1b03db985..1451950d5 100644 --- a/infrastructure/terraform/modules/alarms-sqs/README.md +++ b/infrastructure/terraform/modules/alarms-sqs/README.md @@ -5,12 +5,12 @@ ## Requirements | Name | Version | -|------|---------| +| ---- | ------- | | [terraform](#requirement\_terraform) | >= 1.9.0 | ## Inputs | Name | Description | Type | Default | Required | -|------|-------------|------|---------|:--------:| +| ---- | ----------- | ---- | ------- | :------: | | [age\_anomaly\_datapoints\_to\_alarm](#input\_age\_anomaly\_datapoints\_to\_alarm) | n/a | `number` | `3` | no | | [age\_anomaly\_evaluation\_periods](#input\_age\_anomaly\_evaluation\_periods) | n/a | `number` | `3` | no | | [age\_period\_seconds](#input\_age\_period\_seconds) | n/a | `number` | `300` | no | diff --git a/infrastructure/terraform/modules/eventsub/README.md b/infrastructure/terraform/modules/eventsub/README.md index d8e85389d..f13d96bc8 100644 --- a/infrastructure/terraform/modules/eventsub/README.md +++ b/infrastructure/terraform/modules/eventsub/README.md @@ -5,12 +5,12 @@ ## Requirements | Name | Version | -|------|---------| +| ---- | ------- | | [terraform](#requirement\_terraform) | >= 1.9.0 | ## Inputs | Name | Description | Type | Default | Required | -|------|-------------|------|---------|:--------:| +| ---- | ----------- | ---- | ------- | :------: | | [access\_logging\_bucket](#input\_access\_logging\_bucket) | Name of S3 bucket to use for access logging | `string` | `""` | no | | [aws\_account\_id](#input\_aws\_account\_id) | The AWS Account ID (numeric) | `string` | n/a | yes | | [component](#input\_component) | The name of the terraformscaffold component calling this module | `string` | n/a | yes | @@ -39,12 +39,12 @@ ## Modules | Name | Source | Version | -|------|--------|---------| +| ---- | ------ | ------- | | [s3bucket\_event\_cache](#module\_s3bucket\_event\_cache) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.0.6/terraform-s3bucket.zip | n/a | ## Outputs | Name | Description | -|------|-------------| +| ---- | ----------- | | [s3\_bucket\_event\_cache](#output\_s3\_bucket\_event\_cache) | S3 Bucket ARN and Name for event cache | | [sns\_topic](#output\_sns\_topic) | SNS Topic ARN and Name | From 6b2a52030c06aa745f1c101d502aad4c5bd9620b Mon Sep 17 00:00:00 2001 From: Mark Slowey Date: Fri, 4 Sep 2026 12:49:22 +0100 Subject: [PATCH 4/5] consolidate policy --- .../api/module_lambda_get_letter_data.tf | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf b/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf index a60cfa4e7..b4ae9b0f1 100644 --- a/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf +++ b/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf @@ -92,36 +92,20 @@ data "aws_iam_policy_document" "get_letter_data_lambda" { } statement { - sid = "KMSForCoreS3Access" - actions = [ - "kms:Decrypt", - "kms:GenerateDataKey", - "kms:DescribeKey" - ] - resources = [ - "arn:aws:kms:${var.region}:${var.core_account_id}:key/*" - ] - condition { - test = "ForAnyValue:StringEquals" - variable = "kms:ResourceAliases" - values = [local.core_s3_kms_key_alias_name] - } - } - - statement { - sid = "KMSForDigitalLettersS3Access" + sid = "KMSForS3Access" actions = [ "kms:Decrypt", "kms:GenerateDataKey", "kms:DescribeKey" ] resources = [ + "arn:aws:kms:${var.region}:${var.core_account_id}:key/*", "arn:aws:kms:${var.region}:${var.digital_letters_account_id}:key/*" ] condition { test = "ForAnyValue:StringEquals" variable = "kms:ResourceAliases" - values = [local.digital_letters_s3_kms_key_alias_name] + values = [local.core_s3_kms_key_alias_name] } } } From ebd430cdb3880e6af81836b05b5266334c4411ea Mon Sep 17 00:00:00 2001 From: Mark Slowey Date: Fri, 4 Sep 2026 12:50:07 +0100 Subject: [PATCH 5/5] undo consolidate --- .../api/module_lambda_get_letter_data.tf | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf b/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf index b4ae9b0f1..a60cfa4e7 100644 --- a/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf +++ b/infrastructure/terraform/components/api/module_lambda_get_letter_data.tf @@ -92,15 +92,14 @@ data "aws_iam_policy_document" "get_letter_data_lambda" { } statement { - sid = "KMSForS3Access" + sid = "KMSForCoreS3Access" actions = [ "kms:Decrypt", "kms:GenerateDataKey", "kms:DescribeKey" ] resources = [ - "arn:aws:kms:${var.region}:${var.core_account_id}:key/*", - "arn:aws:kms:${var.region}:${var.digital_letters_account_id}:key/*" + "arn:aws:kms:${var.region}:${var.core_account_id}:key/*" ] condition { test = "ForAnyValue:StringEquals" @@ -108,4 +107,21 @@ data "aws_iam_policy_document" "get_letter_data_lambda" { values = [local.core_s3_kms_key_alias_name] } } + + statement { + sid = "KMSForDigitalLettersS3Access" + actions = [ + "kms:Decrypt", + "kms:GenerateDataKey", + "kms:DescribeKey" + ] + resources = [ + "arn:aws:kms:${var.region}:${var.digital_letters_account_id}:key/*" + ] + condition { + test = "ForAnyValue:StringEquals" + variable = "kms:ResourceAliases" + values = [local.digital_letters_s3_kms_key_alias_name] + } + } }