Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions infrastructure/api-key-pdm.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
resource "aws_api_gateway_usage_plan" "api_key_pdm" {
name = "${terraform.workspace}_pdm-usage-plan"
api_stages {
api_id = aws_api_gateway_rest_api.ndr_doc_store_api.id
stage = aws_api_gateway_stage.ndr_api.stage_name
api_id = aws_api_gateway_rest_api.ndr_doc_store_api_mtls.id
stage = aws_api_gateway_stage.ndr_api_mtls.stage_name
}
}

Expand Down
133 changes: 133 additions & 0 deletions infrastructure/api_mtls.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# New API Gateway for mTLS
resource "aws_api_gateway_rest_api" "ndr_doc_store_api_mtls" {
name = "${terraform.workspace}_DocStoreApiMtls"
description = "Document store API with mTLS enabled"
disable_execute_api_endpoint = true

endpoint_configuration {
types = ["REGIONAL"]
}

tags = {
Name = "${terraform.workspace}_DocStoreApiMtls"
}
}

resource "aws_api_gateway_domain_name" "custom_api_domain_mtls" {
domain_name = local.mtls_api_gateway_full_domain_name
regional_certificate_arn = aws_acm_certificate_validation.mtls_api_gateway_cert.certificate_arn
security_policy = "TLS_1_2"

endpoint_configuration {
types = ["REGIONAL"]
}

mutual_tls_authentication {
truststore_uri = local.truststore_uri
truststore_version = data.aws_s3_object.truststore_ext_cert.version_id
}
}

resource "aws_api_gateway_base_path_mapping" "api_mapping_mtls" {
api_id = aws_api_gateway_rest_api.ndr_doc_store_api_mtls.id
stage_name = var.environment
domain_name = aws_api_gateway_domain_name.custom_api_domain_mtls.domain_name

depends_on = [aws_api_gateway_deployment.ndr_api_deploy_mtls]
}

resource "aws_api_gateway_deployment" "ndr_api_deploy_mtls" {
rest_api_id = aws_api_gateway_rest_api.ndr_doc_store_api_mtls.id

depends_on = [
aws_api_gateway_rest_api.ndr_doc_store_api_mtls,
aws_api_gateway_resource.get_document_reference_mtls,
module.get-doc-fhir-lambda,
aws_api_gateway_integration.get_doc_fhir_lambda_integration,
aws_lambda_permission.lambda_permission_get_mtls_api,
module.post-document-references-fhir-lambda,
aws_api_gateway_integration.post_doc_fhir_lambda_integration,
aws_lambda_permission.lambda_permission_post_mtls_api,
module.search-document-references-fhir-lambda,
aws_api_gateway_integration.search_doc_fhir_lambda_integration,
aws_lambda_permission.lambda_permission_search_mtls_api,
]

lifecycle {
create_before_destroy = true
}

variables = {
deployed_at = timestamp()
}
}

resource "aws_api_gateway_stage" "ndr_api_mtls" {
deployment_id = aws_api_gateway_deployment.ndr_api_deploy_mtls.id
rest_api_id = aws_api_gateway_rest_api.ndr_doc_store_api_mtls.id
stage_name = var.environment
xray_tracing_enabled = var.enable_xray_tracing
}

resource "aws_cloudwatch_log_group" "mtls_api_gateway_stage" {
name = "API-Gateway-Execution-Logs_${aws_api_gateway_rest_api.ndr_doc_store_api_mtls.id}/${var.environment}"
retention_in_days = 0
depends_on = [
aws_api_gateway_account.logging
]
}

resource "aws_api_gateway_method_settings" "mtls_api_gateway_stage" {
rest_api_id = aws_api_gateway_rest_api.ndr_doc_store_api_mtls.id
stage_name = aws_api_gateway_stage.ndr_api_mtls.stage_name
method_path = "*/*"

settings {
logging_level = "INFO"
metrics_enabled = true
data_trace_enabled = true
}
}

resource "aws_api_gateway_gateway_response" "unauthorised_response_mtls" {
rest_api_id = aws_api_gateway_rest_api.ndr_doc_store_api_mtls.id
response_type = "DEFAULT_4XX"

response_templates = {
"application/json" = "{\"message\":$context.error.messageString}"
}

response_parameters = {
"gatewayresponse.header.Access-Control-Allow-Origin" = contains(["prod"], terraform.workspace) ? "'https://${var.domain}'" : "'https://${terraform.workspace}.${var.domain}'"
"gatewayresponse.header.Access-Control-Allow-Methods" = "'*'"
"gatewayresponse.header.Access-Control-Allow-Headers" = "'Content-Type,X-Amz-Date,Authorization,X-Auth,X-Api-Key,X-Amz-Security-Token,X-Auth-Cookie,Accept'"
"gatewayresponse.header.Access-Control-Allow-Credentials" = "'true'"
}
}

