diff --git a/infrastructure/instance/.terraform.lock.hcl b/infrastructure/instance/.terraform.lock.hcl index 299a4b00cf..98b9cc7e6a 100644 --- a/infrastructure/instance/.terraform.lock.hcl +++ b/infrastructure/instance/.terraform.lock.hcl @@ -3,7 +3,7 @@ provider "registry.terraform.io/hashicorp/aws" { version = "6.43.0" - constraints = ">= 6.0.0, ~> 6.0" + constraints = ">= 6.0.0, ~> 6.0, >= 6.28.0" hashes = [ "h1:/A3VpeGOhvutRSlGACfUKeBMFZa3CTSLIqvT+XH0364=", "zh:0fe91026ce8c5178781de6773531dcfcf5280ee139059dc5a0c046f1532cf389", @@ -46,22 +46,22 @@ provider "registry.terraform.io/hashicorp/external" { } provider "registry.terraform.io/hashicorp/local" { - version = "2.7.0" + version = "2.8.0" constraints = ">= 1.0.0" hashes = [ - "h1:sSwlfp2etjCaE9hIF7bJBDjRIhDCVFglEOVyiCI7vgs=", - "zh:261fec71bca13e0a7812dc0d8ae9af2b4326b24d9b2e9beab3d2400fab5c5f9a", - "zh:308da3b5376a9ede815042deec5af1050ec96a5a5410a2206ae847d82070a23e", - "zh:3d056924c420464dc8aba10e1915956b2e5c4d55b11ffff79aa8be563fbfe298", - "zh:643256547b155459c45e0a3e8aab0570db59923c68daf2086be63c444c8c445b", + "h1:3jWHVwO5QUIS9V1NsK10ZzdpkK2ABuB4G+UIWrVeGp4=", + "zh:05f18164beab4a84753e5fedf463771ee0c6eca8e90346b8766f1e1c186dec1e", + "zh:563a0702e3711e25ba8930120899b681378b50cbb957fd204b37745c7c9b5f40", + "zh:5b56ab2ed70ed92721febb4a070af0837f1084c44825c18e4b95f7efb1d45d26", + "zh:6cbedc09b67a5cdb9501ff1b18a315fa46a38e0530424cab1c7f4b3acc75f489", + "zh:71b3bd50f89fb385a42a436ba2ce2b8e00f9de53535ce956deff1477b0b117dc", "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:7aa4d0b853f84205e8cf79f30c9b2c562afbfa63592f7231b6637e5d7a6b5b27", - "zh:7dc251bbc487d58a6ab7f5b07ec9edc630edb45d89b761dba28e0e2ba6b1c11f", - "zh:7ee0ca546cd065030039168d780a15cbbf1765a4c70cd56d394734ab112c93da", - "zh:b1d5d80abb1906e6c6b3685a52a0192b4ca6525fe090881c64ec6f67794b1300", - "zh:d81ea9856d61db3148a4fc6c375bf387a721d78fc1fea7a8823a027272a47a78", - "zh:df0a1f0afc947b8bfc88617c1ad07a689ce3bd1a29fd97318392e6bdd32b230b", - "zh:dfbcad800240e0c68c43e0866f2a751cff09777375ec701918881acf67a268da", + "zh:9d45ac0a00b85cabdd398b859349d17f124c598b6e6bf272f1bb01321ce708a8", + "zh:a453efe8641a8f31fe806b597bf2b34d7b78b971a8e3919061ea89d61fda7b8d", + "zh:ac692bacb8c3dca8b5b37e5383168aca1f87d3cd7b40615efd300defb76494f5", + "zh:bda9e90c8547d90c9c573206985c5675cc1406047605af037a5069942c3c5966", + "zh:c30a1967de040d00f5038086dd53cdbfb78cc05d1dbc75037410f011bf2a20d8", + "zh:c80bbd1c3f56b3c836d80cf93ac0e8809305c2642f0c98b54bf5d05d3b12718c", ] } diff --git a/infrastructure/instance/endpoints.tf b/infrastructure/instance/endpoints.tf index 9ff8d56b21..ab2d3680a6 100644 --- a/infrastructure/instance/endpoints.tf +++ b/infrastructure/instance/endpoints.tf @@ -111,16 +111,17 @@ output "oas" { module "api_gateway" { source = "./modules/api_gateway" - prefix = local.prefix - short_prefix = local.short_prefix - zone_id = data.aws_route53_zone.project_zone.zone_id - api_domain_name = local.service_domain_name - environment = var.environment - sub_environment = var.sub_environment - oas = local.oas - aws_region = var.aws_region - immunisation_account_id = var.immunisation_account_id - csoc_account_id = var.csoc_account_id + prefix = local.prefix + short_prefix = local.short_prefix + zone_id = data.aws_route53_zone.project_zone.zone_id + api_domain_name = local.service_domain_name + environment = var.environment + sub_environment = var.sub_environment + oas = local.oas + aws_region = var.aws_region + immunisation_account_id = var.immunisation_account_id + csoc_account_id = var.csoc_account_id + access_log_target_bucket = var.enable_s3_access_logging ? local.s3_access_log_bucket_name : null } resource "aws_lambda_permission" "api_gw" { diff --git a/infrastructure/instance/environments/preprod/int-blue/variables.tfvars b/infrastructure/instance/environments/preprod/int-blue/variables.tfvars index 0b3107be75..4e35674ad1 100644 --- a/infrastructure/instance/environments/preprod/int-blue/variables.tfvars +++ b/infrastructure/instance/environments/preprod/int-blue/variables.tfvars @@ -10,3 +10,5 @@ mesh_no_invocation_period_seconds = 259200 create_mesh_processor = true has_sub_environment_scope = false dynamodb_point_in_time_recovery_enabled = true +enable_s3_access_logging = true +s3_access_log_bucket_name = "immunisation-preprod-s3-access-logs" diff --git a/infrastructure/instance/environments/preprod/int-green/variables.tfvars b/infrastructure/instance/environments/preprod/int-green/variables.tfvars index 0b3107be75..4e35674ad1 100644 --- a/infrastructure/instance/environments/preprod/int-green/variables.tfvars +++ b/infrastructure/instance/environments/preprod/int-green/variables.tfvars @@ -10,3 +10,5 @@ mesh_no_invocation_period_seconds = 259200 create_mesh_processor = true has_sub_environment_scope = false dynamodb_point_in_time_recovery_enabled = true +enable_s3_access_logging = true +s3_access_log_bucket_name = "immunisation-preprod-s3-access-logs" diff --git a/infrastructure/instance/modules/api_gateway/mtls_cert.tf b/infrastructure/instance/modules/api_gateway/mtls_cert.tf index 0a0c6cffff..ed73bd26b3 100644 --- a/infrastructure/instance/modules/api_gateway/mtls_cert.tf +++ b/infrastructure/instance/modules/api_gateway/mtls_cert.tf @@ -21,6 +21,13 @@ resource "aws_s3_bucket" "truststore_bucket" { force_destroy = true } +resource "aws_s3_bucket_logging" "truststore_bucket" { + count = var.access_log_target_bucket == null ? 0 : 1 + bucket = aws_s3_bucket.truststore_bucket.bucket + target_bucket = var.access_log_target_bucket + target_prefix = "${aws_s3_bucket.truststore_bucket.bucket}/" +} + resource "aws_s3_bucket_versioning" "truststore_bucket" { bucket = aws_s3_bucket.truststore_bucket.bucket versioning_configuration { diff --git a/infrastructure/instance/modules/api_gateway/variables.tf b/infrastructure/instance/modules/api_gateway/variables.tf index aaa0e5d845..8a55588a2b 100644 --- a/infrastructure/instance/modules/api_gateway/variables.tf +++ b/infrastructure/instance/modules/api_gateway/variables.tf @@ -16,3 +16,7 @@ variable "aws_region" { } variable "immunisation_account_id" {} variable "csoc_account_id" {} +variable "access_log_target_bucket" { + type = string + default = null +} diff --git a/infrastructure/instance/modules/splunk/backup.tf b/infrastructure/instance/modules/splunk/backup.tf index 514c656c62..698eee5509 100644 --- a/infrastructure/instance/modules/splunk/backup.tf +++ b/infrastructure/instance/modules/splunk/backup.tf @@ -33,3 +33,10 @@ resource "aws_s3_bucket_policy" "failed_logs_backup_https_only" { bucket = aws_s3_bucket.failed_logs_backup.id policy = data.aws_iam_policy_document.failed_logs_backup_https_only.json } + +resource "aws_s3_bucket_logging" "failed_logs_backup" { + count = var.access_log_target_bucket == null ? 0 : 1 + bucket = aws_s3_bucket.failed_logs_backup.bucket + target_bucket = var.access_log_target_bucket + target_prefix = "${aws_s3_bucket.failed_logs_backup.bucket}/" +} diff --git a/infrastructure/instance/modules/splunk/variables.tf b/infrastructure/instance/modules/splunk/variables.tf index 7f4ac4f86a..238c8121a7 100644 --- a/infrastructure/instance/modules/splunk/variables.tf +++ b/infrastructure/instance/modules/splunk/variables.tf @@ -5,3 +5,7 @@ locals { variable "splunk_endpoint" {} variable "hec_token" {} variable "force_destroy" {} +variable "access_log_target_bucket" { + type = string + default = null +} diff --git a/infrastructure/instance/s3_access_logging.tf b/infrastructure/instance/s3_access_logging.tf new file mode 100644 index 0000000000..0052165477 --- /dev/null +++ b/infrastructure/instance/s3_access_logging.tf @@ -0,0 +1,32 @@ +data "aws_s3_bucket" "existing_s3_access_log_bucket" { + count = var.enable_s3_access_logging ? 1 : 0 + bucket = local.s3_access_log_bucket_name +} + +resource "aws_s3_bucket_logging" "batch_data_source_bucket" { + count = var.enable_s3_access_logging ? 1 : 0 + bucket = aws_s3_bucket.batch_data_source_bucket.bucket + target_bucket = data.aws_s3_bucket.existing_s3_access_log_bucket[0].bucket + target_prefix = "${aws_s3_bucket.batch_data_source_bucket.bucket}/" +} + +resource "aws_s3_bucket_logging" "batch_data_destination_bucket" { + count = var.enable_s3_access_logging ? 1 : 0 + bucket = aws_s3_bucket.batch_data_destination_bucket.bucket + target_bucket = data.aws_s3_bucket.existing_s3_access_log_bucket[0].bucket + target_prefix = "${aws_s3_bucket.batch_data_destination_bucket.bucket}/" +} + +resource "aws_s3_bucket_logging" "batch_config_bucket" { + count = var.enable_s3_access_logging ? 1 : 0 + bucket = aws_s3_bucket.batch_config_bucket.bucket + target_bucket = data.aws_s3_bucket.existing_s3_access_log_bucket[0].bucket + target_prefix = "${aws_s3_bucket.batch_config_bucket.bucket}/" +} + +resource "aws_s3_bucket_logging" "account_batch_data_source_bucket" { + count = var.enable_s3_access_logging && !var.has_sub_environment_scope ? 1 : 0 + bucket = "immunisation-batch-${local.resource_scope}-data-sources" + target_bucket = data.aws_s3_bucket.existing_s3_access_log_bucket[0].bucket + target_prefix = "immunisation-batch-${local.resource_scope}-data-sources/" +} diff --git a/infrastructure/instance/splunk.tf b/infrastructure/instance/splunk.tf index 21ce6d7510..730b70dac7 100644 --- a/infrastructure/instance/splunk.tf +++ b/infrastructure/instance/splunk.tf @@ -6,9 +6,10 @@ data "aws_secretsmanager_secret_version" "splunk_token_id" { } module "splunk" { - source = "./modules/splunk" - prefix = local.prefix - splunk_endpoint = "https://firehose.inputs.splunk.aws.digital.nhs.uk/services/collector/event" - hec_token = data.aws_secretsmanager_secret_version.splunk_token_id.secret_string - force_destroy = local.is_temp + source = "./modules/splunk" + prefix = local.prefix + splunk_endpoint = "https://firehose.inputs.splunk.aws.digital.nhs.uk/services/collector/event" + hec_token = data.aws_secretsmanager_secret_version.splunk_token_id.secret_string + force_destroy = local.is_temp + access_log_target_bucket = var.enable_s3_access_logging ? local.s3_access_log_bucket_name : null } diff --git a/infrastructure/instance/variables.tf b/infrastructure/instance/variables.tf index 21f7ea8e22..9aa6e05a1d 100644 --- a/infrastructure/instance/variables.tf +++ b/infrastructure/instance/variables.tf @@ -224,17 +224,30 @@ variable "redis_sync_image_uri" { } } +variable "s3_access_log_bucket_name" { + description = "Destination bucket used for S3 server access logs" + type = string + default = "" +} + +variable "enable_s3_access_logging" { + description = "When true, manage S3 server access logging resources in this stack" + type = bool + default = false +} + locals { - prefix = "${var.project_name}-${var.service}-${var.sub_environment}" - short_prefix = "${var.project_short_name}-${var.sub_environment}" - batch_prefix = "immunisation-batch-${var.sub_environment}" - root_domain_name = "${var.environment}.vds.platform.nhs.uk" - project_domain_name = "imms.${local.root_domain_name}" - service_domain_name = "${var.sub_environment}.${local.project_domain_name}" - config_bucket_arn = aws_s3_bucket.batch_config_bucket.arn - config_bucket_name = aws_s3_bucket.batch_config_bucket.bucket - is_temp = length(regexall("[a-z]{2,4}-?[0-9]+", var.sub_environment)) > 0 - resource_scope = var.has_sub_environment_scope ? var.sub_environment : var.environment + prefix = "${var.project_name}-${var.service}-${var.sub_environment}" + short_prefix = "${var.project_short_name}-${var.sub_environment}" + batch_prefix = "immunisation-batch-${var.sub_environment}" + root_domain_name = "${var.environment}.vds.platform.nhs.uk" + project_domain_name = "imms.${local.root_domain_name}" + service_domain_name = "${var.sub_environment}.${local.project_domain_name}" + config_bucket_arn = aws_s3_bucket.batch_config_bucket.arn + config_bucket_name = aws_s3_bucket.batch_config_bucket.bucket + is_temp = length(regexall("[a-z]{2,4}-?[0-9]+", var.sub_environment)) > 0 + resource_scope = var.has_sub_environment_scope ? var.sub_environment : var.environment + s3_access_log_bucket_name = var.s3_access_log_bucket_name != "" ? var.s3_access_log_bucket_name : "immunisation-${var.environment}-s3-access-logs" # Public subnet - The subnet has a direct route to an internet gateway. Resources in a public subnet can access the public internet. # public_subnet_ids = [for k, v in data.aws_route.internet_traffic_route_by_subnet : k if length(v.gateway_id) > 0] # Private subnet - The subnet does not have a direct route to an internet gateway. Resources in a private subnet require a NAT device to access the public internet.