diff --git a/infrastructure/terraform/components/api/README.md b/infrastructure/terraform/components/api/README.md
index 2d902e03..22b6d196 100644
--- a/infrastructure/terraform/components/api/README.md
+++ b/infrastructure/terraform/components/api/README.md
@@ -12,12 +12,14 @@ 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 |
@@ -27,10 +29,13 @@ 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
| Name | Description |
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 27808578..56113805 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"
@@ -6,4 +7,41 @@ resource "aws_api_gateway_domain_name" "main" {
endpoint_configuration {
types = ["REGIONAL"]
}
+
+ depends_on = [
+ module.domain_truststore,
+ aws_s3_object.placeholder_truststore
+ ]
+
+ mutual_tls_authentication {
+ truststore_uri = "s3://${module.domain_truststore.id}/${aws_s3_object.placeholder_truststore[0].key}"
+ truststore_version = aws_s3_object.placeholder_truststore[0].version_id
+ }
+
+ lifecycle {
+ 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 = [
+ module.domain_truststore,
+ aws_s3_object.placeholder_truststore_nonprod
+ ]
+
+ mutual_tls_authentication {
+ 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
+ }
}
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
}
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..d1fa221e
--- /dev/null
+++ b/infrastructure/terraform/components/api/module_domain_truststore.tf
@@ -0,0 +1,22 @@
+module "domain_truststore" {
+ source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/s3bucket?ref=v2.0.17"
+
+ name = "truststore"
+ aws_account_id = var.aws_account_id
+ component = var.component
+ environment = var.environment
+ project = var.project
+ region = var.region
+
+ default_tags = local.default_tags
+ kms_key_arn = module.kms.key_id
+
+ bucket_logging_target = {
+ bucket = module.logging_bucket.bucket
+ prefix = "truststore/"
+ }
+
+ policy_documents = [
+ ]
+
+}
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..1acd9836
--- /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 = "bucket-logs"
+ aws_account_id = var.aws_account_id
+ component = var.component
+ environment = var.environment
+ project = var.project
+ region = var.region
+
+ default_tags = local.default_tags
+ kms_key_arn = module.kms.key_id
+
+ policy_documents = [
+ data.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 = [
+ "${module.logging_bucket.arn}/*",
+ ]
+ }
+}
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..8c67aa20
--- /dev/null
+++ b/infrastructure/terraform/components/api/module_supplier_ssl.tf
@@ -0,0 +1,12 @@
+module "supplier_ssl" {
+ source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/ssl?ref=v2.0.17"
+
+ name = "sapi_trust"
+ aws_account_id = var.aws_account_id
+ default_tags = local.default_tags
+ component = var.component
+ environment = var.environment
+ project = var.project
+ region = var.region
+ subject_common_name = local.root_domain_name
+}
diff --git a/infrastructure/terraform/components/api/route53_record.tf b/infrastructure/terraform/components/api/route53_record.tf
index 0ce1d8b0..63affc80 100644
--- a/infrastructure/terraform/components/api/route53_record.tf
+++ b/infrastructure/terraform/components/api/route53_record.tf
@@ -1,11 +1,11 @@
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
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
}
diff --git a/infrastructure/terraform/components/api/s3_object_placeholder_truststore.tf b/infrastructure/terraform/components/api/s3_object_placeholder_truststore.tf
new file mode 100644
index 00000000..b4d1f85a
--- /dev/null
+++ b/infrastructure/terraform/components/api/s3_object_placeholder_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 = module.domain_truststore.bucket
+ key = "truststore.pem"
+ content = module.supplier_ssl.cacert_pem
+
+ depends_on = [
+ module.domain_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 = module.domain_truststore.bucket
+ key = "truststore.pem"
+ content = module.supplier_ssl.cacert_pem
+
+ depends_on = [
+ module.domain_truststore,
+ module.supplier_ssl
+ ]
+}
diff --git a/infrastructure/terraform/components/api/variables.tf b/infrastructure/terraform/components/api/variables.tf
index 51b61627..1b3b789c 100644
--- a/infrastructure/terraform/components/api/variables.tf
+++ b/infrastructure/terraform/components/api/variables.tf
@@ -86,3 +86,15 @@ 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
+}