resource "aws_api_gateway_gateway_response" "bad_gateway_response_mtls" {
rest_api_id = aws_api_gateway_rest_api.ndr_doc_store_api_mtls.id
response_type = "DEFAULT_5XX"

response_templates = {
"application/json" = "{\"message\":$context.error.messageString}"
}

response_parameters = {
"gatewayresponse.header.Access-Control-Allow-Origin" = contains(["prod"], terraform.workspace) ? "'https://${var.domain}'" : "'https://${terraform.workspace}.${var.domain}'"
"gatewayresponse.header.Access-Control-Allow-Methods" = "'*'"
"gatewayresponse.header.Access-Control-Allow-Headers" = "'Content-Type,X-Amz-Date,Authorization,X-Auth,X-Api-Key,X-Amz-Security-Token,X-Auth-Cookie,Accept'"
"gatewayresponse.header.Access-Control-Allow-Credentials" = "'true'"
}
}

module "mtls_api_endpoint_url_ssm_parameter" {
source = "./modules/ssm_parameter"
name = "${terraform.workspace}_ApiEndpointMtls"
description = "mTLS api endpoint URL for ${var.environment}"
resource_depends_on = aws_api_gateway_deployment.ndr_api_deploy_mtls
value = "https://${aws_api_gateway_base_path_mapping.api_mapping_mtls.domain_name}"
type = "SecureString"
owner = var.owner
environment = var.environment
}
5 changes: 5 additions & 0 deletions infrastructure/buckets.tf
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ module "ndr-truststore" {
force_destroy = local.is_force_destroy
}

