Skip to content

Commit fe63c53

Browse files
authored
CCM-11586: Enable mTLS on API GW (#119)
* CCM-11586: initial truststore * CCM-11586: group is invalid prop * CCM-11586: missing name * CCM-11586: store ref not indexed * CCM-11586: store ref not indexed * CCM-11586: cert references * CCM-11586: domain store refs * CCM-11586: domain name lifecycles * CCM-11586: more tf refs * CCM-11586: domain name lifecycles * CCM-11586: more sensible route53 config * CCM-11586: correct name reference * CCM-11586: correct locals csis3 def * CCM-11586: change csi to meet s3 naming convention * CCM-11586: remove config variable, reference infra * CCM-11586: centralised bucket logging, define a bucket * CCM-11586: try fix truststore uri * CCM-11586: Disable execute-api endpoint * CCM-11586: secure logging bucket * CCM-11586: refine logging bucket policies * CCM-11586: does consolidation make sonar happy * CCM-11586: consolidation does make sonar happy * CCM-11586: forgot to save * CCM-11586: version log bucket * CCM-11586: use shared s3 module; always gen dummy certs * CCM-11586: Correct references to new modules * CCM-11586: Correct references to new modules * CCM-11586: Correct references to new modules * CCM-11586: SSL module always present for dummies * CCM-11586: additional tags not needed
1 parent edd08ec commit fe63c53

File tree

10 files changed

+161
-4
lines changed

10 files changed

+161
-4
lines changed

infrastructure/terraform/components/api/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ No requirements.
1212
| <a name="input_aws_account_id"></a> [aws\_account\_id](#input\_aws\_account\_id) | The AWS Account ID (numeric) | `string` | n/a | yes |
1313
| <a name="input_component"></a> [component](#input\_component) | The variable encapsulating the name of this component | `string` | `"supapi"` | no |
1414
| <a name="input_default_tags"></a> [default\_tags](#input\_default\_tags) | A map of default tags to apply to all taggable resources within the component | `map(string)` | `{}` | no |
15+
| <a name="input_enable_backups"></a> [enable\_backups](#input\_enable\_backups) | Enable backups | `bool` | `false` | no |
1516
| <a name="input_environment"></a> [environment](#input\_environment) | The name of the tfscaffold environment | `string` | n/a | yes |
1617
| <a name="input_force_lambda_code_deploy"></a> [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 |
1718
| <a name="input_group"></a> [group](#input\_group) | The group variables are being inherited from (often synonmous with account short-name) | `string` | n/a | yes |
1819
| <a name="input_kms_deletion_window"></a> [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 |
1920
| <a name="input_log_level"></a> [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 |
2021
| <a name="input_log_retention_in_days"></a> [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 |
22+
| <a name="input_manually_configure_mtls_truststore"></a> [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 |
2123
| <a name="input_parent_acct_environment"></a> [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 |
2224
| <a name="input_project"></a> [project](#input\_project) | The name of the tfscaffold project | `string` | n/a | yes |
2325
| <a name="input_region"></a> [region](#input\_region) | The AWS Region | `string` | n/a | yes |
@@ -27,10 +29,13 @@ No requirements.
2729
| Name | Source | Version |
2830
|------|--------|---------|
2931
| <a name="module_authorizer_lambda"></a> [authorizer\_lambda](#module\_authorizer\_lambda) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda | v2.0.4 |
32+
| <a name="module_domain_truststore"></a> [domain\_truststore](#module\_domain\_truststore) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/s3bucket | v2.0.17 |
3033
| <a name="module_get_letters"></a> [get\_letters](#module\_get\_letters) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda | v2.0.10 |
3134
| <a name="module_hello_world"></a> [hello\_world](#module\_hello\_world) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda | v2.0.10 |
3235
| <a name="module_kms"></a> [kms](#module\_kms) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/kms | v2.0.10 |
36+
| <a name="module_logging_bucket"></a> [logging\_bucket](#module\_logging\_bucket) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/s3bucket | v2.0.17 |
3337
| <a name="module_patch_letters"></a> [patch\_letters](#module\_patch\_letters) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/lambda | v2.0.10 |
38+
| <a name="module_supplier_ssl"></a> [supplier\_ssl](#module\_supplier\_ssl) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/ssl | v2.0.17 |
3439
## Outputs
3540

3641
| Name | Description |
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
resource "aws_api_gateway_base_path_mapping" "main" {
22
api_id = aws_api_gateway_rest_api.main.id
33
stage_name = aws_api_gateway_stage.main.stage_name
4-
domain_name = aws_api_gateway_domain_name.main.domain_name
4+
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
55
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,47 @@
11
resource "aws_api_gateway_domain_name" "main" {
2+
count = var.manually_configure_mtls_truststore ? 1 : 0
23
regional_certificate_arn = aws_acm_certificate_validation.main.certificate_arn
34
domain_name = local.root_domain_name
45
security_policy = "TLS_1_2"
56

67
endpoint_configuration {
78
types = ["REGIONAL"]
89
}
10+
11+
depends_on = [
12+
module.domain_truststore,
13+
aws_s3_object.placeholder_truststore
14+
]
15+
16+
mutual_tls_authentication {
17+
truststore_uri = "s3://${module.domain_truststore.id}/${aws_s3_object.placeholder_truststore[0].key}"
18+
truststore_version = aws_s3_object.placeholder_truststore[0].version_id
19+
}
20+
21+
lifecycle {
22+
ignore_changes = [
23+
mutual_tls_authentication
24+
]
25+
}
26+
}
27+
28+
resource "aws_api_gateway_domain_name" "main_nonprod" {
29+
count = !var.manually_configure_mtls_truststore ? 1 : 0
30+
regional_certificate_arn = aws_acm_certificate_validation.main.certificate_arn
31+
domain_name = local.root_domain_name
32+
security_policy = "TLS_1_2"
33+
34+
endpoint_configuration {
35+
types = ["REGIONAL"]
36+
}
37+
38+
depends_on = [
39+
module.domain_truststore,
40+
aws_s3_object.placeholder_truststore_nonprod
41+
]
42+
43+
mutual_tls_authentication {
44+
truststore_uri = "s3://${module.domain_truststore.id}/${aws_s3_object.placeholder_truststore_nonprod[0].key}"
45+
truststore_version = aws_s3_object.placeholder_truststore_nonprod[0].version_id
46+
}
947
}

infrastructure/terraform/components/api/api_gateway_rest_api.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ resource "aws_api_gateway_rest_api" "main" {
22
name = local.csi
33
body = local.openapi_spec
44
description = "Suppliers API"
5+
disable_execute_api_endpoint = true
56
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module "domain_truststore" {
2+
source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/s3bucket?ref=v2.0.17"
3+
4+
name = "truststore"
5+
aws_account_id = var.aws_account_id
6+
component = var.component
7+
environment = var.environment
8+
project = var.project
9+
region = var.region
10+
11+
default_tags = local.default_tags
12+
kms_key_arn = module.kms.key_id
13+
14+
bucket_logging_target = {
15+
bucket = module.logging_bucket.bucket
16+
prefix = "truststore/"
17+
}
18+
19+
policy_documents = [
20+
]
21+
22+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module "logging_bucket" {
2+
source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/s3bucket?ref=v2.0.17"
3+
4+
name = "bucket-logs"
5+
aws_account_id = var.aws_account_id
6+
component = var.component
7+
environment = var.environment
8+
project = var.project
9+
region = var.region
10+
11+
default_tags = local.default_tags
12+
kms_key_arn = module.kms.key_id
13+
14+
policy_documents = [
15+
data.aws_iam_policy_document.logging.json
16+
]
17+
}
18+
19+
data "aws_iam_policy_document" "logging" {
20+
statement {
21+
sid = "s3-log-delivery"
22+
effect = "Allow"
23+
24+
principals {
25+
type = "Service"
26+
identifiers = ["logging.s3.amazonaws.com"]
27+
}
28+
29+
actions = ["s3:PutObject"]
30+
31+
resources = [
32+
"${module.logging_bucket.arn}/*",
33+
]
34+
}
35+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module "supplier_ssl" {
2+
source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/ssl?ref=v2.0.17"
3+
4+
name = "sapi_trust"
5+
aws_account_id = var.aws_account_id
6+
default_tags = local.default_tags
7+
component = var.component
8+
environment = var.environment
9+
project = var.project
10+
region = var.region
11+
subject_common_name = local.root_domain_name
12+
}

infrastructure/terraform/components/api/route53_record.tf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
resource "aws_route53_record" "main" {
2-
name = aws_api_gateway_domain_name.main.domain_name
2+
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
33
type = "A"
44
zone_id = local.root_domain_id
55

66
alias {
7-
name = aws_api_gateway_domain_name.main.regional_domain_name
8-
zone_id = aws_api_gateway_domain_name.main.regional_zone_id
7+
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
8+
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
99

1010
evaluate_target_health = true
1111
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# In manually configured (e.g. dev main, nonprod main, prod main) add lifecycle policy to permit manual management of cert
2+
resource "aws_s3_object" "placeholder_truststore" {
3+
count = var.manually_configure_mtls_truststore ? 1 : 0
4+
bucket = module.domain_truststore.bucket
5+
key = "truststore.pem"
6+
content = module.supplier_ssl.cacert_pem
7+
8+
depends_on = [
9+
module.domain_truststore,
10+
module.supplier_ssl
11+
]
12+
13+
lifecycle {
14+
ignore_changes = [
15+
content
16+
]
17+
}
18+
}
19+
20+
# In non-manually configured env (e.g. PR) exclude lifecycle policy so resources are managed
21+
# Requires duplicate block as lifecycle policies cannot be dynamic
22+
resource "aws_s3_object" "placeholder_truststore_nonprod" {
23+
count = !var.manually_configure_mtls_truststore ? 1 : 0
24+
bucket = module.domain_truststore.bucket
25+
key = "truststore.pem"
26+
content = module.supplier_ssl.cacert_pem
27+
28+
depends_on = [
29+
module.domain_truststore,
30+
module.supplier_ssl
31+
]
32+
}

infrastructure/terraform/components/api/variables.tf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,15 @@ variable "shared_infra_account_id" {
8686
description = "The AWS Account ID of the shared infrastructure account"
8787
default = "000000000000"
8888
}
89+
90+
variable "manually_configure_mtls_truststore" {
91+
type = bool
92+
description = "Manually manage the truststore used for API Gateway mTLS (e.g. for prod environment)"
93+
default = false
94+
}
95+
96+
variable "enable_backups" {
97+
type = bool
98+
description = "Enable backups"
99+
default = false
100+
}

0 commit comments

Comments
 (0)