diff --git a/infrastructure/api.tf b/infrastructure/api.tf index c0cb1e1d..1c3a1431 100644 --- a/infrastructure/api.tf +++ b/infrastructure/api.tf @@ -52,43 +52,49 @@ resource "aws_api_gateway_deployment" "ndr_api_deploy" { module.create-token-gateway, module.create-token-lambda, module.delete-doc-ref-gateway, - module.delete-document-references-fhir-lambda, module.delete-doc-ref-lambda, + module.delete-document-references-fhir-lambda, + module.update_user_restriction_lambda, module.document-manifest-job-gateway, module.document-manifest-job-lambda, module.document_reference_gateway, + module.document-status-check-gateway, + module.document-status-check-lambda, module.feature-flags-gateway, module.feature-flags-lambda, module.fhir_document_reference_gateway, module.get-doc-fhir-lambda, - module.get_document_review_lambda, module.get-doc-ref-lambda, + module.get_document_review_lambda, module.get-report-by-ods-gateway, module.get-report-by-ods-lambda, module.lloyd-george-stitch-gateway, module.lloyd-george-stitch-lambda, module.logout-gateway, module.logout_lambda, + module.patch_document_review_lambda, + module.post-document-references-fhir-lambda, + module.post_document_review_lambda, + module.create_user_restriction_lambda, + module.review_document_status_gateway, + module.review-document-status-check-lambda, + module.review_document_version_gateway, module.search-document-references-gateway, module.search-document-references-lambda, module.search_document_review_lambda, module.search-patient-details-gateway, module.search-patient-details-lambda, + module.get_user_information_lambda, + module.search_user_restriction_lambda, module.send-feedback-gateway, module.send-feedback-lambda, - module.review_document_version_gateway, - module.review_document_status_gateway, - module.review-document-status-check-lambda, module.update-doc-ref-lambda, module.update-upload-state-gateway, module.update-upload-state-lambda, - module.document-status-check-gateway, - module.document-status-check-lambda, - module.post-document-references-fhir-lambda, - module.post_document_review_lambda, - module.patch_document_review_lambda, + module.user_restrictions_gateway, + module.user_restrictions_user_search_gateway, module.virus_scan_result_gateway, - module.virus_scan_result_lambda + module.virus_scan_result_lambda, ] lifecycle { diff --git a/infrastructure/dynamo_db.tf b/infrastructure/dynamo_db.tf index ec570da5..97a05065 100644 --- a/infrastructure/dynamo_db.tf +++ b/infrastructure/dynamo_db.tf @@ -590,6 +590,61 @@ module "bulk_upload_contact_lookup_table" { }, ] + environment = var.environment + owner = var.owner +} + +module "user_restriction_table" { + source = "./modules/dynamo_db" + table_name = var.user_restrictions_table_name + hash_key = "ID" + deletion_protection_enabled = var.deletion_protection_enabled + point_in_time_recovery_enabled = !local.is_sandbox + + attributes = [ + { + name = "ID" + type = "S" + }, + { + name = "RestrictedSmartcard" + type = "S" + }, + { + name = "NhsNumber" + type = "S" + }, + { + name = "Custodian" + type = "S" + }, + { + name = "Created" + type = "N" + }, + ] + + global_secondary_indexes = [ + { + name = "RestrictedSmartcardIndex" + hash_key = "RestrictedSmartcard" + range_key = "Created" + projection_type = "ALL" + }, + { + name = "NhsNumberIndex" + hash_key = "NhsNumber" + range_key = "Created" + projection_type = "ALL" + }, + { + name = "CustodianIndex" + hash_key = "Custodian" + range_key = "Created" + projection_type = "ALL" + } + ] + environment = var.environment owner = var.owner } \ No newline at end of file diff --git a/infrastructure/gateway-user-restrictions.tf b/infrastructure/gateway-user-restrictions.tf new file mode 100644 index 00000000..e8376cf1 --- /dev/null +++ b/infrastructure/gateway-user-restrictions.tf @@ -0,0 +1,39 @@ +module "user_restrictions_gateway" { + source = "./modules/gateway" + api_gateway_id = aws_api_gateway_rest_api.ndr_doc_store_api.id + parent_id = aws_api_gateway_rest_api.ndr_doc_store_api.root_resource_id + http_methods = ["GET", "POST"] + authorization = "CUSTOM" + gateway_path = "UserRestriction" + authorizer_id = aws_api_gateway_authorizer.repo_authoriser.id + require_credentials = true + origin = contains(["prod"], terraform.workspace) ? "'https://${var.domain}'" : "'https://${terraform.workspace}.${var.domain}'" +} + +module "user_restriction_id_gateway" { + source = "./modules/gateway" + api_gateway_id = aws_api_gateway_rest_api.ndr_doc_store_api.id + parent_id = module.user_restrictions_gateway.gateway_resource_id + http_methods = ["PATCH"] + gateway_path = "{id}" + authorization = "CUSTOM" + authorizer_id = aws_api_gateway_authorizer.repo_authoriser.id + require_credentials = true + origin = contains(["prod"], terraform.workspace) ? "'https://${var.domain}'" : "'https://${terraform.workspace}.${var.domain}'" + + request_parameters = { + "method.request.path.id" = true + } +} + +module "user_restrictions_user_search_gateway" { + source = "./modules/gateway" + api_gateway_id = aws_api_gateway_rest_api.ndr_doc_store_api.id + parent_id = module.user_restrictions_gateway.gateway_resource_id + http_methods = ["GET"] + gateway_path = "SearchUser" + authorization = "CUSTOM" + authorizer_id = aws_api_gateway_authorizer.repo_authoriser.id + require_credentials = true + origin = contains(["prod"], terraform.workspace) ? "'https://${var.domain}'" : "'https://${terraform.workspace}.${var.domain}'" +} diff --git a/infrastructure/lambda-create-user-restriction.tf b/infrastructure/lambda-create-user-restriction.tf new file mode 100644 index 00000000..f70b4ede --- /dev/null +++ b/infrastructure/lambda-create-user-restriction.tf @@ -0,0 +1,66 @@ +module "create_user_restriction_lambda" { + source = "./modules/lambda" + name = "CreateUserRestriction" + handler = "handlers.create_user_restriction_handler.lambda_handler" + iam_role_policy_documents = [ + module.ndr-app-config.app_config_policy, + aws_iam_policy.ssm_access_policy.policy, + module.user_restriction_table.dynamodb_write_policy_document + ] + kms_deletion_window = var.kms_deletion_window + rest_api_id = aws_api_gateway_rest_api.ndr_doc_store_api.id + resource_id = module.user_restrictions_gateway.gateway_resource_id + http_methods = ["POST"] + api_execution_arn = aws_api_gateway_rest_api.ndr_doc_store_api.execution_arn + lambda_environment_variables = { + APPCONFIG_APPLICATION = module.ndr-app-config.app_config_application_id + APPCONFIG_ENVIRONMENT = module.ndr-app-config.app_config_environment_id + APPCONFIG_CONFIGURATION = module.ndr-app-config.app_config_configuration_profile_id + WORKSPACE = terraform.workspace + RESTRICTIONS_TABLE_NAME = module.user_restriction_table.table_name + } + + depends_on = [ + aws_api_gateway_rest_api.ndr_doc_store_api, + module.user_restrictions_gateway + ] +} + +module "create_user_restriction_lambda_alarms" { + source = "./modules/lambda_alarms" + lambda_function_name = module.create_user_restriction_lambda.function_name + lambda_timeout = module.create_user_restriction_lambda.timeout + lambda_name = module.create_user_restriction_lambda.function_name + namespace = "AWS/Lambda" + alarm_actions = [module.create_user_restriction_lambda_alarm_topic.arn] + ok_actions = [module.create_user_restriction_lambda_alarm_topic.arn] +} + +module "create_user_restriction_lambda_alarm_topic" { + source = "./modules/sns" + sns_encryption_key_id = module.sns_encryption_key.id + topic_name = "create-user-restriction-lambda-alarm-topic" + topic_protocol = "email" + is_topic_endpoint_list = true + topic_endpoint_list = local.is_sandbox ? [] : nonsensitive(split(",", data.aws_ssm_parameter.cloud_security_notification_email_list.value)) + delivery_policy = jsonencode({ + "Version" : "2012-10-17", + "Statement" : [ + { + "Effect" : "Allow", + "Principal" : { + "Service" : "cloudwatch.amazonaws.com" + }, + "Action" : [ + "SNS:Publish", + ], + "Condition" : { + "ArnLike" : { + "aws:SourceArn" : "arn:aws:cloudwatch:eu-west-2:${data.aws_caller_identity.current.account_id}:alarm:*" + } + } + "Resource" : "*" + } + ] + }) +} \ No newline at end of file diff --git a/infrastructure/lambda-get-user-information.tf b/infrastructure/lambda-get-user-information.tf new file mode 100644 index 00000000..b4522288 --- /dev/null +++ b/infrastructure/lambda-get-user-information.tf @@ -0,0 +1,64 @@ +module "get_user_information_lambda" { + source = "./modules/lambda" + name = "GetUserInformation" + handler = "handlers.get_user_information_handler.lambda_handler" + iam_role_policy_documents = [ + module.ndr-app-config.app_config_policy, + aws_iam_policy.ssm_access_policy.policy, + ] + kms_deletion_window = var.kms_deletion_window + rest_api_id = aws_api_gateway_rest_api.ndr_doc_store_api.id + resource_id = module.user_restrictions_user_search_gateway.gateway_resource_id + http_methods = ["GET"] + api_execution_arn = aws_api_gateway_rest_api.ndr_doc_store_api.execution_arn + lambda_environment_variables = { + APPCONFIG_APPLICATION = module.ndr-app-config.app_config_application_id + APPCONFIG_ENVIRONMENT = module.ndr-app-config.app_config_environment_id + APPCONFIG_CONFIGURATION = module.ndr-app-config.app_config_configuration_profile_id + WORKSPACE = terraform.workspace + } + + depends_on = [ + aws_api_gateway_rest_api.ndr_doc_store_api, + module.user_restrictions_user_search_gateway + ] +} + +module "get_user_information_lambda_alarms" { + source = "./modules/lambda_alarms" + lambda_function_name = module.get_user_information_lambda.function_name + lambda_timeout = module.get_user_information_lambda.timeout + lambda_name = module.get_user_information_lambda.function_name + namespace = "AWS/Lambda" + alarm_actions = [module.get_user_information_lambda_alarm_topic.arn] + ok_actions = [module.get_user_information_lambda_alarm_topic.arn] +} + +module "get_user_information_lambda_alarm_topic" { + source = "./modules/sns" + sns_encryption_key_id = module.sns_encryption_key.id + topic_name = "get-user-information-lambda-alarm-topic" + topic_protocol = "email" + is_topic_endpoint_list = true + topic_endpoint_list = local.is_sandbox ? [] : nonsensitive(split(",", data.aws_ssm_parameter.cloud_security_notification_email_list.value)) + delivery_policy = jsonencode({ + "Version" : "2012-10-17", + "Statement" : [ + { + "Effect" : "Allow", + "Principal" : { + "Service" : "cloudwatch.amazonaws.com" + }, + "Action" : [ + "SNS:Publish", + ], + "Condition" : { + "ArnLike" : { + "aws:SourceArn" : "arn:aws:cloudwatch:eu-west-2:${data.aws_caller_identity.current.account_id}:alarm:*" + } + } + "Resource" : "*" + } + ] + }) +} \ No newline at end of file diff --git a/infrastructure/lambda-search-user-restriction.tf b/infrastructure/lambda-search-user-restriction.tf new file mode 100644 index 00000000..742e7003 --- /dev/null +++ b/infrastructure/lambda-search-user-restriction.tf @@ -0,0 +1,66 @@ +module "search_user_restriction_lambda" { + source = "./modules/lambda" + name = "SearchUserRestriction" + handler = "handlers.search_user_restriction_handler.lambda_handler" + iam_role_policy_documents = [ + module.ndr-app-config.app_config_policy, + aws_iam_policy.ssm_access_policy.policy, + module.user_restriction_table.dynamodb_read_policy_document + ] + kms_deletion_window = var.kms_deletion_window + rest_api_id = aws_api_gateway_rest_api.ndr_doc_store_api.id + resource_id = module.user_restrictions_gateway.gateway_resource_id + http_methods = ["GET"] + api_execution_arn = aws_api_gateway_rest_api.ndr_doc_store_api.execution_arn + lambda_environment_variables = { + APPCONFIG_APPLICATION = module.ndr-app-config.app_config_application_id + APPCONFIG_ENVIRONMENT = module.ndr-app-config.app_config_environment_id + APPCONFIG_CONFIGURATION = module.ndr-app-config.app_config_configuration_profile_id + WORKSPACE = terraform.workspace + RESTRICTIONS_TABLE_NAME = module.user_restriction_table.table_name + } + + depends_on = [ + aws_api_gateway_rest_api.ndr_doc_store_api, + module.user_restrictions_gateway + ] +} + +module "search_user_restriction_lambda_alarms" { + source = "./modules/lambda_alarms" + lambda_timeout = module.search_user_restriction_lambda.timeout + lambda_function_name = module.search_user_restriction_lambda.function_name + lambda_name = module.search_user_restriction_lambda.function_name + namespace = "AWS/Lambda" + alarm_actions = [module.search_user_restriction_lambda_alarm_topic.arn] + ok_actions = [module.search_user_restriction_lambda_alarm_topic.arn] +} + +module "search_user_restriction_lambda_alarm_topic" { + source = "./modules/sns" + sns_encryption_key_id = module.sns_encryption_key.id + topic_name = "search-user-restriction-lambda-alarm-topic" + topic_protocol = "email" + is_topic_endpoint_list = true + topic_endpoint_list = local.is_sandbox ? [] : nonsensitive(split(",", data.aws_ssm_parameter.cloud_security_notification_email_list.value)) + delivery_policy = jsonencode({ + "Version" : "2012-10-17", + "Statement" : [ + { + "Effect" : "Allow", + "Principal" : { + "Service" : "cloudwatch.amazonaws.com" + }, + "Action" : [ + "SNS:Publish", + ], + "Condition" : { + "ArnLike" : { + "aws:SourceArn" : "arn:aws:cloudwatch:eu-west-2:${data.aws_caller_identity.current.account_id}:alarm:*" + } + } + "Resource" : "*" + } + ] + }) +} diff --git a/infrastructure/lambda-update-status-user-restriction.tf b/infrastructure/lambda-update-status-user-restriction.tf new file mode 100644 index 00000000..b2f57484 --- /dev/null +++ b/infrastructure/lambda-update-status-user-restriction.tf @@ -0,0 +1,66 @@ +module "update_user_restriction_lambda" { + source = "./modules/lambda" + name = "UpdateStatusUserRestriction" + handler = "handlers.update_status_user_restriction_handler.lambda_handler" + iam_role_policy_documents = [ + module.ndr-app-config.app_config_policy, + aws_iam_policy.ssm_access_policy.policy, + module.user_restriction_table.dynamodb_write_policy_document + ] + kms_deletion_window = var.kms_deletion_window + rest_api_id = aws_api_gateway_rest_api.ndr_doc_store_api.id + resource_id = module.user_restriction_id_gateway.gateway_resource_id + http_methods = ["PATCH"] + api_execution_arn = aws_api_gateway_rest_api.ndr_doc_store_api.execution_arn + lambda_environment_variables = { + APPCONFIG_APPLICATION = module.ndr-app-config.app_config_application_id + APPCONFIG_ENVIRONMENT = module.ndr-app-config.app_config_environment_id + APPCONFIG_CONFIGURATION = module.ndr-app-config.app_config_configuration_profile_id + WORKSPACE = terraform.workspace + RESTRICTIONS_TABLE_NAME = module.user_restriction_table.table_name + } + + depends_on = [ + aws_api_gateway_rest_api.ndr_doc_store_api, + module.user_restriction_id_gateway + ] +} + +module "update_status_user_restriction_lambda_alarms" { + source = "./modules/lambda_alarms" + lambda_function_name = module.update_user_restriction_lambda.function_name + lambda_timeout = module.update_user_restriction_lambda.timeout + lambda_name = module.update_user_restriction_lambda.function_name + namespace = "AWS/Lambda" + alarm_actions = [module.update_status_user_restriction_lambda_alarm_topic.arn] + ok_actions = [module.update_status_user_restriction_lambda_alarm_topic.arn] +} + +module "update_status_user_restriction_lambda_alarm_topic" { + source = "./modules/sns" + sns_encryption_key_id = module.sns_encryption_key.id + topic_name = "update-status-user-restriction-lambda-alarm-topic" + topic_protocol = "email" + is_topic_endpoint_list = true + topic_endpoint_list = local.is_sandbox ? [] : nonsensitive(split(",", data.aws_ssm_parameter.cloud_security_notification_email_list.value)) + delivery_policy = jsonencode({ + "Version" : "2012-10-17", + "Statement" : [ + { + "Effect" : "Allow", + "Principal" : { + "Service" : "cloudwatch.amazonaws.com" + }, + "Action" : [ + "SNS:Publish", + ], + "Condition" : { + "ArnLike" : { + "aws:SourceArn" : "arn:aws:cloudwatch:eu-west-2:${data.aws_caller_identity.current.account_id}:alarm:*" + } + } + "Resource" : "*" + } + ] + }) +} \ No newline at end of file diff --git a/infrastructure/variable.tf b/infrastructure/variable.tf index 0dcbe220..6ed61e1c 100644 --- a/infrastructure/variable.tf +++ b/infrastructure/variable.tf @@ -208,6 +208,12 @@ variable "deletion_protection_enabled" { default = false } +variable "user_restrictions_table_name" { + description = "The DynamoDB table name for storing user restrictions" + type = string + default = "UserRestrictions" +} + # VPC Variables variable "standalone_vpc_tag" {