data "aws_s3_object" "truststore_ext_cert" {
bucket = local.truststore_bucket_id
key = var.ca_pem_filename
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This truststore object needs to be manually created and in place before deploying

# Lifecycle Rules
resource "aws_s3_bucket_lifecycle_configuration" "lg-lifecycle-rules" {
bucket = module.ndr-lloyd-george-store.bucket_id
Expand Down
10 changes: 10 additions & 0 deletions infrastructure/gateway-document-reference-mtls.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module "fhir_document_reference_mtls_gateway" {
source = "./modules/gateway"
api_gateway_id = aws_api_gateway_rest_api.ndr_doc_store_api_mtls.id
parent_id = aws_api_gateway_rest_api.ndr_doc_store_api_mtls.root_resource_id
http_methods = ["POST", "GET"]
authorization = "NONE"
api_key_required = true
gateway_path = "DocumentReference"
require_credentials = true
}
38 changes: 38 additions & 0 deletions infrastructure/lambda-get-document-fhir.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ resource "aws_api_gateway_resource" "get_document_reference" {
path_part = "{id}"
}

resource "aws_api_gateway_resource" "get_document_reference_mtls" {
rest_api_id = aws_api_gateway_rest_api.ndr_doc_store_api_mtls.id
parent_id = module.fhir_document_reference_mtls_gateway.gateway_resource_id
path_part = "{id}"
}

resource "aws_api_gateway_method" "get_document_reference" {
rest_api_id = aws_api_gateway_rest_api.ndr_doc_store_api.id
resource_id = aws_api_gateway_resource.get_document_reference.id
Expand All @@ -15,6 +21,17 @@ resource "aws_api_gateway_method" "get_document_reference" {
}
}

resource "aws_api_gateway_method" "get_document_reference_mtls" {
rest_api_id = aws_api_gateway_rest_api.ndr_doc_store_api_mtls.id
resource_id = aws_api_gateway_resource.get_document_reference_mtls.id
http_method = "GET"
authorization = "NONE"
api_key_required = true
request_parameters = {
"method.request.path.id" = true
}
}


module "get-doc-fhir-lambda" {
source = "./modules/lambda"
Expand Down Expand Up @@ -46,3 +63,24 @@ module "get-doc-fhir-lambda" {
depends_on = [aws_api_gateway_method.get_document_reference]
}

resource "aws_api_gateway_integration" "get_doc_fhir_lambda_integration" {
rest_api_id = aws_api_gateway_rest_api.ndr_doc_store_api_mtls.id
resource_id = aws_api_gateway_resource.get_document_reference_mtls.id
http_method = "GET"
integration_http_method = "POST"
type = "AWS_PROXY"
uri = module.get-doc-fhir-lambda.invoke_arn

depends_on = [aws_api_gateway_method.get_document_reference_mtls]

}

resource "aws_lambda_permission" "lambda_permission_get_mtls_api" {
statement_id = "AllowAPImTLSGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = module.get-doc-fhir-lambda.lambda_arn
principal = "apigateway.amazonaws.com"
# The "/*/*" portion grants access from any method on any resource
# within the API Gateway REST API.
source_arn = "${aws_api_gateway_rest_api.ndr_doc_store_api_mtls.execution_arn}/*/*"
}
22 changes: 22 additions & 0 deletions infrastructure/lambda-post-document-fhir.tf
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,25 @@ module "post-document-references-fhir-lambda" {
PRESIGNED_ASSUME_ROLE = aws_iam_role.create_post_presign_url_role.arn
}
}

resource "aws_api_gateway_integration" "post_doc_fhir_lambda_integration" {
rest_api_id = aws_api_gateway_rest_api.ndr_doc_store_api_mtls.id
resource_id = module.fhir_document_reference_mtls_gateway.gateway_resource_id
http_method = "POST"
integration_http_method = "POST"
type = "AWS_PROXY"
uri = module.post-document-references-fhir-lambda.invoke_arn

depends_on = [module.fhir_document_reference_mtls_gateway]

}

resource "aws_lambda_permission" "lambda_permission_post_mtls_api" {
statement_id = "AllowAPImTLSGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = module.post-document-references-fhir-lambda.lambda_arn
principal = "apigateway.amazonaws.com"
# The "/*/*" portion grants access from any method on any resource
# within the API Gateway REST API.
source_arn = "${aws_api_gateway_rest_api.ndr_doc_store_api_mtls.execution_arn}/*/*"
}
21 changes: 21 additions & 0 deletions infrastructure/lambda-search-document-references-fhir.tf
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,24 @@ module "search-document-references-fhir-lambda" {
module.ndr-app-config
]
}

resource "aws_api_gateway_integration" "search_doc_fhir_lambda_integration" {
rest_api_id = aws_api_gateway_rest_api.ndr_doc_store_api_mtls.id
resource_id = module.fhir_document_reference_mtls_gateway.gateway_resource_id
http_method = "GET"
integration_http_method = "POST"
type = "AWS_PROXY"
uri = module.search-document-references-fhir-lambda.invoke_arn

depends_on = [module.fhir_document_reference_mtls_gateway]
}

resource "aws_lambda_permission" "lambda_permission_search_mtls_api" {
statement_id = "AllowMtlsApiGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = module.search-document-references-fhir-lambda.lambda_arn
principal = "apigateway.amazonaws.com"
# The "/*/*" portion grants access from any method on any resource
# within the API Gateway REST API.
source_arn = "${aws_api_gateway_rest_api.ndr_doc_store_api_mtls.execution_arn}/*/*"
}
12 changes: 12 additions & 0 deletions infrastructure/route53.tf
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,15 @@ module "route53_fargate_ui" {
api_gateway_full_domain_name = aws_api_gateway_domain_name.custom_api_domain.regional_domain_name
api_gateway_zone_id = aws_api_gateway_domain_name.custom_api_domain.regional_zone_id
}

resource "aws_route53_record" "ndr_mtls_api_record" {
name = aws_api_gateway_domain_name.custom_api_domain_mtls.domain_name
type = "A"
zone_id = module.route53_fargate_ui.zone_id

alias {
name = aws_api_gateway_domain_name.custom_api_domain_mtls.regional_domain_name
zone_id = aws_api_gateway_domain_name.custom_api_domain_mtls.regional_zone_id
evaluate_target_health = true
}
}
9 changes: 9 additions & 0 deletions infrastructure/variable.tf
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ variable "truststore_bucket_name" {
default = "ndr-truststore"
}

variable "ca_pem_filename" {
type = string
description = "Filename of the CA Truststore pem file stored in the core Truststore s3 bucket"
default = "ndr-truststore.pem"
}

# DynamoDB Table Variables

variable "pdm_dynamodb_table_name" {
Expand Down Expand Up @@ -232,6 +238,9 @@ locals {
current_account_id = data.aws_caller_identity.current.account_id

apim_api_url = "https://${var.apim_environment}api.service.nhs.uk/national-document-repository"

truststore_bucket_id = local.is_sandbox ? "ndr-dev-${var.truststore_bucket_name}" : module.ndr-truststore[0].bucket_id
truststore_uri = "s3://${local.truststore_bucket_id}/${var.ca_pem_filename}"
}

variable "nrl_api_endpoint_suffix" {
Expand Down