From 8a93d88d2a73857515d3d92c6d01eaaf974ddcaf Mon Sep 17 00:00:00 2001 From: aidenvaines-bjss Date: Fri, 1 Aug 2025 15:24:11 +0100 Subject: [PATCH 1/6] CCM-11211 Drop Acct Component --- .../terraform/components/acct/.tool-versions | 1 - .../terraform/components/acct/README.md | 42 ----- .../components/acct/budgets_budget.tf | 31 ---- ...cloudwatch_event_rule_cloudwatch_alarms.tf | 48 ------ .../cloudwatch_log_group_route53_query_log.tf | 37 ----- .../components/acct/cost_anomaly_monitor.tf | 28 ---- .../acct/iam_policy_github_deploy_overload.tf | 23 --- .../terraform/components/acct/locals.tf | 3 - .../components/acct/locals_remote_state.tf | 21 --- .../components/acct/locals_tfscaffold.tf | 44 ----- .../acct/module_s3bucket_access_logs.tf | 150 ------------------ ...dule_s3bucket_lambda_function_artefacts.tf | 133 ---------------- .../terraform/components/acct/outputs.tf | 22 --- .../terraform/components/acct/provider_aws.tf | 24 --- .../components/acct/route53_delegation_set.tf | 3 - .../components/acct/route53_query_log.tf | 9 -- .../terraform/components/acct/route53_zone.tf | 5 - .../components/acct/sns_topic_costs.tf | 36 ----- .../terraform/components/acct/variables.tf | 87 ---------- .../terraform/components/acct/versions.tf | 10 -- 20 files changed, 757 deletions(-) delete mode 100644 infrastructure/terraform/components/acct/.tool-versions delete mode 100644 infrastructure/terraform/components/acct/README.md delete mode 100644 infrastructure/terraform/components/acct/budgets_budget.tf delete mode 100644 infrastructure/terraform/components/acct/cloudwatch_event_rule_cloudwatch_alarms.tf delete mode 100644 infrastructure/terraform/components/acct/cloudwatch_log_group_route53_query_log.tf delete mode 100644 infrastructure/terraform/components/acct/cost_anomaly_monitor.tf delete mode 100644 infrastructure/terraform/components/acct/iam_policy_github_deploy_overload.tf delete mode 100644 infrastructure/terraform/components/acct/locals.tf delete mode 100644 infrastructure/terraform/components/acct/locals_remote_state.tf delete mode 100644 infrastructure/terraform/components/acct/locals_tfscaffold.tf delete mode 100644 infrastructure/terraform/components/acct/module_s3bucket_access_logs.tf delete mode 100644 infrastructure/terraform/components/acct/module_s3bucket_lambda_function_artefacts.tf delete mode 100644 infrastructure/terraform/components/acct/outputs.tf delete mode 100644 infrastructure/terraform/components/acct/provider_aws.tf delete mode 100644 infrastructure/terraform/components/acct/route53_delegation_set.tf delete mode 100644 infrastructure/terraform/components/acct/route53_query_log.tf delete mode 100644 infrastructure/terraform/components/acct/route53_zone.tf delete mode 100644 infrastructure/terraform/components/acct/sns_topic_costs.tf delete mode 100644 infrastructure/terraform/components/acct/variables.tf delete mode 100644 infrastructure/terraform/components/acct/versions.tf diff --git a/infrastructure/terraform/components/acct/.tool-versions b/infrastructure/terraform/components/acct/.tool-versions deleted file mode 100644 index 3dd74c7..0000000 --- a/infrastructure/terraform/components/acct/.tool-versions +++ /dev/null @@ -1 +0,0 @@ -terraform 1.10.1 diff --git a/infrastructure/terraform/components/acct/README.md b/infrastructure/terraform/components/acct/README.md deleted file mode 100644 index 8bc0a83..0000000 --- a/infrastructure/terraform/components/acct/README.md +++ /dev/null @@ -1,42 +0,0 @@ - - - - -## Requirements - -| Name | Version | -|------|---------| -| [terraform](#requirement\_terraform) | >= 1.10.1 | -| [aws](#requirement\_aws) | ~> 5.50 | -## Inputs - -| Name | Description | Type | Default | Required | -|------|-------------|------|---------|:--------:| -| [aws\_account\_id](#input\_aws\_account\_id) | The AWS Account ID (numeric) | `string` | n/a | yes | -| [budget\_amount](#input\_budget\_amount) | The budget amount in USD for the account | `number` | `500` | no | -| [component](#input\_component) | The variable encapsulating the name of this component | `string` | `"acct"` | no | -| [cost\_alarm\_recipients](#input\_cost\_alarm\_recipients) | A list of email addresses to receive alarm notifications | `list(string)` | `[]` | no | -| [cost\_anomaly\_threshold](#input\_cost\_anomaly\_threshold) | The threshold percentage for cost anomaly detection | `number` | `10` | no | -| [default\_tags](#input\_default\_tags) | A map of default tags to apply to all taggable resources within the component | `map(string)` | `{}` | no | -| [environment](#input\_environment) | The name of the tfscaffold environment | `string` | n/a | yes | -| [group](#input\_group) | The group variables are being inherited from (often synonmous with account short-name) | `string` | n/a | yes | -| [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 | -| [observability\_account\_id](#input\_observability\_account\_id) | The Observability Account ID that needs access | `string` | n/a | yes | -| [project](#input\_project) | The name of the tfscaffold project | `string` | n/a | yes | -| [region](#input\_region) | The AWS Region | `string` | n/a | yes | -| [root\_domain\_name](#input\_root\_domain\_name) | The service's root DNS root nameespace, like nonprod.nhsnotify.national.nhs.uk | `string` | `"nonprod.nhsnotify.national.nhs.uk"` | no | -## Modules - -| Name | Source | Version | -|------|--------|---------| -| [s3bucket\_access\_logs](#module\_s3bucket\_access\_logs) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/s3bucket | v1.0.8 | -| [s3bucket\_lambda\_artefacts](#module\_s3bucket\_lambda\_artefacts) | git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/s3bucket | v1.0.8 | -## Outputs - -| Name | Description | -|------|-------------| -| [dns\_zone](#output\_dns\_zone) | n/a | -| [s3\_buckets](#output\_s3\_buckets) | n/a | - - - diff --git a/infrastructure/terraform/components/acct/budgets_budget.tf b/infrastructure/terraform/components/acct/budgets_budget.tf deleted file mode 100644 index 6a253fa..0000000 --- a/infrastructure/terraform/components/acct/budgets_budget.tf +++ /dev/null @@ -1,31 +0,0 @@ -resource "aws_budgets_budget" "main" { - name = "${local.csi}-monthly-budget" - budget_type = "COST" - limit_amount = var.budget_amount - limit_unit = "USD" - time_unit = "MONTHLY" - - notification { - comparison_operator = "GREATER_THAN" - notification_type = "FORECASTED" - threshold = 100 - threshold_type = "PERCENTAGE" - subscriber_sns_topic_arns = [aws_sns_topic.costs.arn] - } - - notification { - comparison_operator = "GREATER_THAN" - notification_type = "ACTUAL" - threshold = 100 - threshold_type = "PERCENTAGE" - subscriber_sns_topic_arns = [aws_sns_topic.costs.arn] - } - - notification { - comparison_operator = "GREATER_THAN" - notification_type = "ACTUAL" - threshold = 85 - threshold_type = "PERCENTAGE" - subscriber_sns_topic_arns = [aws_sns_topic.costs.arn] - } -} diff --git a/infrastructure/terraform/components/acct/cloudwatch_event_rule_cloudwatch_alarms.tf b/infrastructure/terraform/components/acct/cloudwatch_event_rule_cloudwatch_alarms.tf deleted file mode 100644 index c453eac..0000000 --- a/infrastructure/terraform/components/acct/cloudwatch_event_rule_cloudwatch_alarms.tf +++ /dev/null @@ -1,48 +0,0 @@ -resource "aws_cloudwatch_event_rule" "cloudwatch_alarms" { - name = "${local.csi}-cloudwatch-alarm-fowarding" - description = "Forwards CloudWatch Alarm state changes to Custom Event Bus in Observability Account" - - event_pattern = jsonencode({ - "source" = ["aws.cloudwatch"], - "detail-type" = ["CloudWatch Alarm State Change"] - }) -} - -resource "aws_cloudwatch_event_target" "cloudwatch_alarms" { - rule = aws_cloudwatch_event_rule.cloudwatch_alarms.name - arn = local.event_bus_arn - role_arn = aws_iam_role.cloudwatch_alarms.arn -} - -resource "aws_iam_role" "cloudwatch_alarms" { - name = "${local.csi}-cloudwatch-alarms" - - assume_role_policy = jsonencode({ - Version = "2012-10-17", - Statement = [{ - Effect = "Allow", - Principal = { - Service = "events.amazonaws.com" - }, - Action = "sts:AssumeRole" - }] - }) -} - -resource "aws_iam_policy" "cloudwatch_alarms" { - name = "${local.csi}-cloudwatch-alarms" - - policy = jsonencode({ - Version = "2012-10-17", - Statement = [{ - Effect = "Allow", - Action = "events:PutEvents", - Resource = local.event_bus_arn - }] - }) -} - -resource "aws_iam_role_policy_attachment" "cloudwatch_alarms" { - role = aws_iam_role.cloudwatch_alarms.name - policy_arn = aws_iam_policy.cloudwatch_alarms.arn -} diff --git a/infrastructure/terraform/components/acct/cloudwatch_log_group_route53_query_log.tf b/infrastructure/terraform/components/acct/cloudwatch_log_group_route53_query_log.tf deleted file mode 100644 index e30e208..0000000 --- a/infrastructure/terraform/components/acct/cloudwatch_log_group_route53_query_log.tf +++ /dev/null @@ -1,37 +0,0 @@ -resource "aws_cloudwatch_log_group" "aws_route53_query_log" { - provider = aws.us-east-1 # Route53 query logging must be in us-east-1 https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_query_log - - name = "/aws/route53/${local.csi}" - retention_in_days = var.log_retention_in_days -} - -resource "aws_cloudwatch_log_resource_policy" "route53_query_logging_policy" { - provider = aws.us-east-1 # Route53 query logging must be in us-east-1 https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_query_log - - policy_document = data.aws_iam_policy_document.route53_logs.json - policy_name = "${local.csi}-route53-query-logging-policy" -} - -data "aws_iam_policy_document" "route53_logs" { - statement { - effect = "Allow" - - principals { - type = "Service" - - identifiers = [ - "route53.amazonaws.com" - ] - } - - actions = [ - "logs:CreateLogStream", - "logs:PutLogEvents", - ] - - resources = [ - aws_cloudwatch_log_group.aws_route53_query_log.arn, - "${aws_cloudwatch_log_group.aws_route53_query_log.arn}:*" - ] - } -} diff --git a/infrastructure/terraform/components/acct/cost_anomaly_monitor.tf b/infrastructure/terraform/components/acct/cost_anomaly_monitor.tf deleted file mode 100644 index 986336a..0000000 --- a/infrastructure/terraform/components/acct/cost_anomaly_monitor.tf +++ /dev/null @@ -1,28 +0,0 @@ -resource "aws_ce_anomaly_monitor" "anomaly_monitor" { - name = "${local.csi}-anomaly-monitor" - monitor_type = "DIMENSIONAL" - monitor_dimension = "SERVICE" -} - -resource "aws_ce_anomaly_subscription" "realtime_subscription" { - name = "${local.csi}-realtime-subscription" - frequency = "IMMEDIATE" - threshold_expression { - dimension { - key = "ANOMALY_TOTAL_IMPACT_PERCENTAGE" - values = [var.cost_anomaly_threshold] - match_options = ["GREATER_THAN_OR_EQUAL"] - } - } - monitor_arn_list = [ - aws_ce_anomaly_monitor.anomaly_monitor.arn, - ] - - subscriber { - type = "SNS" - address = aws_sns_topic.costs.arn - } - depends_on = [ - aws_sns_topic_policy.costs, - ] -} diff --git a/infrastructure/terraform/components/acct/iam_policy_github_deploy_overload.tf b/infrastructure/terraform/components/acct/iam_policy_github_deploy_overload.tf deleted file mode 100644 index 77cc2b6..0000000 --- a/infrastructure/terraform/components/acct/iam_policy_github_deploy_overload.tf +++ /dev/null @@ -1,23 +0,0 @@ -resource "aws_iam_policy" "github_deploy_overload" { - name = "${local.csi}-github-deploy-overload" - description = "Overloads the github permission to perform build actions for services in this account" - policy = data.aws_iam_policy_document.github_deploy.json -} - -resource "aws_iam_role_policy_attachment" "github_deploy_overload" { - role = local.bootstrap.iam_github_deploy_role["name"] - policy_arn = aws_iam_policy.github_deploy_overload.arn -} - -#trivy:ignore:aws-iam-no-policy-wildcards Policy voilation expected for CI user role -data "aws_iam_policy_document" "github_deploy" { - statement { - effect = "Allow" - - actions = [ - "cloudfront:*", - "wafv2:*", - ] - resources = ["*"] - } -} diff --git a/infrastructure/terraform/components/acct/locals.tf b/infrastructure/terraform/components/acct/locals.tf deleted file mode 100644 index fe71c80..0000000 --- a/infrastructure/terraform/components/acct/locals.tf +++ /dev/null @@ -1,3 +0,0 @@ -locals { - event_bus_arn = "arn:aws:events:eu-west-2:${var.observability_account_id}:event-bus/nhs-notify-main-acct-alerts-bus" -} diff --git a/infrastructure/terraform/components/acct/locals_remote_state.tf b/infrastructure/terraform/components/acct/locals_remote_state.tf deleted file mode 100644 index cd59a7c..0000000 --- a/infrastructure/terraform/components/acct/locals_remote_state.tf +++ /dev/null @@ -1,21 +0,0 @@ -locals { - bootstrap = data.terraform_remote_state.bootstrap.outputs -} - -data "terraform_remote_state" "bootstrap" { - backend = "s3" - - config = { - bucket = local.terraform_state_bucket - - key = format( - "%s/%s/%s/%s/bootstrap.tfstate", - var.project, - var.aws_account_id, - "eu-west-2", - "bootstrap" - ) - - region = "eu-west-2" - } -} diff --git a/infrastructure/terraform/components/acct/locals_tfscaffold.tf b/infrastructure/terraform/components/acct/locals_tfscaffold.tf deleted file mode 100644 index b7cf321..0000000 --- a/infrastructure/terraform/components/acct/locals_tfscaffold.tf +++ /dev/null @@ -1,44 +0,0 @@ -locals { - terraform_state_bucket = format( - "%s-tfscaffold-%s-%s", - var.project, - var.aws_account_id, - var.region, - ) - - csi = replace( - format( - "%s-%s-%s", - var.project, - var.environment, - var.component, - ), - "_", - "", - ) - - # CSI for use in resources with a global namespace, i.e. S3 Buckets - csi_global = replace( - format( - "%s-%s-%s-%s-%s", - var.project, - var.aws_account_id, - var.region, - var.environment, - var.component, - ), - "_", - "", - ) - - default_tags = merge( - var.default_tags, - { - Project = var.project - Environment = var.environment - Component = var.component - Group = var.group - Name = local.csi - }, - ) -} diff --git a/infrastructure/terraform/components/acct/module_s3bucket_access_logs.tf b/infrastructure/terraform/components/acct/module_s3bucket_access_logs.tf deleted file mode 100644 index 89e53dd..0000000 --- a/infrastructure/terraform/components/acct/module_s3bucket_access_logs.tf +++ /dev/null @@ -1,150 +0,0 @@ -module "s3bucket_access_logs" { - source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/s3bucket?ref=v1.0.8" - - providers = { - aws = aws.us-east-1 - } - - name = "access-logs" - - aws_account_id = var.aws_account_id - region = "us-east-1" - project = var.project - environment = var.environment - component = var.component - - acl = "private" - force_destroy = false - versioning = true - - lifecycle_rules = [ - { - enabled = true - - noncurrent_version_transition = [ - { - noncurrent_days = "30" - storage_class = "STANDARD_IA" - } - ] - - noncurrent_version_expiration = { - noncurrent_days = "90" - } - - abort_incomplete_multipart_upload = { - days = "1" - } - } - ] - - policy_documents = [ - data.aws_iam_policy_document.s3bucket_access_logs.json - ] - - public_access = { - block_public_acls = true - block_public_policy = true - ignore_public_acls = true - restrict_public_buckets = true - } - - - default_tags = { - Name = "S3 bucket access logs" - } -} - -data "aws_iam_policy_document" "s3bucket_access_logs" { - statement { - sid = "DontAllowNonSecureConnection" - effect = "Deny" - - actions = [ - "s3:*", - ] - - resources = [ - module.s3bucket_access_logs.arn, - "${module.s3bucket_access_logs.arn}/*", - ] - - principals { - type = "AWS" - - identifiers = [ - "*", - ] - } - - condition { - test = "Bool" - variable = "aws:SecureTransport" - - values = [ - "false", - ] - } - } - - statement { - sid = "AllowManagedAccountsToList" - effect = "Allow" - - actions = [ - "s3:ListBucket", - ] - - resources = [ - module.s3bucket_access_logs.arn, - ] - - principals { - type = "AWS" - identifiers = [ - "arn:aws:iam::${var.aws_account_id}:root" - ] - } - } - - statement { - sid = "AllowManagedAccountsToGet" - effect = "Allow" - - actions = [ - "s3:GetObject", - ] - - resources = [ - "${module.s3bucket_access_logs.arn}/*", - ] - - principals { - type = "AWS" - identifiers = [ - "arn:aws:iam::${var.aws_account_id}:root" - ] - } - } - - statement { - sid = "AllowS3AccessLogging" - effect = "Allow" - - actions = [ - "s3:PutObject", - ] - - resources = [ - "${module.s3bucket_access_logs.arn}/*", - ] - - principals { - type = "Service" - - identifiers = [ - "logging.s3.amazonaws.com", - ] - } - } -} diff --git a/infrastructure/terraform/components/acct/module_s3bucket_lambda_function_artefacts.tf b/infrastructure/terraform/components/acct/module_s3bucket_lambda_function_artefacts.tf deleted file mode 100644 index e87dd3a..0000000 --- a/infrastructure/terraform/components/acct/module_s3bucket_lambda_function_artefacts.tf +++ /dev/null @@ -1,133 +0,0 @@ -module "s3bucket_lambda_artefacts" { - source = "git::https://github.com/NHSDigital/nhs-notify-shared-modules.git//infrastructure/modules/s3bucket?ref=v1.0.8" - providers = { - aws = aws.us-east-1 - } - - name = "lambda-artefacts" - - aws_account_id = var.aws_account_id - region = "us-east-1" - project = var.project - environment = var.environment - component = var.component - - acl = "private" - force_destroy = false - versioning = true - - lifecycle_rules = [ - { - prefix = "" - enabled = true - - noncurrent_version_transition = [ - { - noncurrent_days = "30" - storage_class = "STANDARD_IA" - } - ] - - noncurrent_version_expiration = { - noncurrent_days = "90" - } - - abort_incomplete_multipart_upload = { - days = "1" - } - } - ] - - policy_documents = [ - data.aws_iam_policy_document.s3bucket_lambda_artefacts.json - ] - - bucket_logging_target = { - bucket = module.s3bucket_access_logs.id - } - - public_access = { - block_public_acls = true - block_public_policy = true - ignore_public_acls = true - restrict_public_buckets = true - } - - - default_tags = { - Name = "Lambda function artefact bucket" - } -} - -data "aws_iam_policy_document" "s3bucket_lambda_artefacts" { - statement { - sid = "DontAllowNonSecureConnection" - effect = "Deny" - - actions = [ - "s3:*", - ] - - resources = [ - module.s3bucket_lambda_artefacts.arn, - "${module.s3bucket_lambda_artefacts.arn}/*", - ] - - principals { - type = "AWS" - - identifiers = [ - "*", - ] - } - - condition { - test = "Bool" - variable = "aws:SecureTransport" - - values = [ - "false", - ] - } - } - - statement { - sid = "AllowManagedAccountsToList" - effect = "Allow" - - actions = [ - "s3:ListBucket", - ] - - resources = [ - module.s3bucket_lambda_artefacts.arn, - ] - - principals { - type = "AWS" - identifiers = [ - "arn:aws:iam::${var.aws_account_id}:root" - ] - } - } - - statement { - sid = "AllowManagedAccountsToGet" - effect = "Allow" - - actions = [ - "s3:GetObject", - ] - - resources = [ - "${module.s3bucket_lambda_artefacts.arn}/*", - ] - - principals { - type = "AWS" - identifiers = [ - "arn:aws:iam::${var.aws_account_id}:root" - ] - } - } -} diff --git a/infrastructure/terraform/components/acct/outputs.tf b/infrastructure/terraform/components/acct/outputs.tf deleted file mode 100644 index 872e6c3..0000000 --- a/infrastructure/terraform/components/acct/outputs.tf +++ /dev/null @@ -1,22 +0,0 @@ -output "dns_zone" { - value = { - id = aws_route53_zone.main.id - name = aws_route53_zone.main.name - nameservers = aws_route53_zone.main.name_servers - } -} - -output "s3_buckets" { - value = { - access_logs = { - arn = module.s3bucket_access_logs.arn - bucket = module.s3bucket_access_logs.bucket - id = module.s3bucket_access_logs.id - } - lambda_function_artefacts = { - arn = module.s3bucket_lambda_artefacts.arn - bucket = module.s3bucket_lambda_artefacts.bucket - id = module.s3bucket_lambda_artefacts.id - } - } -} diff --git a/infrastructure/terraform/components/acct/provider_aws.tf b/infrastructure/terraform/components/acct/provider_aws.tf deleted file mode 100644 index d694811..0000000 --- a/infrastructure/terraform/components/acct/provider_aws.tf +++ /dev/null @@ -1,24 +0,0 @@ -provider "aws" { - region = var.region - - allowed_account_ids = [ - var.aws_account_id, - ] - - default_tags { - tags = local.default_tags - } -} - -provider "aws" { - alias = "us-east-1" - region = "us-east-1" - - default_tags { - tags = local.default_tags - } - - allowed_account_ids = [ - var.aws_account_id, - ] -} diff --git a/infrastructure/terraform/components/acct/route53_delegation_set.tf b/infrastructure/terraform/components/acct/route53_delegation_set.tf deleted file mode 100644 index d80179b..0000000 --- a/infrastructure/terraform/components/acct/route53_delegation_set.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_route53_delegation_set" "main" { - reference_name = "web-gateway.${var.root_domain_name}" -} diff --git a/infrastructure/terraform/components/acct/route53_query_log.tf b/infrastructure/terraform/components/acct/route53_query_log.tf deleted file mode 100644 index 305ebb4..0000000 --- a/infrastructure/terraform/components/acct/route53_query_log.tf +++ /dev/null @@ -1,9 +0,0 @@ -resource "aws_route53_query_log" "main" { - zone_id = aws_route53_zone.main.zone_id - - cloudwatch_log_group_arn = aws_cloudwatch_log_group.aws_route53_query_log.arn - - depends_on = [ - aws_cloudwatch_log_resource_policy.route53_query_logging_policy - ] -} diff --git a/infrastructure/terraform/components/acct/route53_zone.tf b/infrastructure/terraform/components/acct/route53_zone.tf deleted file mode 100644 index 66efb8e..0000000 --- a/infrastructure/terraform/components/acct/route53_zone.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "aws_route53_zone" "main" { - name = "web-gateway.${var.root_domain_name}" - - delegation_set_id = aws_route53_delegation_set.main.id -} diff --git a/infrastructure/terraform/components/acct/sns_topic_costs.tf b/infrastructure/terraform/components/acct/sns_topic_costs.tf deleted file mode 100644 index 1a455da..0000000 --- a/infrastructure/terraform/components/acct/sns_topic_costs.tf +++ /dev/null @@ -1,36 +0,0 @@ -resource "aws_sns_topic" "costs" { - name = "${local.csi}-costs" -} - -resource "aws_sns_topic_policy" "costs" { - arn = aws_sns_topic.costs.arn - - policy = data.aws_iam_policy_document.sns_costs.json -} - -data "aws_iam_policy_document" "sns_costs" { - statement { - sid = "AllowSNSCosts" - effect = "Allow" - - actions = [ - "SNS:Publish", - ] - - resources = [ - aws_sns_topic.costs.arn, - ] - - principals { - type = "Service" - identifiers = ["budgets.amazonaws.com", "costalerts.amazonaws.com"] - } - } -} - -resource "aws_sns_topic_subscription" "costs" { - for_each = toset(var.cost_alarm_recipients) - topic_arn = aws_sns_topic.costs.arn - protocol = "email" - endpoint = each.value -} diff --git a/infrastructure/terraform/components/acct/variables.tf b/infrastructure/terraform/components/acct/variables.tf deleted file mode 100644 index cbc3494..0000000 --- a/infrastructure/terraform/components/acct/variables.tf +++ /dev/null @@ -1,87 +0,0 @@ -## -# Basic Required Variables for tfscaffold Components -## - -variable "project" { - type = string - description = "The name of the tfscaffold project" -} - -variable "environment" { - type = string - description = "The name of the tfscaffold environment" -} - -variable "aws_account_id" { - type = string - description = "The AWS Account ID (numeric)" -} - -variable "region" { - type = string - description = "The AWS Region" -} - -variable "group" { - type = string - description = "The group variables are being inherited from (often synonmous with account short-name)" -} - -## -# tfscaffold variables specific to this component -## - -# This is the only primary variable to have its value defined as -# a default within its declaration in this file, because the variables -# purpose is as an identifier unique to this component, rather -# then to the environment from where all other variables come. -variable "component" { - type = string - description = "The variable encapsulating the name of this component" - default = "acct" -} - -variable "default_tags" { - type = map(string) - description = "A map of default tags to apply to all taggable resources within the component" - default = {} -} - -## -# Variables specific to the "dnsroot"component -## - -variable "log_retention_in_days" { - type = number - description = "The retention period in days for the Cloudwatch Logs events to be retained, default of 0 is indefinite" - default = 0 -} - -variable "root_domain_name" { - type = string - description = "The service's root DNS root nameespace, like nonprod.nhsnotify.national.nhs.uk" - default = "nonprod.nhsnotify.national.nhs.uk" -} - -variable "observability_account_id" { - type = string - description = "The Observability Account ID that needs access" -} - -variable "cost_alarm_recipients" { - type = list(string) - description = "A list of email addresses to receive alarm notifications" - default = [] -} - -variable "budget_amount" { - type = number - description = "The budget amount in USD for the account" - default = 500 -} - -variable "cost_anomaly_threshold" { - type = number - description = "The threshold percentage for cost anomaly detection" - default = 10 -} diff --git a/infrastructure/terraform/components/acct/versions.tf b/infrastructure/terraform/components/acct/versions.tf deleted file mode 100644 index 224cb0a..0000000 --- a/infrastructure/terraform/components/acct/versions.tf +++ /dev/null @@ -1,10 +0,0 @@ -terraform { - required_providers { - aws = { - source = "hashicorp/aws" - version = "~> 5.50" - } - } - - required_version = ">= 1.10.1" -} From 05d70c9f363bf3cceb9e87869a9354b993692646 Mon Sep 17 00:00:00 2001 From: aidenvaines-bjss Date: Fri, 1 Aug 2025 15:25:19 +0100 Subject: [PATCH 2/6] CCM-11211 Migration to shared Acct config --- .github/workflows/scorecard.yml | 2 +- .../terraform/components/cdn/README.md | 4 +-- .../components/cdn/iam_role_grafana_access.tf | 30 ------------------- .../terraform/components/cdn/locals.tf | 5 +++- .../components/cdn/locals_remote_state.tf | 21 +------------ ...e_lambda_rewrite_origin_branch_requests.tf | 2 +- ..._lambda_rewrite_viewer_trailing_slashes.tf | 2 +- .../components/cdn/module_s3bucket_cf_logs.tf | 2 +- .../cdn/route53_record_acm_validation.tf | 2 +- .../components/cdn/route53_record_alias.tf | 4 +-- .../terraform/components/cdn/variables.tf | 11 +++---- .../terraform/components/cdn/versions.tf | 2 +- 12 files changed, 21 insertions(+), 66 deletions(-) delete mode 100644 infrastructure/terraform/components/cdn/iam_role_grafana_access.tf diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 5552785..822410d 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -37,7 +37,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1 + uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 with: results_file: results.sarif results_format: sarif diff --git a/infrastructure/terraform/components/cdn/README.md b/infrastructure/terraform/components/cdn/README.md index c0cbec8..bbbfea5 100644 --- a/infrastructure/terraform/components/cdn/README.md +++ b/infrastructure/terraform/components/cdn/README.md @@ -7,7 +7,7 @@ | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.10.1 | -| [aws](#requirement\_aws) | ~> 5.50 | +| [aws](#requirement\_aws) | ~> 6.7 | | [github](#requirement\_github) | ~> 6.0 | ## Inputs @@ -27,10 +27,10 @@ | [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 | -| [observability\_account\_id](#input\_observability\_account\_id) | The Observability Account ID that needs access | `string` | n/a | yes | | [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 | +| [shared\_infra\_account\_id](#input\_shared\_infra\_account\_id) | The AWS Account ID of the shared infrastructure account | `string` | `"000000000000"` | no | | [template\_files\_origin\_domain\_name](#input\_template\_files\_origin\_domain\_name) | Domain name for template file download origin | `string` | n/a | yes | | [waf\_rate\_limit\_cdn](#input\_waf\_rate\_limit\_cdn) | The rate limit is the maximum number of CDN requests from a single IP address that are allowed in a five-minute period | `number` | `20000` | no | ## Modules diff --git a/infrastructure/terraform/components/cdn/iam_role_grafana_access.tf b/infrastructure/terraform/components/cdn/iam_role_grafana_access.tf deleted file mode 100644 index 33f09cf..0000000 --- a/infrastructure/terraform/components/cdn/iam_role_grafana_access.tf +++ /dev/null @@ -1,30 +0,0 @@ -resource "aws_iam_role" "grafana_access" { - name = replace("${local.csi}-obs-cross-access-role", "-${var.component}", "") - assume_role_policy = data.aws_iam_policy_document.observability_grafana_role_assume_role_policy.json -} - -data "aws_iam_policy_document" "observability_grafana_role_assume_role_policy" { - statement { - actions = ["sts:AssumeRole"] - effect = "Allow" - principals { - type = "AWS" - identifiers = [ - "arn:aws:iam::${var.observability_account_id}:root" - ] - } - condition { - test = "ArnLike" - variable = "aws:PrincipalArn" - - values = [ - "arn:aws:iam::${var.observability_account_id}:role/*obs-workspace-role" - ] - } - } -} - -resource "aws_iam_role_policy_attachment" "grafana_workspace_cloudwatch" { - role = aws_iam_role.grafana_access.name - policy_arn = "arn:aws:iam::aws:policy/CloudWatchReadOnlyAccess" -} diff --git a/infrastructure/terraform/components/cdn/locals.tf b/infrastructure/terraform/components/cdn/locals.tf index b9c5511..6c3a7f9 100644 --- a/infrastructure/terraform/components/cdn/locals.tf +++ b/infrastructure/terraform/components/cdn/locals.tf @@ -1,7 +1,10 @@ locals { - root_domain_name = "${var.environment}.${local.acct.dns_zone["name"]}" # e.g. [main|dev|abxy0].web-frontend.[dev|nonprod|prod].nhsnotify.national.nhs.uk aws_lambda_functions_dir_path = "../../../../lambdas" + root_domain_name = "${var.environment}.${local.acct.route53_zone_names["web-gw"]}" # e.g. [main|dev|abxy0].web-gateway.[dev|nonprod|prod].nhsnotify.national.nhs.uk + root_domain_id = local.acct.route53_zone_ids["web-gw"] + root_domain_nameservers = local.acct.route53_zone_nameservers["web-gw"] + cloudfront_error_map = { "400" : { error_code : 400, response_page_path : "/error/400", response_code : "400" }, "403" : { error_code : 403, response_page_path : "/error/403", response_code : "403" }, diff --git a/infrastructure/terraform/components/cdn/locals_remote_state.tf b/infrastructure/terraform/components/cdn/locals_remote_state.tf index 7f87c1f..8c8f24f 100644 --- a/infrastructure/terraform/components/cdn/locals_remote_state.tf +++ b/infrastructure/terraform/components/cdn/locals_remote_state.tf @@ -1,26 +1,7 @@ locals { - bootstrap = data.terraform_remote_state.bootstrap.outputs acct = data.terraform_remote_state.acct.outputs } -data "terraform_remote_state" "bootstrap" { - backend = "s3" - - config = { - bucket = local.terraform_state_bucket - - key = format( - "%s/%s/%s/%s/bootstrap.tfstate", - var.project, - var.aws_account_id, - "eu-west-2", - "bootstrap" - ) - - region = "eu-west-2" - } -} - data "terraform_remote_state" "acct" { backend = "s3" @@ -37,4 +18,4 @@ data "terraform_remote_state" "acct" { region = "eu-west-2" } -} +} \ No newline at end of file diff --git a/infrastructure/terraform/components/cdn/module_lambda_rewrite_origin_branch_requests.tf b/infrastructure/terraform/components/cdn/module_lambda_rewrite_origin_branch_requests.tf index c2e996c..f0d9986 100644 --- a/infrastructure/terraform/components/cdn/module_lambda_rewrite_origin_branch_requests.tf +++ b/infrastructure/terraform/components/cdn/module_lambda_rewrite_origin_branch_requests.tf @@ -22,7 +22,7 @@ module "lambda_rewrite_origin_branch_requests" { body = data.aws_iam_policy_document.lambda_rewrite_origin_branch_requests.json } - function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"] + function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts_us"]["id"] function_code_base_path = local.aws_lambda_functions_dir_path function_code_dir = "rewrite-origin-branch-requests/src" function_include_common = true diff --git a/infrastructure/terraform/components/cdn/module_lambda_rewrite_viewer_trailing_slashes.tf b/infrastructure/terraform/components/cdn/module_lambda_rewrite_viewer_trailing_slashes.tf index cdcdc16..7ba2b57 100644 --- a/infrastructure/terraform/components/cdn/module_lambda_rewrite_viewer_trailing_slashes.tf +++ b/infrastructure/terraform/components/cdn/module_lambda_rewrite_viewer_trailing_slashes.tf @@ -22,7 +22,7 @@ module "lambda_rewrite_viewer_trailing_slashes" { body = data.aws_iam_policy_document.lambda_rewrite_viewer_trailing_slashes.json } - function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"] + function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts_us"]["id"] function_code_base_path = local.aws_lambda_functions_dir_path function_code_dir = "rewrite-viewer-trailing-slashes/src" function_include_common = true diff --git a/infrastructure/terraform/components/cdn/module_s3bucket_cf_logs.tf b/infrastructure/terraform/components/cdn/module_s3bucket_cf_logs.tf index 26f8186..4c75c95 100644 --- a/infrastructure/terraform/components/cdn/module_s3bucket_cf_logs.tf +++ b/infrastructure/terraform/components/cdn/module_s3bucket_cf_logs.tf @@ -66,7 +66,7 @@ module "s3bucket_cf_logs" { ] bucket_logging_target = { - bucket = local.acct.s3_buckets["access_logs"]["id"] + bucket = local.acct.s3_buckets["access_logs_us"]["id"] } public_access = { diff --git a/infrastructure/terraform/components/cdn/route53_record_acm_validation.tf b/infrastructure/terraform/components/cdn/route53_record_acm_validation.tf index 3da05e7..06c1270 100644 --- a/infrastructure/terraform/components/cdn/route53_record_acm_validation.tf +++ b/infrastructure/terraform/components/cdn/route53_record_acm_validation.tf @@ -12,6 +12,6 @@ resource "aws_route53_record" "acm_validation" { name = each.value.name records = [each.value.record] type = each.value.type - zone_id = local.acct.dns_zone["id"] + zone_id = local.root_domain_id ttl = 60 } diff --git a/infrastructure/terraform/components/cdn/route53_record_alias.tf b/infrastructure/terraform/components/cdn/route53_record_alias.tf index 6ff206d..79951f6 100644 --- a/infrastructure/terraform/components/cdn/route53_record_alias.tf +++ b/infrastructure/terraform/components/cdn/route53_record_alias.tf @@ -1,6 +1,6 @@ resource "aws_route53_record" "alias_A" { name = local.root_domain_name - zone_id = local.acct.dns_zone["id"] + zone_id = local.root_domain_id type = "A" alias { @@ -12,7 +12,7 @@ resource "aws_route53_record" "alias_A" { resource "aws_route53_record" "alias_AAAA" { name = local.root_domain_name - zone_id = local.acct.dns_zone["id"] + zone_id = local.root_domain_id type = "AAAA" alias { diff --git a/infrastructure/terraform/components/cdn/variables.tf b/infrastructure/terraform/components/cdn/variables.tf index 862d677..d98d383 100644 --- a/infrastructure/terraform/components/cdn/variables.tf +++ b/infrastructure/terraform/components/cdn/variables.tf @@ -81,6 +81,12 @@ variable "parent_acct_environment" { default = "main" } +variable "shared_infra_account_id" { + type = string + description = "The AWS Account ID of the shared infrastructure account" + default = "000000000000" +} + variable "force_lambda_code_deploy" { type = bool description = "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" @@ -134,8 +140,3 @@ variable "template_files_origin_domain_name" { type = string description = "Domain name for template file download origin" } - -variable "observability_account_id" { - type = string - description = "The Observability Account ID that needs access" -} diff --git a/infrastructure/terraform/components/cdn/versions.tf b/infrastructure/terraform/components/cdn/versions.tf index f607c33..928403c 100644 --- a/infrastructure/terraform/components/cdn/versions.tf +++ b/infrastructure/terraform/components/cdn/versions.tf @@ -2,7 +2,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = "~> 5.50" + version = "~> 6.7" } github = { source = "integrations/github" From 08cb539a96e300f9e868bec680400e1d80363128 Mon Sep 17 00:00:00 2001 From: aidenvaines-bjss Date: Fri, 1 Aug 2025 15:27:51 +0100 Subject: [PATCH 3/6] CCM-11211 Migration to shared Acct config --- .github/workflows/pr_closed.yaml | 2 +- .github/workflows/release_created.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr_closed.yaml b/.github/workflows/pr_closed.yaml index 506a375..d16a309 100644 --- a/.github/workflows/pr_closed.yaml +++ b/.github/workflows/pr_closed.yaml @@ -43,7 +43,7 @@ jobs: strategy: max-parallel: 1 matrix: - component: [acct, cdn] + component: [cdn] uses: ./.github/workflows/reusable_internal_repo_build.yaml secrets: inherit diff --git a/.github/workflows/release_created.yaml b/.github/workflows/release_created.yaml index 5fae2f7..0bce598 100644 --- a/.github/workflows/release_created.yaml +++ b/.github/workflows/release_created.yaml @@ -19,7 +19,7 @@ jobs: strategy: max-parallel: 1 matrix: - component: [acct, cdn] + component: [cdn] uses: ./.github/workflows/reusable_internal_repo_build.yaml secrets: inherit From 644f706aa64a9f2369f2dd230eaad84fd8aa48d6 Mon Sep 17 00:00:00 2001 From: aidenvaines-bjss Date: Mon, 4 Aug 2025 11:30:34 +0100 Subject: [PATCH 4/6] CCM-11211 Migration to shared Acct config --- infrastructure/terraform/components/cdn/locals.tf | 1 - infrastructure/terraform/components/cdn/locals_remote_state.tf | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/infrastructure/terraform/components/cdn/locals.tf b/infrastructure/terraform/components/cdn/locals.tf index 6c3a7f9..985c4cb 100644 --- a/infrastructure/terraform/components/cdn/locals.tf +++ b/infrastructure/terraform/components/cdn/locals.tf @@ -19,4 +19,3 @@ locals { "504" : { error_code : 504, response_page_path : "/error/400", response_code : "504" }, } } - diff --git a/infrastructure/terraform/components/cdn/locals_remote_state.tf b/infrastructure/terraform/components/cdn/locals_remote_state.tf index 8c8f24f..074e241 100644 --- a/infrastructure/terraform/components/cdn/locals_remote_state.tf +++ b/infrastructure/terraform/components/cdn/locals_remote_state.tf @@ -18,4 +18,4 @@ data "terraform_remote_state" "acct" { region = "eu-west-2" } -} \ No newline at end of file +} From f9c2876887708af4126e22c62e23fc4aed9ad46d Mon Sep 17 00:00:00 2001 From: aidenvaines-bjss Date: Mon, 4 Aug 2025 16:50:21 +0100 Subject: [PATCH 5/6] CCM-11211 Bucket Destruction for dev --- .../terraform/components/cdn/module_s3bucket_cf_logs.tf | 2 +- infrastructure/terraform/components/cdn/variables.tf | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/infrastructure/terraform/components/cdn/module_s3bucket_cf_logs.tf b/infrastructure/terraform/components/cdn/module_s3bucket_cf_logs.tf index 4c75c95..09572d0 100644 --- a/infrastructure/terraform/components/cdn/module_s3bucket_cf_logs.tf +++ b/infrastructure/terraform/components/cdn/module_s3bucket_cf_logs.tf @@ -13,7 +13,7 @@ module "s3bucket_cf_logs" { component = var.component acl = "private" - force_destroy = false + force_destroy = var.force_s3_destroy versioning = true object_ownership = "ObjectWriter" diff --git a/infrastructure/terraform/components/cdn/variables.tf b/infrastructure/terraform/components/cdn/variables.tf index d98d383..7b3e742 100644 --- a/infrastructure/terraform/components/cdn/variables.tf +++ b/infrastructure/terraform/components/cdn/variables.tf @@ -93,6 +93,12 @@ variable "force_lambda_code_deploy" { default = false } +variable "force_s3_destroy" { + type = bool + description = "Flag to force deletion of S3 buckets" + default = false +} + variable "waf_rate_limit_cdn" { type = number description = "The rate limit is the maximum number of CDN requests from a single IP address that are allowed in a five-minute period" From 146c55b6b176d8d5d3482de4d01a61b3ca12bc35 Mon Sep 17 00:00:00 2001 From: aidenvaines-bjss Date: Mon, 4 Aug 2025 16:51:47 +0100 Subject: [PATCH 6/6] CCM-11211 Bucket Destruction for dev --- infrastructure/terraform/components/cdn/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/infrastructure/terraform/components/cdn/README.md b/infrastructure/terraform/components/cdn/README.md index bbbfea5..0c26572 100644 --- a/infrastructure/terraform/components/cdn/README.md +++ b/infrastructure/terraform/components/cdn/README.md @@ -23,6 +23,7 @@ | [enable\_github\_actions\_ip\_access](#input\_enable\_github\_actions\_ip\_access) | Should the Github actions runner IP addresses be permitted access to this distribution. This should not be enabled in production environments | `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 | +| [force\_s3\_destroy](#input\_force\_s3\_destroy) | Flag to force deletion of S3 buckets | `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 |