From aa25315f538152921a30388da647a40298c22807 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Mon, 18 Aug 2025 16:14:57 +0100 Subject: [PATCH 01/30] CCM-11586: initial truststore --- .../terraform/components/api/README.md | 4 + .../components/api/api_gateway_domain.tf | 15 ++++ .../terraform/components/api/locals.tf | 11 +++ .../components/api/module_supplier_ssl.tf | 14 +++ .../api/s3_bucket_policy_truststore.tf | 28 ++++++ .../components/api/s3_bucket_truststore.tf | 85 +++++++++++++++++++ .../terraform/components/api/variables.tf | 26 ++++++ 7 files changed, 183 insertions(+) create mode 100644 infrastructure/terraform/components/api/module_supplier_ssl.tf create mode 100644 infrastructure/terraform/components/api/s3_bucket_policy_truststore.tf create mode 100644 infrastructure/terraform/components/api/s3_bucket_truststore.tf diff --git a/infrastructure/terraform/components/api/README.md b/infrastructure/terraform/components/api/README.md index 2d902e03..850369a0 100644 --- a/infrastructure/terraform/components/api/README.md +++ b/infrastructure/terraform/components/api/README.md @@ -12,16 +12,19 @@ No requirements. | [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` | `"supapi"` | no | | [default\_tags](#input\_default\_tags) | A map of default tags to apply to all taggable resources within the component | `map(string)` | `{}` | no | +| [enable\_backups](#input\_enable\_backups) | Enable backups | `bool` | `false` | 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 | | [kms\_deletion\_window](#input\_kms\_deletion\_window) | When a kms key is deleted, how long should it wait in the pending deletion state? | `string` | `"30"` | no | | [log\_level](#input\_log\_level) | The log level to be used in lambda functions within the component. Any log with a lower severity than the configured value will not be logged: https://docs.python.org/3/library/logging.html#levels | `string` | `"INFO"` | no | | [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 | +| [manually\_configure\_mtls\_truststore](#input\_manually\_configure\_mtls\_truststore) | Manually manage the truststore used for API Gateway mTLS (e.g. for prod environment) | `bool` | `false` | no | | [parent\_acct\_environment](#input\_parent\_acct\_environment) | Name of the environment responsible for the acct resources used, affects things like DNS zone. Useful for named dev environments | `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 | | [shared\_infra\_account\_id](#input\_shared\_infra\_account\_id) | The AWS Account ID of the shared infrastructure account | `string` | `"000000000000"` | no | +| [truststore\_s3\_bucket\_config](#input\_truststore\_s3\_bucket\_config) | Parameters for configuring the Notify Supplier API truststore bucket |
object({
kms_key_id = string
kms_key_arn = string
bucket_logs_bucket_name = string
})
|
{
"bucket_logs_bucket_name": "",
"kms_key_arn": "",
"kms_key_id": ""
}
| no | ## Modules | Name | Source | Version | @@ -31,6 +34,7 @@ No requirements. | [hello\_world](#module\_hello\_world) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda | v2.0.10 | | [kms](#module\_kms) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/kms | v2.0.10 | | [patch\_letters](#module\_patch\_letters) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda | v2.0.10 | +| [supplier\_ssl](#module\_supplier\_ssl) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/ssl | v2.0.17 | ## Outputs | Name | Description | diff --git a/infrastructure/terraform/components/api/api_gateway_domain.tf b/infrastructure/terraform/components/api/api_gateway_domain.tf index 27808578..3ed91d1a 100644 --- a/infrastructure/terraform/components/api/api_gateway_domain.tf +++ b/infrastructure/terraform/components/api/api_gateway_domain.tf @@ -6,4 +6,19 @@ resource "aws_api_gateway_domain_name" "main" { endpoint_configuration { types = ["REGIONAL"] } + + depends_on = [ + aws_s3_bucket.truststore + ] + + mutual_tls_authentication { + truststore_uri = "s3://${aws_s3_bucket.truststore[0].id}/${aws_s3_object.placeholder_truststore[0].id}" + truststore_version = aws_s3_object.placeholder_truststore[0].version_id + } + + lifecycle { + ignore_changes = [ + mutual_tls_authentication + ] + } } diff --git a/infrastructure/terraform/components/api/locals.tf b/infrastructure/terraform/components/api/locals.tf index 5400579d..d2b786cc 100644 --- a/infrastructure/terraform/components/api/locals.tf +++ b/infrastructure/terraform/components/api/locals.tf @@ -14,4 +14,15 @@ locals { }) destination_arn = "arn:aws:logs:${var.region}:${var.shared_infra_account_id}:destination:nhs-main-obs-firehose-logs" + + csi_s3 = replace( + format( + "%s-%s-%s-%s", + var.project, + var.aws_account_id, + var.environment + ), + "_", + "", + ) } diff --git a/infrastructure/terraform/components/api/module_supplier_ssl.tf b/infrastructure/terraform/components/api/module_supplier_ssl.tf new file mode 100644 index 00000000..6b6f264d --- /dev/null +++ b/infrastructure/terraform/components/api/module_supplier_ssl.tf @@ -0,0 +1,14 @@ +module "supplier_ssl" { + source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/ssl?ref=v2.0.17" + + count = var.manually_configure_mtls_truststore ? 0 : 1 + + aws_account_id = var.aws_account_id + default_tags = local.default_tags + component = var.component + environment = var.environment + project = var.project + region = var.region + group = var.group + subject_common_name = local.root_domain_name +} diff --git a/infrastructure/terraform/components/api/s3_bucket_policy_truststore.tf b/infrastructure/terraform/components/api/s3_bucket_policy_truststore.tf new file mode 100644 index 00000000..36ed5166 --- /dev/null +++ b/infrastructure/terraform/components/api/s3_bucket_policy_truststore.tf @@ -0,0 +1,28 @@ +resource "aws_s3_bucket_policy" "truststore" { + bucket = aws_s3_bucket.truststore[0].id + policy = data.aws_iam_policy_document.truststore[0].json +} + +data "aws_iam_policy_document" "truststore" { + statement { + effect = "Deny" + actions = ["s3:*"] + resources = [ + aws_s3_bucket.truststore[0].arn, + "${aws_s3_bucket.truststore[0].arn}/*", + ] + + principals { + type = "AWS" + identifiers = ["*"] + } + + condition { + test = "Bool" + variable = "aws:SecureTransport" + values = [ + false + ] + } + } +} diff --git a/infrastructure/terraform/components/api/s3_bucket_truststore.tf b/infrastructure/terraform/components/api/s3_bucket_truststore.tf new file mode 100644 index 00000000..9f46ce4d --- /dev/null +++ b/infrastructure/terraform/components/api/s3_bucket_truststore.tf @@ -0,0 +1,85 @@ +resource "aws_s3_bucket" "truststore" { + bucket = "${local.csi_s3}-truststore" + tags = merge(local.default_tags, { "Enable-Backup" = var.enable_backups }, { "Enable-S3-Continuous-Backup" = var.enable_backups }, { "SKIP_S3_AUDIT" = "true" }) +} + +resource "aws_s3_bucket_ownership_controls" "truststore" { + bucket = aws_s3_bucket.truststore[0].id + + rule { + object_ownership = "BucketOwnerPreferred" + } +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "truststore" { + bucket = aws_s3_bucket.truststore[0].id + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "aws:kms" + kms_master_key_id = var.truststore_s3_bucket_config.kms_key_id + } + bucket_key_enabled = true + } +} + +resource "aws_s3_bucket_versioning" "truststore" { + bucket = aws_s3_bucket.truststore[0].id + + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_s3_bucket_public_access_block" "truststore" { + depends_on = [ + aws_s3_bucket_policy.truststore + ] + + bucket = aws_s3_bucket.truststore[0].id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +resource "aws_s3_bucket_logging" "truststore" { + bucket = aws_s3_bucket.truststore[0].id + + target_bucket = var.truststore_s3_bucket_config.bucket_logs_bucket_name + target_prefix = "truststore/${aws_s3_bucket.truststore[0].bucket}/" +} + +# If Environment is to be Manually configured, need to create a placeholder truststore file for mtls +resource "aws_s3_object" "placeholder_truststore" { + count = var.manually_configure_mtls_truststore ? 1 : 0 + bucket = aws_s3_bucket.truststore[0].bucket + key = "truststore.pem" + content = tls_self_signed_cert.placeholder_cert[0].cert_pem + + depends_on = [ + aws_s3_bucket_versioning.truststore + ] + + lifecycle { + ignore_changes = [ + content + ] + } +} + +# If env is not manually configured, use the certs generated from the ssl module +# Having a duplicate resource here as lifcycle rules can't be dynamic or variable +# We don't want to ignore content in nonprod, but we do for prod as we will manually update certs and not via ssl module +resource "aws_s3_object" "placeholder_truststore_nonprod" { + count = var.manually_configure_mtls_truststore ? 0 : 1 + bucket = aws_s3_bucket.truststore[0].bucket + key = "truststore.pem" + content = module.supplier_ssl.cacert_pem + + depends_on = [ + aws_s3_bucket_versioning.truststore, + module.supplier_ssl + ] +} diff --git a/infrastructure/terraform/components/api/variables.tf b/infrastructure/terraform/components/api/variables.tf index 51b61627..39a1a395 100644 --- a/infrastructure/terraform/components/api/variables.tf +++ b/infrastructure/terraform/components/api/variables.tf @@ -86,3 +86,29 @@ variable "shared_infra_account_id" { description = "The AWS Account ID of the shared infrastructure account" default = "000000000000" } + +variable "manually_configure_mtls_truststore" { + type = bool + description = "Manually manage the truststore used for API Gateway mTLS (e.g. for prod environment)" + default = false +} + +variable "enable_backups" { + type = bool + description = "Enable backups" + default = false +} + +variable "truststore_s3_bucket_config" { + type = object({ + kms_key_id = string + kms_key_arn = string + bucket_logs_bucket_name = string + }) + description = "Parameters for configuring the Notify Supplier API truststore bucket" + default = { + bucket_logs_bucket_name = "" + kms_key_arn = "" + kms_key_id = "" + } +} From 9bca7cb0802d33a675c00a576af542ea8f7feea7 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Mon, 18 Aug 2025 16:19:42 +0100 Subject: [PATCH 02/30] CCM-11586: group is invalid prop --- infrastructure/terraform/components/api/module_supplier_ssl.tf | 1 - 1 file changed, 1 deletion(-) diff --git a/infrastructure/terraform/components/api/module_supplier_ssl.tf b/infrastructure/terraform/components/api/module_supplier_ssl.tf index 6b6f264d..7017a903 100644 --- a/infrastructure/terraform/components/api/module_supplier_ssl.tf +++ b/infrastructure/terraform/components/api/module_supplier_ssl.tf @@ -9,6 +9,5 @@ module "supplier_ssl" { environment = var.environment project = var.project region = var.region - group = var.group subject_common_name = local.root_domain_name } From 6e1a983635b1adf44e2d6e0a69b405269b7c6a11 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Mon, 18 Aug 2025 16:24:46 +0100 Subject: [PATCH 03/30] CCM-11586: missing name --- infrastructure/terraform/components/api/module_supplier_ssl.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/infrastructure/terraform/components/api/module_supplier_ssl.tf b/infrastructure/terraform/components/api/module_supplier_ssl.tf index 7017a903..07fa82ef 100644 --- a/infrastructure/terraform/components/api/module_supplier_ssl.tf +++ b/infrastructure/terraform/components/api/module_supplier_ssl.tf @@ -3,6 +3,7 @@ module "supplier_ssl" { count = var.manually_configure_mtls_truststore ? 0 : 1 + name = "sapi_trust" aws_account_id = var.aws_account_id default_tags = local.default_tags component = var.component From 2b3ac47a4b4ed0a15b73dd18258433d9c9be428a Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Mon, 18 Aug 2025 16:29:20 +0100 Subject: [PATCH 04/30] CCM-11586: store ref not indexed --- .../components/api/s3_bucket_truststore.tf | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/infrastructure/terraform/components/api/s3_bucket_truststore.tf b/infrastructure/terraform/components/api/s3_bucket_truststore.tf index 9f46ce4d..61a828cd 100644 --- a/infrastructure/terraform/components/api/s3_bucket_truststore.tf +++ b/infrastructure/terraform/components/api/s3_bucket_truststore.tf @@ -4,7 +4,7 @@ resource "aws_s3_bucket" "truststore" { } resource "aws_s3_bucket_ownership_controls" "truststore" { - bucket = aws_s3_bucket.truststore[0].id + bucket = aws_s3_bucket.truststore.id rule { object_ownership = "BucketOwnerPreferred" @@ -12,7 +12,7 @@ resource "aws_s3_bucket_ownership_controls" "truststore" { } resource "aws_s3_bucket_server_side_encryption_configuration" "truststore" { - bucket = aws_s3_bucket.truststore[0].id + bucket = aws_s3_bucket.truststore.id rule { apply_server_side_encryption_by_default { @@ -24,7 +24,7 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "truststore" { } resource "aws_s3_bucket_versioning" "truststore" { - bucket = aws_s3_bucket.truststore[0].id + bucket = aws_s3_bucket.truststore.id versioning_configuration { status = "Enabled" @@ -36,7 +36,7 @@ resource "aws_s3_bucket_public_access_block" "truststore" { aws_s3_bucket_policy.truststore ] - bucket = aws_s3_bucket.truststore[0].id + bucket = aws_s3_bucket.truststore.id block_public_acls = true block_public_policy = true @@ -45,7 +45,7 @@ resource "aws_s3_bucket_public_access_block" "truststore" { } resource "aws_s3_bucket_logging" "truststore" { - bucket = aws_s3_bucket.truststore[0].id + bucket = aws_s3_bucket.truststore.id target_bucket = var.truststore_s3_bucket_config.bucket_logs_bucket_name target_prefix = "truststore/${aws_s3_bucket.truststore[0].bucket}/" @@ -54,9 +54,9 @@ resource "aws_s3_bucket_logging" "truststore" { # If Environment is to be Manually configured, need to create a placeholder truststore file for mtls resource "aws_s3_object" "placeholder_truststore" { count = var.manually_configure_mtls_truststore ? 1 : 0 - bucket = aws_s3_bucket.truststore[0].bucket + bucket = aws_s3_bucket.truststore.bucket key = "truststore.pem" - content = tls_self_signed_cert.placeholder_cert[0].cert_pem + content = tls_self_signed_cert.placeholder_cert.cert_pem depends_on = [ aws_s3_bucket_versioning.truststore @@ -74,7 +74,7 @@ resource "aws_s3_object" "placeholder_truststore" { # We don't want to ignore content in nonprod, but we do for prod as we will manually update certs and not via ssl module resource "aws_s3_object" "placeholder_truststore_nonprod" { count = var.manually_configure_mtls_truststore ? 0 : 1 - bucket = aws_s3_bucket.truststore[0].bucket + bucket = aws_s3_bucket.truststore.bucket key = "truststore.pem" content = module.supplier_ssl.cacert_pem From d3d31dca6d504b7e37389eae88fa07594f7ba77e Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Mon, 18 Aug 2025 16:33:01 +0100 Subject: [PATCH 05/30] CCM-11586: store ref not indexed --- .../components/api/s3_bucket_policy_truststore.tf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/infrastructure/terraform/components/api/s3_bucket_policy_truststore.tf b/infrastructure/terraform/components/api/s3_bucket_policy_truststore.tf index 36ed5166..759b3c5b 100644 --- a/infrastructure/terraform/components/api/s3_bucket_policy_truststore.tf +++ b/infrastructure/terraform/components/api/s3_bucket_policy_truststore.tf @@ -1,6 +1,6 @@ resource "aws_s3_bucket_policy" "truststore" { - bucket = aws_s3_bucket.truststore[0].id - policy = data.aws_iam_policy_document.truststore[0].json + bucket = aws_s3_bucket.truststore.id + policy = data.aws_iam_policy_document.truststore.json } data "aws_iam_policy_document" "truststore" { @@ -8,8 +8,8 @@ data "aws_iam_policy_document" "truststore" { effect = "Deny" actions = ["s3:*"] resources = [ - aws_s3_bucket.truststore[0].arn, - "${aws_s3_bucket.truststore[0].arn}/*", + aws_s3_bucket.truststore.arn, + "${aws_s3_bucket.truststore.arn}/*", ] principals { From 1193294880063b6dbc12adf1854aeee41c83b072 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Mon, 18 Aug 2025 16:46:00 +0100 Subject: [PATCH 06/30] CCM-11586: cert references --- .../components/api/s3_bucket_truststore.tf | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/infrastructure/terraform/components/api/s3_bucket_truststore.tf b/infrastructure/terraform/components/api/s3_bucket_truststore.tf index 61a828cd..094ef9da 100644 --- a/infrastructure/terraform/components/api/s3_bucket_truststore.tf +++ b/infrastructure/terraform/components/api/s3_bucket_truststore.tf @@ -48,15 +48,15 @@ resource "aws_s3_bucket_logging" "truststore" { bucket = aws_s3_bucket.truststore.id target_bucket = var.truststore_s3_bucket_config.bucket_logs_bucket_name - target_prefix = "truststore/${aws_s3_bucket.truststore[0].bucket}/" + target_prefix = "truststore/${aws_s3_bucket.truststore.bucket}/" } -# If Environment is to be Manually configured, need to create a placeholder truststore file for mtls +# In manually configured (e.g. dev main, nonprod main, prod main) add lifecycle policy to permit manual management of cert resource "aws_s3_object" "placeholder_truststore" { count = var.manually_configure_mtls_truststore ? 1 : 0 bucket = aws_s3_bucket.truststore.bucket key = "truststore.pem" - content = tls_self_signed_cert.placeholder_cert.cert_pem + content = module.supplier_ssl[0].cacert_pem depends_on = [ aws_s3_bucket_versioning.truststore @@ -69,14 +69,13 @@ resource "aws_s3_object" "placeholder_truststore" { } } -# If env is not manually configured, use the certs generated from the ssl module -# Having a duplicate resource here as lifcycle rules can't be dynamic or variable -# We don't want to ignore content in nonprod, but we do for prod as we will manually update certs and not via ssl module +# In non-manually configured env (e.g. PR) exclude lifecycle policy so resources are managed +# Requires duplicate block as lifecycle policies cannot be dynamic resource "aws_s3_object" "placeholder_truststore_nonprod" { count = var.manually_configure_mtls_truststore ? 0 : 1 bucket = aws_s3_bucket.truststore.bucket key = "truststore.pem" - content = module.supplier_ssl.cacert_pem + content = module.supplier_ssl[0].cacert_pem depends_on = [ aws_s3_bucket_versioning.truststore, From bfe977e3592d3740c9ec60b7c8e89211e317fc98 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Mon, 18 Aug 2025 16:49:26 +0100 Subject: [PATCH 07/30] CCM-11586: domain store refs --- infrastructure/terraform/components/api/api_gateway_domain.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/terraform/components/api/api_gateway_domain.tf b/infrastructure/terraform/components/api/api_gateway_domain.tf index 3ed91d1a..8e0437be 100644 --- a/infrastructure/terraform/components/api/api_gateway_domain.tf +++ b/infrastructure/terraform/components/api/api_gateway_domain.tf @@ -12,8 +12,8 @@ resource "aws_api_gateway_domain_name" "main" { ] mutual_tls_authentication { - truststore_uri = "s3://${aws_s3_bucket.truststore[0].id}/${aws_s3_object.placeholder_truststore[0].id}" - truststore_version = aws_s3_object.placeholder_truststore[0].version_id + truststore_uri = "s3://${aws_s3_bucket.truststore.id}/${aws_s3_object.placeholder_truststore.id}" + truststore_version = aws_s3_object.placeholder_truststore.version_id } lifecycle { From a54d726a14b2e9bbcc09d6ab516d15631e128cfc Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Mon, 18 Aug 2025 17:03:37 +0100 Subject: [PATCH 08/30] CCM-11586: domain name lifecycles --- .../api/api_gateway_base_path_mapping.tf | 2 +- .../components/api/api_gateway_domain.tf | 23 ++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/infrastructure/terraform/components/api/api_gateway_base_path_mapping.tf b/infrastructure/terraform/components/api/api_gateway_base_path_mapping.tf index 30e41803..0cc9a325 100644 --- a/infrastructure/terraform/components/api/api_gateway_base_path_mapping.tf +++ b/infrastructure/terraform/components/api/api_gateway_base_path_mapping.tf @@ -1,5 +1,5 @@ resource "aws_api_gateway_base_path_mapping" "main" { api_id = aws_api_gateway_rest_api.main.id stage_name = aws_api_gateway_stage.main.stage_name - domain_name = aws_api_gateway_domain_name.main.domain_name + domain_name = var.manually_configure_mtls_truststore ? aws_api_gateway_domain_name.main.0.domain_name : aws_api_gateway_domain_name.main_nonprod.0.domain_name } diff --git a/infrastructure/terraform/components/api/api_gateway_domain.tf b/infrastructure/terraform/components/api/api_gateway_domain.tf index 8e0437be..973379ed 100644 --- a/infrastructure/terraform/components/api/api_gateway_domain.tf +++ b/infrastructure/terraform/components/api/api_gateway_domain.tf @@ -1,4 +1,5 @@ resource "aws_api_gateway_domain_name" "main" { + count = var.manually_configure_mtls_truststore ? 1 : 0 regional_certificate_arn = aws_acm_certificate_validation.main.certificate_arn domain_name = local.root_domain_name security_policy = "TLS_1_2" @@ -12,7 +13,7 @@ resource "aws_api_gateway_domain_name" "main" { ] mutual_tls_authentication { - truststore_uri = "s3://${aws_s3_bucket.truststore.id}/${aws_s3_object.placeholder_truststore.id}" + truststore_uri = "s3://${aws_s3_bucket.truststore.id}/${aws_s3_object.placeholder_truststore[0].id}" truststore_version = aws_s3_object.placeholder_truststore.version_id } @@ -22,3 +23,23 @@ resource "aws_api_gateway_domain_name" "main" { ] } } + +resource "aws_api_gateway_domain_name" "main_nonprod" { + count = var.manually_configure_mtls_truststore ? 1 : 0 + regional_certificate_arn = aws_acm_certificate_validation.main.certificate_arn + domain_name = local.root_domain_name + security_policy = "TLS_1_2" + + endpoint_configuration { + types = ["REGIONAL"] + } + + depends_on = [ + aws_s3_bucket.truststore + ] + + mutual_tls_authentication { + truststore_uri = "s3://${aws_s3_bucket.truststore.id}/${aws_s3_object.placeholder_truststore_nonprod[0].id}" + truststore_version = aws_s3_object.placeholder_truststore_nonprod[0].version_id + } +} From 20f4ec2e10c7ff4085d8abe17bd0dd2f9685e36d Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Tue, 19 Aug 2025 11:15:41 +0100 Subject: [PATCH 09/30] CCM-11586: more tf refs --- infrastructure/terraform/components/api/api_gateway_domain.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/terraform/components/api/api_gateway_domain.tf b/infrastructure/terraform/components/api/api_gateway_domain.tf index 973379ed..18b4603e 100644 --- a/infrastructure/terraform/components/api/api_gateway_domain.tf +++ b/infrastructure/terraform/components/api/api_gateway_domain.tf @@ -14,7 +14,7 @@ resource "aws_api_gateway_domain_name" "main" { mutual_tls_authentication { truststore_uri = "s3://${aws_s3_bucket.truststore.id}/${aws_s3_object.placeholder_truststore[0].id}" - truststore_version = aws_s3_object.placeholder_truststore.version_id + truststore_version = aws_s3_object.placeholder_truststore[0].version_id } lifecycle { From 94e1215e5d5a14be7f48911bc2341cdca64550e6 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Tue, 19 Aug 2025 11:57:46 +0100 Subject: [PATCH 10/30] CCM-11586: domain name lifecycles --- .../components/api/api_gateway_domain.tf | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/infrastructure/terraform/components/api/api_gateway_domain.tf b/infrastructure/terraform/components/api/api_gateway_domain.tf index 18b4603e..1f7fd664 100644 --- a/infrastructure/terraform/components/api/api_gateway_domain.tf +++ b/infrastructure/terraform/components/api/api_gateway_domain.tf @@ -1,5 +1,4 @@ resource "aws_api_gateway_domain_name" "main" { - count = var.manually_configure_mtls_truststore ? 1 : 0 regional_certificate_arn = aws_acm_certificate_validation.main.certificate_arn domain_name = local.root_domain_name security_policy = "TLS_1_2" @@ -18,28 +17,26 @@ resource "aws_api_gateway_domain_name" "main" { } lifecycle { - ignore_changes = [ - mutual_tls_authentication - ] + ignore_changes = var.manually_configure_mtls_truststore ? [mutual_tls_authentication] : [] } } -resource "aws_api_gateway_domain_name" "main_nonprod" { - count = var.manually_configure_mtls_truststore ? 1 : 0 - regional_certificate_arn = aws_acm_certificate_validation.main.certificate_arn - domain_name = local.root_domain_name - security_policy = "TLS_1_2" - - endpoint_configuration { - types = ["REGIONAL"] - } - - depends_on = [ - aws_s3_bucket.truststore - ] - - mutual_tls_authentication { - truststore_uri = "s3://${aws_s3_bucket.truststore.id}/${aws_s3_object.placeholder_truststore_nonprod[0].id}" - truststore_version = aws_s3_object.placeholder_truststore_nonprod[0].version_id - } -} +# resource "aws_api_gateway_domain_name" "main_nonprod" { +# count = var.manually_configure_mtls_truststore ? 1 : 0 +# regional_certificate_arn = aws_acm_certificate_validation.main.certificate_arn +# domain_name = local.root_domain_name +# security_policy = "TLS_1_2" + +# endpoint_configuration { +# types = ["REGIONAL"] +# } + +# depends_on = [ +# aws_s3_bucket.truststore +# ] + +# mutual_tls_authentication { +# truststore_uri = "s3://${aws_s3_bucket.truststore.id}/${aws_s3_object.placeholder_truststore_nonprod[0].id}" +# truststore_version = aws_s3_object.placeholder_truststore_nonprod[0].version_id +# } +# } From fdde8154867de1e9f06f083fcd9d331df9008e51 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Wed, 20 Aug 2025 13:51:03 +0100 Subject: [PATCH 11/30] CCM-11586: more sensible route53 config --- .../components/api/api_gateway_domain.tf | 43 ++++++++++--------- .../components/api/route53_record.tf | 4 +- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/infrastructure/terraform/components/api/api_gateway_domain.tf b/infrastructure/terraform/components/api/api_gateway_domain.tf index 1f7fd664..42d3ff49 100644 --- a/infrastructure/terraform/components/api/api_gateway_domain.tf +++ b/infrastructure/terraform/components/api/api_gateway_domain.tf @@ -1,4 +1,5 @@ resource "aws_api_gateway_domain_name" "main" { + count = var.manually_configure_mtls_truststore ? 1 : 0 regional_certificate_arn = aws_acm_certificate_validation.main.certificate_arn domain_name = local.root_domain_name security_policy = "TLS_1_2" @@ -17,26 +18,28 @@ resource "aws_api_gateway_domain_name" "main" { } lifecycle { - ignore_changes = var.manually_configure_mtls_truststore ? [mutual_tls_authentication] : [] + ignore_changes = [ + mutual_tls_authentication + ] } } -# resource "aws_api_gateway_domain_name" "main_nonprod" { -# count = var.manually_configure_mtls_truststore ? 1 : 0 -# regional_certificate_arn = aws_acm_certificate_validation.main.certificate_arn -# domain_name = local.root_domain_name -# security_policy = "TLS_1_2" - -# endpoint_configuration { -# types = ["REGIONAL"] -# } - -# depends_on = [ -# aws_s3_bucket.truststore -# ] - -# mutual_tls_authentication { -# truststore_uri = "s3://${aws_s3_bucket.truststore.id}/${aws_s3_object.placeholder_truststore_nonprod[0].id}" -# truststore_version = aws_s3_object.placeholder_truststore_nonprod[0].version_id -# } -# } +resource "aws_api_gateway_domain_name" "main_nonprod" { + count = !var.manually_configure_mtls_truststore ? 1 : 0 + regional_certificate_arn = aws_acm_certificate_validation.main.certificate_arn + domain_name = local.root_domain_name + security_policy = "TLS_1_2" + + endpoint_configuration { + types = ["REGIONAL"] + } + + depends_on = [ + aws_s3_bucket.truststore + ] + + mutual_tls_authentication { + truststore_uri = "s3://${aws_s3_bucket.truststore.id}/${aws_s3_object.placeholder_truststore_nonprod[0].id}" + truststore_version = aws_s3_object.placeholder_truststore_nonprod[0].version_id + } +} diff --git a/infrastructure/terraform/components/api/route53_record.tf b/infrastructure/terraform/components/api/route53_record.tf index 0ce1d8b0..d8fe6d97 100644 --- a/infrastructure/terraform/components/api/route53_record.tf +++ b/infrastructure/terraform/components/api/route53_record.tf @@ -4,8 +4,8 @@ resource "aws_route53_record" "main" { zone_id = local.root_domain_id alias { - name = aws_api_gateway_domain_name.main.regional_domain_name - zone_id = aws_api_gateway_domain_name.main.regional_zone_id + name = var.manually_configure_mtls_truststore ? aws_api_gateway_domain_name.main.0.regional_domain_name : aws_api_gateway_domain_name.main_nonprod.0.regional_domain_name + zone_id = var.manually_configure_mtls_truststore ? aws_api_gateway_domain_name.main.0.regional_zone_id : aws_api_gateway_domain_name.main_nonprod.0.regional_zone_id evaluate_target_health = true } From 235abc7080ed53e26f73afd4c355ec0813d6e527 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Wed, 20 Aug 2025 13:53:47 +0100 Subject: [PATCH 12/30] CCM-11586: correct name reference --- infrastructure/terraform/components/api/route53_record.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/terraform/components/api/route53_record.tf b/infrastructure/terraform/components/api/route53_record.tf index d8fe6d97..63affc80 100644 --- a/infrastructure/terraform/components/api/route53_record.tf +++ b/infrastructure/terraform/components/api/route53_record.tf @@ -1,5 +1,5 @@ resource "aws_route53_record" "main" { - name = aws_api_gateway_domain_name.main.domain_name + name = var.manually_configure_mtls_truststore ? aws_api_gateway_domain_name.main.0.regional_domain_name : aws_api_gateway_domain_name.main_nonprod.0.regional_domain_name type = "A" zone_id = local.root_domain_id From 4397b2cbb66b33248ff4706d37e3d257ef1c93af Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Wed, 20 Aug 2025 13:58:57 +0100 Subject: [PATCH 13/30] CCM-11586: correct locals csis3 def --- infrastructure/terraform/components/api/locals.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/terraform/components/api/locals.tf b/infrastructure/terraform/components/api/locals.tf index d2b786cc..dda9ac75 100644 --- a/infrastructure/terraform/components/api/locals.tf +++ b/infrastructure/terraform/components/api/locals.tf @@ -17,7 +17,7 @@ locals { csi_s3 = replace( format( - "%s-%s-%s-%s", + "%s-%s-%s", var.project, var.aws_account_id, var.environment From 911df5d19fe81b575934ed80b2fbeccf8a800f66 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Wed, 20 Aug 2025 14:09:18 +0100 Subject: [PATCH 14/30] CCM-11586: change csi to meet s3 naming convention --- infrastructure/terraform/components/api/locals.tf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/infrastructure/terraform/components/api/locals.tf b/infrastructure/terraform/components/api/locals.tf index dda9ac75..851ad443 100644 --- a/infrastructure/terraform/components/api/locals.tf +++ b/infrastructure/terraform/components/api/locals.tf @@ -17,9 +17,10 @@ locals { csi_s3 = replace( format( - "%s-%s-%s", + "%s-%s-%s-%s", var.project, var.aws_account_id, + var.region, var.environment ), "_", From e29e8cc3f94f7e08a4fc89e902379ab7c2aed53d Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Wed, 20 Aug 2025 14:38:09 +0100 Subject: [PATCH 15/30] CCM-11586: remove config variable, reference infra --- infrastructure/terraform/components/api/README.md | 1 - .../components/api/s3_bucket_truststore.tf | 4 ++-- .../terraform/components/api/variables.tf | 14 -------------- 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/infrastructure/terraform/components/api/README.md b/infrastructure/terraform/components/api/README.md index 850369a0..6314d73b 100644 --- a/infrastructure/terraform/components/api/README.md +++ b/infrastructure/terraform/components/api/README.md @@ -24,7 +24,6 @@ No requirements. | [project](#input\_project) | The name of the tfscaffold project | `string` | n/a | yes | | [region](#input\_region) | The AWS Region | `string` | n/a | yes | | [shared\_infra\_account\_id](#input\_shared\_infra\_account\_id) | The AWS Account ID of the shared infrastructure account | `string` | `"000000000000"` | no | -| [truststore\_s3\_bucket\_config](#input\_truststore\_s3\_bucket\_config) | Parameters for configuring the Notify Supplier API truststore bucket |
object({
kms_key_id = string
kms_key_arn = string
bucket_logs_bucket_name = string
})
|
{
"bucket_logs_bucket_name": "",
"kms_key_arn": "",
"kms_key_id": ""
}
| no | ## Modules | Name | Source | Version | diff --git a/infrastructure/terraform/components/api/s3_bucket_truststore.tf b/infrastructure/terraform/components/api/s3_bucket_truststore.tf index 094ef9da..3e6c64f0 100644 --- a/infrastructure/terraform/components/api/s3_bucket_truststore.tf +++ b/infrastructure/terraform/components/api/s3_bucket_truststore.tf @@ -17,7 +17,7 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "truststore" { rule { apply_server_side_encryption_by_default { sse_algorithm = "aws:kms" - kms_master_key_id = var.truststore_s3_bucket_config.kms_key_id + kms_master_key_id = module.kms.key_id } bucket_key_enabled = true } @@ -47,7 +47,7 @@ resource "aws_s3_bucket_public_access_block" "truststore" { resource "aws_s3_bucket_logging" "truststore" { bucket = aws_s3_bucket.truststore.id - target_bucket = var.truststore_s3_bucket_config.bucket_logs_bucket_name + target_bucket = "${local.csi_s3}-bucket-logs" target_prefix = "truststore/${aws_s3_bucket.truststore.bucket}/" } diff --git a/infrastructure/terraform/components/api/variables.tf b/infrastructure/terraform/components/api/variables.tf index 39a1a395..1b3b789c 100644 --- a/infrastructure/terraform/components/api/variables.tf +++ b/infrastructure/terraform/components/api/variables.tf @@ -98,17 +98,3 @@ variable "enable_backups" { description = "Enable backups" default = false } - -variable "truststore_s3_bucket_config" { - type = object({ - kms_key_id = string - kms_key_arn = string - bucket_logs_bucket_name = string - }) - description = "Parameters for configuring the Notify Supplier API truststore bucket" - default = { - bucket_logs_bucket_name = "" - kms_key_arn = "" - kms_key_id = "" - } -} From 6dbea64d2c9f63f6a539f1078d81cecc69fafa62 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Wed, 20 Aug 2025 14:44:46 +0100 Subject: [PATCH 16/30] CCM-11586: centralised bucket logging, define a bucket --- .../terraform/components/api/s3_bucket_logging.tf | 11 +++++++++++ .../terraform/components/api/s3_bucket_truststore.tf | 7 ------- 2 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 infrastructure/terraform/components/api/s3_bucket_logging.tf diff --git a/infrastructure/terraform/components/api/s3_bucket_logging.tf b/infrastructure/terraform/components/api/s3_bucket_logging.tf new file mode 100644 index 00000000..38b9ce8f --- /dev/null +++ b/infrastructure/terraform/components/api/s3_bucket_logging.tf @@ -0,0 +1,11 @@ +resource "aws_s3_bucket" "logging" { + bucket = "${local.csi_s3}-bucket-logs" + tags = merge(local.default_tags, { "Enable-Backup" = var.enable_backups }, { "Enable-S3-Continuous-Backup" = var.enable_backups }, { "SKIP_S3_AUDIT" = "true" }) +} + +resource "aws_s3_bucket_logging" "truststore" { + bucket = aws_s3_bucket.truststore.id + + target_bucket = aws_s3_bucket.logging.bucket + target_prefix = "truststore/${aws_s3_bucket.truststore.bucket}/" +} diff --git a/infrastructure/terraform/components/api/s3_bucket_truststore.tf b/infrastructure/terraform/components/api/s3_bucket_truststore.tf index 3e6c64f0..014c9ea9 100644 --- a/infrastructure/terraform/components/api/s3_bucket_truststore.tf +++ b/infrastructure/terraform/components/api/s3_bucket_truststore.tf @@ -44,13 +44,6 @@ resource "aws_s3_bucket_public_access_block" "truststore" { restrict_public_buckets = true } -resource "aws_s3_bucket_logging" "truststore" { - bucket = aws_s3_bucket.truststore.id - - target_bucket = "${local.csi_s3}-bucket-logs" - target_prefix = "truststore/${aws_s3_bucket.truststore.bucket}/" -} - # In manually configured (e.g. dev main, nonprod main, prod main) add lifecycle policy to permit manual management of cert resource "aws_s3_object" "placeholder_truststore" { count = var.manually_configure_mtls_truststore ? 1 : 0 From 27b267195cef9e2d37603e6df6aca1b65dfe233b Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Wed, 20 Aug 2025 15:07:05 +0100 Subject: [PATCH 17/30] CCM-11586: try fix truststore uri --- .../terraform/components/api/api_gateway_domain.tf | 10 ++++++---- .../terraform/components/api/s3_bucket_truststore.tf | 5 +++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/infrastructure/terraform/components/api/api_gateway_domain.tf b/infrastructure/terraform/components/api/api_gateway_domain.tf index 42d3ff49..c68b5ee1 100644 --- a/infrastructure/terraform/components/api/api_gateway_domain.tf +++ b/infrastructure/terraform/components/api/api_gateway_domain.tf @@ -9,11 +9,12 @@ resource "aws_api_gateway_domain_name" "main" { } depends_on = [ - aws_s3_bucket.truststore + aws_s3_bucket.truststore, + aws_s3_object.placeholder_truststore ] mutual_tls_authentication { - truststore_uri = "s3://${aws_s3_bucket.truststore.id}/${aws_s3_object.placeholder_truststore[0].id}" + truststore_uri = "s3://${aws_s3_bucket.truststore.id}/${aws_s3_object.placeholder_truststore[0].key}" truststore_version = aws_s3_object.placeholder_truststore[0].version_id } @@ -35,11 +36,12 @@ resource "aws_api_gateway_domain_name" "main_nonprod" { } depends_on = [ - aws_s3_bucket.truststore + aws_s3_bucket.truststore, + aws_s3_object.placeholder_truststore_nonprod ] mutual_tls_authentication { - truststore_uri = "s3://${aws_s3_bucket.truststore.id}/${aws_s3_object.placeholder_truststore_nonprod[0].id}" + truststore_uri = "s3://${aws_s3_bucket.truststore.id}/${aws_s3_object.placeholder_truststore_nonprod[0].key}" truststore_version = aws_s3_object.placeholder_truststore_nonprod[0].version_id } } diff --git a/infrastructure/terraform/components/api/s3_bucket_truststore.tf b/infrastructure/terraform/components/api/s3_bucket_truststore.tf index 014c9ea9..5e6dda0d 100644 --- a/infrastructure/terraform/components/api/s3_bucket_truststore.tf +++ b/infrastructure/terraform/components/api/s3_bucket_truststore.tf @@ -52,7 +52,8 @@ resource "aws_s3_object" "placeholder_truststore" { content = module.supplier_ssl[0].cacert_pem depends_on = [ - aws_s3_bucket_versioning.truststore + aws_s3_bucket_versioning.truststore, + module.supplier_ssl ] lifecycle { @@ -65,7 +66,7 @@ resource "aws_s3_object" "placeholder_truststore" { # In non-manually configured env (e.g. PR) exclude lifecycle policy so resources are managed # Requires duplicate block as lifecycle policies cannot be dynamic resource "aws_s3_object" "placeholder_truststore_nonprod" { - count = var.manually_configure_mtls_truststore ? 0 : 1 + count = !var.manually_configure_mtls_truststore ? 1 : 0 bucket = aws_s3_bucket.truststore.bucket key = "truststore.pem" content = module.supplier_ssl[0].cacert_pem From f02cafc57b1f988f68a2a0a125016b9c034a1460 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Wed, 20 Aug 2025 15:14:42 +0100 Subject: [PATCH 18/30] CCM-11586: Disable execute-api endpoint --- infrastructure/terraform/components/api/api_gateway_rest_api.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/infrastructure/terraform/components/api/api_gateway_rest_api.tf b/infrastructure/terraform/components/api/api_gateway_rest_api.tf index 1ff0e47b..70452941 100644 --- a/infrastructure/terraform/components/api/api_gateway_rest_api.tf +++ b/infrastructure/terraform/components/api/api_gateway_rest_api.tf @@ -2,4 +2,5 @@ resource "aws_api_gateway_rest_api" "main" { name = local.csi body = local.openapi_spec description = "Suppliers API" + disable_execute_api_endpoint = true } From 1413b02c8a6df7d8278e71e9b9604116e728601b Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Wed, 20 Aug 2025 15:25:53 +0100 Subject: [PATCH 19/30] CCM-11586: secure logging bucket --- .../components/api/s3_bucket_logging.tf | 37 +++++++++++++++++++ .../api/s3_bucket_policy_logging.tf | 28 ++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 infrastructure/terraform/components/api/s3_bucket_policy_logging.tf diff --git a/infrastructure/terraform/components/api/s3_bucket_logging.tf b/infrastructure/terraform/components/api/s3_bucket_logging.tf index 38b9ce8f..a2be4395 100644 --- a/infrastructure/terraform/components/api/s3_bucket_logging.tf +++ b/infrastructure/terraform/components/api/s3_bucket_logging.tf @@ -3,6 +3,43 @@ resource "aws_s3_bucket" "logging" { tags = merge(local.default_tags, { "Enable-Backup" = var.enable_backups }, { "Enable-S3-Continuous-Backup" = var.enable_backups }, { "SKIP_S3_AUDIT" = "true" }) } +resource "aws_s3_bucket_ownership_controls" "logging" { + bucket = aws_s3_bucket.logging.id + + rule { + object_ownership = "BucketOwnerPreferred" + } +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "logging" { + bucket = aws_s3_bucket.logging.id + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "aws:kms" + kms_master_key_id = module.kms.key_id + } + bucket_key_enabled = true + } +} + +resource "aws_s3_bucket_public_access_block" "logging" { + depends_on = [ + aws_s3_bucket_policy.logging + ] + + bucket = aws_s3_bucket.logging.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +### +# Bucket logging definitions past here +### + resource "aws_s3_bucket_logging" "truststore" { bucket = aws_s3_bucket.truststore.id diff --git a/infrastructure/terraform/components/api/s3_bucket_policy_logging.tf b/infrastructure/terraform/components/api/s3_bucket_policy_logging.tf new file mode 100644 index 00000000..24ebecf3 --- /dev/null +++ b/infrastructure/terraform/components/api/s3_bucket_policy_logging.tf @@ -0,0 +1,28 @@ +resource "aws_s3_bucket_policy" "logging" { + bucket = aws_s3_bucket.logging.id + policy = data.aws_iam_policy_document.logging.json +} + +data "aws_iam_policy_document" "logging" { + statement { + effect = "Deny" + actions = ["s3:*"] + resources = [ + aws_s3_bucket.logging.arn, + "${aws_s3_bucket.logging.arn}/*", + ] + + principals { + type = "AWS" + identifiers = ["*"] + } + + condition { + test = "Bool" + variable = "aws:SecureTransport" + values = [ + false + ] + } + } +} From 108dfc1934304eece9a01c1aae0ccee4a2ee6bd6 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Wed, 20 Aug 2025 15:32:08 +0100 Subject: [PATCH 20/30] CCM-11586: refine logging bucket policies --- .../components/api/s3_bucket_logging.tf | 2 +- .../components/api/s3_bucket_policy_logging.tf | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/infrastructure/terraform/components/api/s3_bucket_logging.tf b/infrastructure/terraform/components/api/s3_bucket_logging.tf index a2be4395..7d795f36 100644 --- a/infrastructure/terraform/components/api/s3_bucket_logging.tf +++ b/infrastructure/terraform/components/api/s3_bucket_logging.tf @@ -44,5 +44,5 @@ resource "aws_s3_bucket_logging" "truststore" { bucket = aws_s3_bucket.truststore.id target_bucket = aws_s3_bucket.logging.bucket - target_prefix = "truststore/${aws_s3_bucket.truststore.bucket}/" + target_prefix = "${aws_s3_bucket.truststore.bucket}/" } diff --git a/infrastructure/terraform/components/api/s3_bucket_policy_logging.tf b/infrastructure/terraform/components/api/s3_bucket_policy_logging.tf index 24ebecf3..304155bc 100644 --- a/infrastructure/terraform/components/api/s3_bucket_policy_logging.tf +++ b/infrastructure/terraform/components/api/s3_bucket_policy_logging.tf @@ -25,4 +25,20 @@ data "aws_iam_policy_document" "logging" { ] } } + + statement { + sid = "s3-log-delivery" + effect = "Allow" + + principals { + type = "Service" + identifiers = ["logging.s3.amazonaws.com"] + } + + actions = ["s3:PutObject"] + + resources = [ + "${aws_s3_bucket.logging.arn}/*", + ] + } } From 8d30c4b7ad16de5ea1eeefdcfef1b62885b2cea5 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Wed, 20 Aug 2025 15:39:53 +0100 Subject: [PATCH 21/30] CCM-11586: does consolidation make sonar happy --- .../components/api/s3_bucket_logging.tf | 48 ++++++++++++++++--- .../api/s3_bucket_policy_logging.tf | 44 ----------------- .../components/api/s3_bucket_truststore.tf | 7 +++ 3 files changed, 48 insertions(+), 51 deletions(-) delete mode 100644 infrastructure/terraform/components/api/s3_bucket_policy_logging.tf diff --git a/infrastructure/terraform/components/api/s3_bucket_logging.tf b/infrastructure/terraform/components/api/s3_bucket_logging.tf index 7d795f36..9afb14f5 100644 --- a/infrastructure/terraform/components/api/s3_bucket_logging.tf +++ b/infrastructure/terraform/components/api/s3_bucket_logging.tf @@ -36,13 +36,47 @@ resource "aws_s3_bucket_public_access_block" "logging" { restrict_public_buckets = true } -### -# Bucket logging definitions past here -### +data "aws_iam_policy_document" "logging" { + statement { + effect = "Deny" + actions = ["s3:*"] + resources = [ + aws_s3_bucket.logging.arn, + "${aws_s3_bucket.logging.arn}/*", + ] -resource "aws_s3_bucket_logging" "truststore" { - bucket = aws_s3_bucket.truststore.id + principals { + type = "AWS" + identifiers = ["*"] + } + + condition { + test = "Bool" + variable = "aws:SecureTransport" + values = [ + false + ] + } + } + + statement { + sid = "s3-log-delivery" + effect = "Allow" + + principals { + type = "Service" + identifiers = ["logging.s3.amazonaws.com"] + } - target_bucket = aws_s3_bucket.logging.bucket - target_prefix = "${aws_s3_bucket.truststore.bucket}/" + actions = ["s3:PutObject"] + + resources = [ + "${aws_s3_bucket.logging.arn}/*", + ] + } +} + +resource "aws_s3_bucket_policy" "logging" { + bucket = aws_s3_bucket.logging.id + policy = data.aws_iam_policy_document.logging.json } diff --git a/infrastructure/terraform/components/api/s3_bucket_policy_logging.tf b/infrastructure/terraform/components/api/s3_bucket_policy_logging.tf deleted file mode 100644 index 304155bc..00000000 --- a/infrastructure/terraform/components/api/s3_bucket_policy_logging.tf +++ /dev/null @@ -1,44 +0,0 @@ -resource "aws_s3_bucket_policy" "logging" { - bucket = aws_s3_bucket.logging.id - policy = data.aws_iam_policy_document.logging.json -} - -data "aws_iam_policy_document" "logging" { - statement { - effect = "Deny" - actions = ["s3:*"] - resources = [ - aws_s3_bucket.logging.arn, - "${aws_s3_bucket.logging.arn}/*", - ] - - principals { - type = "AWS" - identifiers = ["*"] - } - - condition { - test = "Bool" - variable = "aws:SecureTransport" - values = [ - false - ] - } - } - - statement { - sid = "s3-log-delivery" - effect = "Allow" - - principals { - type = "Service" - identifiers = ["logging.s3.amazonaws.com"] - } - - actions = ["s3:PutObject"] - - resources = [ - "${aws_s3_bucket.logging.arn}/*", - ] - } -} diff --git a/infrastructure/terraform/components/api/s3_bucket_truststore.tf b/infrastructure/terraform/components/api/s3_bucket_truststore.tf index 5e6dda0d..97939348 100644 --- a/infrastructure/terraform/components/api/s3_bucket_truststore.tf +++ b/infrastructure/terraform/components/api/s3_bucket_truststore.tf @@ -44,6 +44,13 @@ resource "aws_s3_bucket_public_access_block" "truststore" { restrict_public_buckets = true } +resource "aws_s3_bucket_logging" "truststore" { + bucket = aws_s3_bucket.truststore.id + + target_bucket = aws_s3_bucket.logging.bucket + target_prefix = "${aws_s3_bucket.truststore.bucket}/" +} + # In manually configured (e.g. dev main, nonprod main, prod main) add lifecycle policy to permit manual management of cert resource "aws_s3_object" "placeholder_truststore" { count = var.manually_configure_mtls_truststore ? 1 : 0 From 00faa97ebdda3aeb82eb884887370ded80cff5fb Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Wed, 20 Aug 2025 15:43:50 +0100 Subject: [PATCH 22/30] CCM-11586: consolidation does make sonar happy --- .../api/s3_bucket_object_truststore.tf | 32 +++++++++++++++++++ .../api/s3_bucket_policy_truststore.tf | 28 ---------------- 2 files changed, 32 insertions(+), 28 deletions(-) create mode 100644 infrastructure/terraform/components/api/s3_bucket_object_truststore.tf delete mode 100644 infrastructure/terraform/components/api/s3_bucket_policy_truststore.tf diff --git a/infrastructure/terraform/components/api/s3_bucket_object_truststore.tf b/infrastructure/terraform/components/api/s3_bucket_object_truststore.tf new file mode 100644 index 00000000..a5db4b69 --- /dev/null +++ b/infrastructure/terraform/components/api/s3_bucket_object_truststore.tf @@ -0,0 +1,32 @@ +# In manually configured (e.g. dev main, nonprod main, prod main) add lifecycle policy to permit manual management of cert +resource "aws_s3_object" "placeholder_truststore" { + count = var.manually_configure_mtls_truststore ? 1 : 0 + bucket = aws_s3_bucket.truststore.bucket + key = "truststore.pem" + content = module.supplier_ssl[0].cacert_pem + + depends_on = [ + aws_s3_bucket_versioning.truststore, + module.supplier_ssl + ] + + lifecycle { + ignore_changes = [ + content + ] + } +} + +# In non-manually configured env (e.g. PR) exclude lifecycle policy so resources are managed +# Requires duplicate block as lifecycle policies cannot be dynamic +resource "aws_s3_object" "placeholder_truststore_nonprod" { + count = !var.manually_configure_mtls_truststore ? 1 : 0 + bucket = aws_s3_bucket.truststore.bucket + key = "truststore.pem" + content = module.supplier_ssl[0].cacert_pem + + depends_on = [ + aws_s3_bucket_versioning.truststore, + module.supplier_ssl + ] +} diff --git a/infrastructure/terraform/components/api/s3_bucket_policy_truststore.tf b/infrastructure/terraform/components/api/s3_bucket_policy_truststore.tf deleted file mode 100644 index 759b3c5b..00000000 --- a/infrastructure/terraform/components/api/s3_bucket_policy_truststore.tf +++ /dev/null @@ -1,28 +0,0 @@ -resource "aws_s3_bucket_policy" "truststore" { - bucket = aws_s3_bucket.truststore.id - policy = data.aws_iam_policy_document.truststore.json -} - -data "aws_iam_policy_document" "truststore" { - statement { - effect = "Deny" - actions = ["s3:*"] - resources = [ - aws_s3_bucket.truststore.arn, - "${aws_s3_bucket.truststore.arn}/*", - ] - - principals { - type = "AWS" - identifiers = ["*"] - } - - condition { - test = "Bool" - variable = "aws:SecureTransport" - values = [ - false - ] - } - } -} From d3eb5137af118a5a8522d2c7ac2495fc5f9c8fce Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Wed, 20 Aug 2025 15:46:22 +0100 Subject: [PATCH 23/30] CCM-11586: forgot to save --- .../components/api/s3_bucket_truststore.tf | 60 +++++++++---------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/infrastructure/terraform/components/api/s3_bucket_truststore.tf b/infrastructure/terraform/components/api/s3_bucket_truststore.tf index 97939348..8f82c931 100644 --- a/infrastructure/terraform/components/api/s3_bucket_truststore.tf +++ b/infrastructure/terraform/components/api/s3_bucket_truststore.tf @@ -44,42 +44,38 @@ resource "aws_s3_bucket_public_access_block" "truststore" { restrict_public_buckets = true } -resource "aws_s3_bucket_logging" "truststore" { - bucket = aws_s3_bucket.truststore.id - - target_bucket = aws_s3_bucket.logging.bucket - target_prefix = "${aws_s3_bucket.truststore.bucket}/" -} - -# In manually configured (e.g. dev main, nonprod main, prod main) add lifecycle policy to permit manual management of cert -resource "aws_s3_object" "placeholder_truststore" { - count = var.manually_configure_mtls_truststore ? 1 : 0 - bucket = aws_s3_bucket.truststore.bucket - key = "truststore.pem" - content = module.supplier_ssl[0].cacert_pem +data "aws_iam_policy_document" "truststore" { + statement { + effect = "Deny" + actions = ["s3:*"] + resources = [ + aws_s3_bucket.truststore.arn, + "${aws_s3_bucket.truststore.arn}/*", + ] - depends_on = [ - aws_s3_bucket_versioning.truststore, - module.supplier_ssl - ] + principals { + type = "AWS" + identifiers = ["*"] + } - lifecycle { - ignore_changes = [ - content - ] + condition { + test = "Bool" + variable = "aws:SecureTransport" + values = [ + false + ] + } } } -# In non-manually configured env (e.g. PR) exclude lifecycle policy so resources are managed -# Requires duplicate block as lifecycle policies cannot be dynamic -resource "aws_s3_object" "placeholder_truststore_nonprod" { - count = !var.manually_configure_mtls_truststore ? 1 : 0 - bucket = aws_s3_bucket.truststore.bucket - key = "truststore.pem" - content = module.supplier_ssl[0].cacert_pem +resource "aws_s3_bucket_policy" "truststore" { + bucket = aws_s3_bucket.truststore.id + policy = data.aws_iam_policy_document.truststore.json +} - depends_on = [ - aws_s3_bucket_versioning.truststore, - module.supplier_ssl - ] +resource "aws_s3_bucket_logging" "truststore" { + bucket = aws_s3_bucket.truststore.id + + target_bucket = aws_s3_bucket.logging.bucket + target_prefix = "${aws_s3_bucket.truststore.bucket}/" } From a23d453f3ff46abccb308bf184934b669f1d58eb Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Wed, 20 Aug 2025 16:14:28 +0100 Subject: [PATCH 24/30] CCM-11586: version log bucket --- .../terraform/components/api/s3_bucket_logging.tf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/infrastructure/terraform/components/api/s3_bucket_logging.tf b/infrastructure/terraform/components/api/s3_bucket_logging.tf index 9afb14f5..55f9fddb 100644 --- a/infrastructure/terraform/components/api/s3_bucket_logging.tf +++ b/infrastructure/terraform/components/api/s3_bucket_logging.tf @@ -23,6 +23,14 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "logging" { } } +resource "aws_s3_bucket_versioning" "logging" { + bucket = aws_s3_bucket.logging.id + + versioning_configuration { + status = "Enabled" + } +} + resource "aws_s3_bucket_public_access_block" "logging" { depends_on = [ aws_s3_bucket_policy.logging From 7112ad2433e44d009c45862c1233ad68e78b4ed6 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Thu, 21 Aug 2025 14:31:11 +0100 Subject: [PATCH 25/30] CCM-11586: use shared s3 module; always gen dummy certs --- .../terraform/components/api/README.md | 2 + .../api/module_domain_truststore.tf | 23 +++++ .../components/api/module_logging_bucket.tf | 35 ++++++++ .../components/api/module_supplier_ssl.tf | 2 - .../components/api/s3_bucket_logging.tf | 90 ------------------- .../components/api/s3_bucket_truststore.tf | 81 ----------------- 6 files changed, 60 insertions(+), 173 deletions(-) create mode 100644 infrastructure/terraform/components/api/module_domain_truststore.tf create mode 100644 infrastructure/terraform/components/api/module_logging_bucket.tf delete mode 100644 infrastructure/terraform/components/api/s3_bucket_logging.tf delete mode 100644 infrastructure/terraform/components/api/s3_bucket_truststore.tf diff --git a/infrastructure/terraform/components/api/README.md b/infrastructure/terraform/components/api/README.md index 6314d73b..22b6d196 100644 --- a/infrastructure/terraform/components/api/README.md +++ b/infrastructure/terraform/components/api/README.md @@ -29,9 +29,11 @@ No requirements. | Name | Source | Version | |------|--------|---------| | [authorizer\_lambda](#module\_authorizer\_lambda) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda | v2.0.4 | +| [domain\_truststore](#module\_domain\_truststore) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/s3bucket | v2.0.17 | | [get\_letters](#module\_get\_letters) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda | v2.0.10 | | [hello\_world](#module\_hello\_world) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda | v2.0.10 | | [kms](#module\_kms) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/kms | v2.0.10 | +| [logging\_bucket](#module\_logging\_bucket) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/s3bucket | v2.0.17 | | [patch\_letters](#module\_patch\_letters) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda | v2.0.10 | | [supplier\_ssl](#module\_supplier\_ssl) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/ssl | v2.0.17 | ## Outputs diff --git a/infrastructure/terraform/components/api/module_domain_truststore.tf b/infrastructure/terraform/components/api/module_domain_truststore.tf new file mode 100644 index 00000000..a9eb5e56 --- /dev/null +++ b/infrastructure/terraform/components/api/module_domain_truststore.tf @@ -0,0 +1,23 @@ +module "domain_truststore" { + source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/s3bucket?ref=v2.0.17" + + name = "${local.csi_s3}-truststore" + aws_account_id = var.aws_account_id + component = var.component + environment = var.environment + project = var.project + region = var.region + + default_tags = merge(local.default_tags, { "Enable-Backup" = var.enable_backups }, { "Enable-S3-Continuous-Backup" = var.enable_backups }, { "SKIP_S3_AUDIT" = "true" }) + kms_key_arn = module.kms.key_id + + bucket_logging_target = { + bucket = module.logging_bucket.bucket + prefix = "${name}/" + } + + policy_documents = [ + aws_iam_policy_document.truststore.json + ] + +} diff --git a/infrastructure/terraform/components/api/module_logging_bucket.tf b/infrastructure/terraform/components/api/module_logging_bucket.tf new file mode 100644 index 00000000..0fa838e8 --- /dev/null +++ b/infrastructure/terraform/components/api/module_logging_bucket.tf @@ -0,0 +1,35 @@ +module "logging_bucket" { + source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/s3bucket?ref=v2.0.17" + + name = "${local.csi_s3}-bucket-logs" + aws_account_id = var.aws_account_id + component = var.component + environment = var.environment + project = var.project + region = var.region + + default_tags = merge(local.default_tags, { "Enable-Backup" = var.enable_backups }, { "Enable-S3-Continuous-Backup" = var.enable_backups }, { "SKIP_S3_AUDIT" = "true" }) + kms_key_arn = module.kms.key_id + + policy_documents = [ + aws_iam_policy_document.logging.json + ] +} + +data "aws_iam_policy_document" "logging" { + statement { + sid = "s3-log-delivery" + effect = "Allow" + + principals { + type = "Service" + identifiers = ["logging.s3.amazonaws.com"] + } + + actions = ["s3:PutObject"] + + resources = [ + "${aws_s3_bucket.logging.arn}/*", + ] + } +} diff --git a/infrastructure/terraform/components/api/module_supplier_ssl.tf b/infrastructure/terraform/components/api/module_supplier_ssl.tf index 07fa82ef..8c67aa20 100644 --- a/infrastructure/terraform/components/api/module_supplier_ssl.tf +++ b/infrastructure/terraform/components/api/module_supplier_ssl.tf @@ -1,8 +1,6 @@ module "supplier_ssl" { source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/ssl?ref=v2.0.17" - count = var.manually_configure_mtls_truststore ? 0 : 1 - name = "sapi_trust" aws_account_id = var.aws_account_id default_tags = local.default_tags diff --git a/infrastructure/terraform/components/api/s3_bucket_logging.tf b/infrastructure/terraform/components/api/s3_bucket_logging.tf deleted file mode 100644 index 55f9fddb..00000000 --- a/infrastructure/terraform/components/api/s3_bucket_logging.tf +++ /dev/null @@ -1,90 +0,0 @@ -resource "aws_s3_bucket" "logging" { - bucket = "${local.csi_s3}-bucket-logs" - tags = merge(local.default_tags, { "Enable-Backup" = var.enable_backups }, { "Enable-S3-Continuous-Backup" = var.enable_backups }, { "SKIP_S3_AUDIT" = "true" }) -} - -resource "aws_s3_bucket_ownership_controls" "logging" { - bucket = aws_s3_bucket.logging.id - - rule { - object_ownership = "BucketOwnerPreferred" - } -} - -resource "aws_s3_bucket_server_side_encryption_configuration" "logging" { - bucket = aws_s3_bucket.logging.id - - rule { - apply_server_side_encryption_by_default { - sse_algorithm = "aws:kms" - kms_master_key_id = module.kms.key_id - } - bucket_key_enabled = true - } -} - -resource "aws_s3_bucket_versioning" "logging" { - bucket = aws_s3_bucket.logging.id - - versioning_configuration { - status = "Enabled" - } -} - -resource "aws_s3_bucket_public_access_block" "logging" { - depends_on = [ - aws_s3_bucket_policy.logging - ] - - bucket = aws_s3_bucket.logging.id - - block_public_acls = true - block_public_policy = true - ignore_public_acls = true - restrict_public_buckets = true -} - -data "aws_iam_policy_document" "logging" { - statement { - effect = "Deny" - actions = ["s3:*"] - resources = [ - aws_s3_bucket.logging.arn, - "${aws_s3_bucket.logging.arn}/*", - ] - - principals { - type = "AWS" - identifiers = ["*"] - } - - condition { - test = "Bool" - variable = "aws:SecureTransport" - values = [ - false - ] - } - } - - statement { - sid = "s3-log-delivery" - effect = "Allow" - - principals { - type = "Service" - identifiers = ["logging.s3.amazonaws.com"] - } - - actions = ["s3:PutObject"] - - resources = [ - "${aws_s3_bucket.logging.arn}/*", - ] - } -} - -resource "aws_s3_bucket_policy" "logging" { - bucket = aws_s3_bucket.logging.id - policy = data.aws_iam_policy_document.logging.json -} diff --git a/infrastructure/terraform/components/api/s3_bucket_truststore.tf b/infrastructure/terraform/components/api/s3_bucket_truststore.tf deleted file mode 100644 index 8f82c931..00000000 --- a/infrastructure/terraform/components/api/s3_bucket_truststore.tf +++ /dev/null @@ -1,81 +0,0 @@ -resource "aws_s3_bucket" "truststore" { - bucket = "${local.csi_s3}-truststore" - tags = merge(local.default_tags, { "Enable-Backup" = var.enable_backups }, { "Enable-S3-Continuous-Backup" = var.enable_backups }, { "SKIP_S3_AUDIT" = "true" }) -} - -resource "aws_s3_bucket_ownership_controls" "truststore" { - bucket = aws_s3_bucket.truststore.id - - rule { - object_ownership = "BucketOwnerPreferred" - } -} - -resource "aws_s3_bucket_server_side_encryption_configuration" "truststore" { - bucket = aws_s3_bucket.truststore.id - - rule { - apply_server_side_encryption_by_default { - sse_algorithm = "aws:kms" - kms_master_key_id = module.kms.key_id - } - bucket_key_enabled = true - } -} - -resource "aws_s3_bucket_versioning" "truststore" { - bucket = aws_s3_bucket.truststore.id - - versioning_configuration { - status = "Enabled" - } -} - -resource "aws_s3_bucket_public_access_block" "truststore" { - depends_on = [ - aws_s3_bucket_policy.truststore - ] - - bucket = aws_s3_bucket.truststore.id - - block_public_acls = true - block_public_policy = true - ignore_public_acls = true - restrict_public_buckets = true -} - -data "aws_iam_policy_document" "truststore" { - statement { - effect = "Deny" - actions = ["s3:*"] - resources = [ - aws_s3_bucket.truststore.arn, - "${aws_s3_bucket.truststore.arn}/*", - ] - - principals { - type = "AWS" - identifiers = ["*"] - } - - condition { - test = "Bool" - variable = "aws:SecureTransport" - values = [ - false - ] - } - } -} - -resource "aws_s3_bucket_policy" "truststore" { - bucket = aws_s3_bucket.truststore.id - policy = data.aws_iam_policy_document.truststore.json -} - -resource "aws_s3_bucket_logging" "truststore" { - bucket = aws_s3_bucket.truststore.id - - target_bucket = aws_s3_bucket.logging.bucket - target_prefix = "${aws_s3_bucket.truststore.bucket}/" -} From dc0ef789194ff6ddcdd6fbff25cbe6d0ec1f99c5 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Thu, 21 Aug 2025 14:44:26 +0100 Subject: [PATCH 26/30] CCM-11586: Correct references to new modules --- .../terraform/components/api/module_domain_truststore.tf | 3 +-- .../terraform/components/api/module_logging_bucket.tf | 4 ++-- .../components/api/s3_bucket_object_truststore.tf | 8 ++++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/infrastructure/terraform/components/api/module_domain_truststore.tf b/infrastructure/terraform/components/api/module_domain_truststore.tf index a9eb5e56..94cdb6c1 100644 --- a/infrastructure/terraform/components/api/module_domain_truststore.tf +++ b/infrastructure/terraform/components/api/module_domain_truststore.tf @@ -13,11 +13,10 @@ module "domain_truststore" { bucket_logging_target = { bucket = module.logging_bucket.bucket - prefix = "${name}/" + prefix = "${local.csi_s3}-truststore/" } policy_documents = [ - aws_iam_policy_document.truststore.json ] } diff --git a/infrastructure/terraform/components/api/module_logging_bucket.tf b/infrastructure/terraform/components/api/module_logging_bucket.tf index 0fa838e8..bee39ff4 100644 --- a/infrastructure/terraform/components/api/module_logging_bucket.tf +++ b/infrastructure/terraform/components/api/module_logging_bucket.tf @@ -12,7 +12,7 @@ module "logging_bucket" { kms_key_arn = module.kms.key_id policy_documents = [ - aws_iam_policy_document.logging.json + data.aws_iam_policy_document.logging.json ] } @@ -29,7 +29,7 @@ data "aws_iam_policy_document" "logging" { actions = ["s3:PutObject"] resources = [ - "${aws_s3_bucket.logging.arn}/*", + "${module.logging_bucket.arn}/*", ] } } diff --git a/infrastructure/terraform/components/api/s3_bucket_object_truststore.tf b/infrastructure/terraform/components/api/s3_bucket_object_truststore.tf index a5db4b69..69e82e02 100644 --- a/infrastructure/terraform/components/api/s3_bucket_object_truststore.tf +++ b/infrastructure/terraform/components/api/s3_bucket_object_truststore.tf @@ -1,12 +1,12 @@ # In manually configured (e.g. dev main, nonprod main, prod main) add lifecycle policy to permit manual management of cert resource "aws_s3_object" "placeholder_truststore" { count = var.manually_configure_mtls_truststore ? 1 : 0 - bucket = aws_s3_bucket.truststore.bucket + bucket = module.domain_truststore.bucket key = "truststore.pem" content = module.supplier_ssl[0].cacert_pem depends_on = [ - aws_s3_bucket_versioning.truststore, + module.domain_truststore, module.supplier_ssl ] @@ -21,12 +21,12 @@ resource "aws_s3_object" "placeholder_truststore" { # Requires duplicate block as lifecycle policies cannot be dynamic resource "aws_s3_object" "placeholder_truststore_nonprod" { count = !var.manually_configure_mtls_truststore ? 1 : 0 - bucket = aws_s3_bucket.truststore.bucket + bucket = module.domain_truststore.bucket key = "truststore.pem" content = module.supplier_ssl[0].cacert_pem depends_on = [ - aws_s3_bucket_versioning.truststore, + module.domain_truststore, module.supplier_ssl ] } From 7517345c4e87225cb40d2ada4ac11c47bdf192e6 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Thu, 21 Aug 2025 14:49:36 +0100 Subject: [PATCH 27/30] CCM-11586: Correct references to new modules --- .../terraform/components/api/api_gateway_domain.tf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/infrastructure/terraform/components/api/api_gateway_domain.tf b/infrastructure/terraform/components/api/api_gateway_domain.tf index c68b5ee1..56113805 100644 --- a/infrastructure/terraform/components/api/api_gateway_domain.tf +++ b/infrastructure/terraform/components/api/api_gateway_domain.tf @@ -9,12 +9,12 @@ resource "aws_api_gateway_domain_name" "main" { } depends_on = [ - aws_s3_bucket.truststore, + module.domain_truststore, aws_s3_object.placeholder_truststore ] mutual_tls_authentication { - truststore_uri = "s3://${aws_s3_bucket.truststore.id}/${aws_s3_object.placeholder_truststore[0].key}" + truststore_uri = "s3://${module.domain_truststore.id}/${aws_s3_object.placeholder_truststore[0].key}" truststore_version = aws_s3_object.placeholder_truststore[0].version_id } @@ -36,12 +36,12 @@ resource "aws_api_gateway_domain_name" "main_nonprod" { } depends_on = [ - aws_s3_bucket.truststore, + module.domain_truststore, aws_s3_object.placeholder_truststore_nonprod ] mutual_tls_authentication { - truststore_uri = "s3://${aws_s3_bucket.truststore.id}/${aws_s3_object.placeholder_truststore_nonprod[0].key}" + truststore_uri = "s3://${module.domain_truststore.id}/${aws_s3_object.placeholder_truststore_nonprod[0].key}" truststore_version = aws_s3_object.placeholder_truststore_nonprod[0].version_id } } From 381eb33644cecf8d691fbfaa0fc8f3f4666b734b Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Thu, 21 Aug 2025 14:54:24 +0100 Subject: [PATCH 28/30] CCM-11586: Correct references to new modules --- infrastructure/terraform/components/api/locals.tf | 12 ------------ .../components/api/module_domain_truststore.tf | 4 ++-- .../components/api/module_logging_bucket.tf | 2 +- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/infrastructure/terraform/components/api/locals.tf b/infrastructure/terraform/components/api/locals.tf index 851ad443..5400579d 100644 --- a/infrastructure/terraform/components/api/locals.tf +++ b/infrastructure/terraform/components/api/locals.tf @@ -14,16 +14,4 @@ locals { }) destination_arn = "arn:aws:logs:${var.region}:${var.shared_infra_account_id}:destination:nhs-main-obs-firehose-logs" - - csi_s3 = replace( - format( - "%s-%s-%s-%s", - var.project, - var.aws_account_id, - var.region, - var.environment - ), - "_", - "", - ) } diff --git a/infrastructure/terraform/components/api/module_domain_truststore.tf b/infrastructure/terraform/components/api/module_domain_truststore.tf index 94cdb6c1..f502b384 100644 --- a/infrastructure/terraform/components/api/module_domain_truststore.tf +++ b/infrastructure/terraform/components/api/module_domain_truststore.tf @@ -1,7 +1,7 @@ module "domain_truststore" { source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/s3bucket?ref=v2.0.17" - name = "${local.csi_s3}-truststore" + name = "truststore" aws_account_id = var.aws_account_id component = var.component environment = var.environment @@ -13,7 +13,7 @@ module "domain_truststore" { bucket_logging_target = { bucket = module.logging_bucket.bucket - prefix = "${local.csi_s3}-truststore/" + prefix = "truststore/" } policy_documents = [ diff --git a/infrastructure/terraform/components/api/module_logging_bucket.tf b/infrastructure/terraform/components/api/module_logging_bucket.tf index bee39ff4..c5a6073e 100644 --- a/infrastructure/terraform/components/api/module_logging_bucket.tf +++ b/infrastructure/terraform/components/api/module_logging_bucket.tf @@ -1,7 +1,7 @@ module "logging_bucket" { source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/s3bucket?ref=v2.0.17" - name = "${local.csi_s3}-bucket-logs" + name = "bucket-logs" aws_account_id = var.aws_account_id component = var.component environment = var.environment From a7a6cae258f7342838f3c14595d7e1e3bfe79441 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Thu, 21 Aug 2025 14:59:14 +0100 Subject: [PATCH 29/30] CCM-11586: SSL module always present for dummies --- ...ject_truststore.tf => s3_object_placeholder_truststore.tf} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename infrastructure/terraform/components/api/{s3_bucket_object_truststore.tf => s3_object_placeholder_truststore.tf} (90%) diff --git a/infrastructure/terraform/components/api/s3_bucket_object_truststore.tf b/infrastructure/terraform/components/api/s3_object_placeholder_truststore.tf similarity index 90% rename from infrastructure/terraform/components/api/s3_bucket_object_truststore.tf rename to infrastructure/terraform/components/api/s3_object_placeholder_truststore.tf index 69e82e02..b4d1f85a 100644 --- a/infrastructure/terraform/components/api/s3_bucket_object_truststore.tf +++ b/infrastructure/terraform/components/api/s3_object_placeholder_truststore.tf @@ -3,7 +3,7 @@ resource "aws_s3_object" "placeholder_truststore" { count = var.manually_configure_mtls_truststore ? 1 : 0 bucket = module.domain_truststore.bucket key = "truststore.pem" - content = module.supplier_ssl[0].cacert_pem + content = module.supplier_ssl.cacert_pem depends_on = [ module.domain_truststore, @@ -23,7 +23,7 @@ resource "aws_s3_object" "placeholder_truststore_nonprod" { count = !var.manually_configure_mtls_truststore ? 1 : 0 bucket = module.domain_truststore.bucket key = "truststore.pem" - content = module.supplier_ssl[0].cacert_pem + content = module.supplier_ssl.cacert_pem depends_on = [ module.domain_truststore, From 706dbd05c575c97945588b6044a6aaa1f2ffb3e5 Mon Sep 17 00:00:00 2001 From: "mark.slowey1" Date: Thu, 21 Aug 2025 15:26:47 +0100 Subject: [PATCH 30/30] CCM-11586: additional tags not needed --- .../terraform/components/api/module_domain_truststore.tf | 2 +- .../terraform/components/api/module_logging_bucket.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/terraform/components/api/module_domain_truststore.tf b/infrastructure/terraform/components/api/module_domain_truststore.tf index f502b384..d1fa221e 100644 --- a/infrastructure/terraform/components/api/module_domain_truststore.tf +++ b/infrastructure/terraform/components/api/module_domain_truststore.tf @@ -8,7 +8,7 @@ module "domain_truststore" { project = var.project region = var.region - default_tags = merge(local.default_tags, { "Enable-Backup" = var.enable_backups }, { "Enable-S3-Continuous-Backup" = var.enable_backups }, { "SKIP_S3_AUDIT" = "true" }) + default_tags = local.default_tags kms_key_arn = module.kms.key_id bucket_logging_target = { diff --git a/infrastructure/terraform/components/api/module_logging_bucket.tf b/infrastructure/terraform/components/api/module_logging_bucket.tf index c5a6073e..1acd9836 100644 --- a/infrastructure/terraform/components/api/module_logging_bucket.tf +++ b/infrastructure/terraform/components/api/module_logging_bucket.tf @@ -8,7 +8,7 @@ module "logging_bucket" { project = var.project region = var.region - default_tags = merge(local.default_tags, { "Enable-Backup" = var.enable_backups }, { "Enable-S3-Continuous-Backup" = var.enable_backups }, { "SKIP_S3_AUDIT" = "true" }) + default_tags = local.default_tags kms_key_arn = module.kms.key_id policy_documents = [