From c230418505552f7fb2806ce60e4e12a42e874e97 Mon Sep 17 00:00:00 2001 From: Greg Tyler Date: Thu, 26 Oct 2023 12:52:45 +0100 Subject: [PATCH] Add DNS records for environment (#23) Forward to API Gateway and use the DNS endpoint for tests. I've weighted 100% to eu-west-1 for now because multi-region signatures aren't well supported yet (i.e. you need to know which region you're signing for) and all our traffic originates in eu-west-1, but we should really take a proper look at this for future reliability. #minor --- .github/workflows/env-destroy.yml | 10 ---- terraform/account/apigateway.tf | 6 +++ terraform/account/region/dns.tf | 28 +++++++++++ terraform/account/region/terraform.tf | 13 +++++ terraform/account/region/variables.tf | 4 ++ terraform/account/regions.tf | 21 ++++++++ terraform/account/terraform.tf | 57 ++++++++++++++++++++++ terraform/account/variables.tf | 6 +++ terraform/environment/region/apigateway.tf | 12 +++++ terraform/environment/region/dns.tf | 45 +++++++++++++++++ terraform/environment/region/outputs.tf | 2 +- terraform/environment/region/variables.tf | 6 +++ terraform/environment/regions.tf | 2 + 13 files changed, 201 insertions(+), 11 deletions(-) create mode 100644 terraform/account/region/dns.tf create mode 100644 terraform/account/region/terraform.tf create mode 100644 terraform/account/region/variables.tf create mode 100644 terraform/account/regions.tf create mode 100644 terraform/environment/region/dns.tf diff --git a/.github/workflows/env-destroy.yml b/.github/workflows/env-destroy.yml index 238411f8..3a419276 100644 --- a/.github/workflows/env-destroy.yml +++ b/.github/workflows/env-destroy.yml @@ -52,13 +52,3 @@ jobs: terraform workspace select default terraform workspace delete ${{ inputs.workspace_name }} working-directory: ./terraform/environment - - - name: Destroy deployment environment - env: - GH_TOKEN: ${{ github.token }} - run: | - gh api \ - --method DELETE \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - /repos/${{ github.repository }}/environments/${{ inputs.workspace_name }} diff --git a/terraform/account/apigateway.tf b/terraform/account/apigateway.tf index 8a468a8a..90125175 100644 --- a/terraform/account/apigateway.tf +++ b/terraform/account/apigateway.tf @@ -1,6 +1,8 @@ resource "aws_iam_role" "api_gateway_cloudwatch" { name = "api-gateway-cloudwatch-global" assume_role_policy = data.aws_iam_policy_document.api_gateway_assume_role.json + + provider = aws.global } data "aws_iam_policy_document" "api_gateway_assume_role" { @@ -12,9 +14,13 @@ data "aws_iam_policy_document" "api_gateway_assume_role" { identifiers = ["apigateway.amazonaws.com"] } } + + provider = aws.global } resource "aws_iam_role_policy_attachment" "api_gateway_log_to_cloudwatch" { role = aws_iam_role.api_gateway_cloudwatch.id policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs" + + provider = aws.global } diff --git a/terraform/account/region/dns.tf b/terraform/account/region/dns.tf new file mode 100644 index 00000000..16fda2d0 --- /dev/null +++ b/terraform/account/region/dns.tf @@ -0,0 +1,28 @@ +locals { + domain_name = var.is_production ? data.aws_route53_zone.service.name : "*.${data.aws_route53_zone.service.name}" +} + +data "aws_route53_zone" "service" { + name = "lpa-store.api.opg.service.justice.gov.uk" + provider = aws.management +} + +resource "aws_acm_certificate" "environment" { + domain_name = local.domain_name + validation_method = "DNS" + lifecycle { + create_before_destroy = true + } + + provider = aws.region +} + +resource "aws_route53_record" "validation" { + name = sort(aws_acm_certificate.environment.domain_validation_options[*].resource_record_name)[0] + type = sort(aws_acm_certificate.environment.domain_validation_options[*].resource_record_type)[0] + zone_id = data.aws_route53_zone.service.id + records = [sort(aws_acm_certificate.environment.domain_validation_options[*].resource_record_value)[0]] + ttl = 60 + allow_overwrite = true + provider = aws.management +} diff --git a/terraform/account/region/terraform.tf b/terraform/account/region/terraform.tf new file mode 100644 index 00000000..2703e7fa --- /dev/null +++ b/terraform/account/region/terraform.tf @@ -0,0 +1,13 @@ +terraform { + required_version = ">= 1.4.0" + + required_providers { + aws = { + source = "hashicorp/aws" + configuration_aliases = [ + aws.region, + aws.management, + ] + } + } +} diff --git a/terraform/account/region/variables.tf b/terraform/account/region/variables.tf new file mode 100644 index 00000000..d251868e --- /dev/null +++ b/terraform/account/region/variables.tf @@ -0,0 +1,4 @@ +variable "is_production" { + description = "Whether this is a production environment" + type = bool +} diff --git a/terraform/account/regions.tf b/terraform/account/regions.tf new file mode 100644 index 00000000..bd571b8f --- /dev/null +++ b/terraform/account/regions.tf @@ -0,0 +1,21 @@ +module "eu_west_1" { + source = "./region" + + is_production = local.account.is_production + + providers = { + aws.region = aws.eu_west_1 + aws.management = aws.management_eu_west_1 + } +} + +module "eu_west_2" { + source = "./region" + + is_production = local.account.is_production + + providers = { + aws.region = aws.eu_west_2 + aws.management = aws.management_eu_west_2 + } +} diff --git a/terraform/account/terraform.tf b/terraform/account/terraform.tf index 631705a9..bae634fb 100644 --- a/terraform/account/terraform.tf +++ b/terraform/account/terraform.tf @@ -18,6 +18,7 @@ terraform { } provider "aws" { + alias = "eu_west_1" region = "eu-west-1" assume_role { @@ -29,3 +30,59 @@ provider "aws" { tags = local.default_tags } } + +provider "aws" { + alias = "eu_west_2" + region = "eu-west-2" + + assume_role { + role_arn = "arn:aws:iam::${local.account.account_id}:role/${var.default_role}" + session_name = "terraform-session" + } + + default_tags { + tags = local.default_tags + } +} + +provider "aws" { + alias = "global" + region = "us-east-1" + + assume_role { + role_arn = "arn:aws:iam::${local.account.account_id}:role/${var.default_role}" + session_name = "terraform-session" + } + + default_tags { + tags = local.default_tags + } +} + +provider "aws" { + alias = "management_eu_west_1" + region = "eu-west-1" + + assume_role { + role_arn = "arn:aws:iam::311462405659:role/${var.management_role}" + session_name = "terraform-session" + } + + default_tags { + tags = local.default_tags + } +} + +provider "aws" { + alias = "management_eu_west_2" + region = "eu-west-2" + + assume_role { + role_arn = "arn:aws:iam::311462405659:role/${var.management_role}" + session_name = "terraform-session" + } + + default_tags { + tags = local.default_tags + } +} diff --git a/terraform/account/variables.tf b/terraform/account/variables.tf index 6138be3e..4205850f 100644 --- a/terraform/account/variables.tf +++ b/terraform/account/variables.tf @@ -33,3 +33,9 @@ variable "default_role" { type = string default = "lpa-store-ci" } + +variable "management_role" { + description = "Role to assume in Management account" + type = string + default = "lpa-store-ci" +} diff --git a/terraform/environment/region/apigateway.tf b/terraform/environment/region/apigateway.tf index 56f7346d..9abf3b83 100644 --- a/terraform/environment/region/apigateway.tf +++ b/terraform/environment/region/apigateway.tf @@ -143,3 +143,15 @@ resource "aws_lambda_permission" "api_gateway_invoke" { provider = aws.region } + +resource "aws_api_gateway_base_path_mapping" "mapping" { + api_id = aws_api_gateway_rest_api.lpa_store.id + stage_name = aws_api_gateway_stage.current.stage_name + domain_name = aws_api_gateway_domain_name.lpa_store.domain_name + + lifecycle { + create_before_destroy = true + } + + provider = aws.region +} diff --git a/terraform/environment/region/dns.tf b/terraform/environment/region/dns.tf new file mode 100644 index 00000000..11b3881b --- /dev/null +++ b/terraform/environment/region/dns.tf @@ -0,0 +1,45 @@ +locals { + a_record = terraform.workspace == "production" ? data.aws_route53_zone.service.name : var.environment_name + domain_name = terraform.workspace == "production" ? data.aws_route53_zone.service.name : "${local.a_record}.${data.aws_route53_zone.service.name}" +} + +data "aws_route53_zone" "service" { + name = "lpa-store.api.opg.service.justice.gov.uk" + provider = aws.management +} + +data "aws_acm_certificate" "root" { + domain = terraform.workspace == "production" ? data.aws_route53_zone.service.name : "*.${data.aws_route53_zone.service.name}" + provider = aws.region +} + +resource "aws_route53_record" "environment_record" { + name = local.a_record + type = "A" + zone_id = data.aws_route53_zone.service.id + set_identifier = data.aws_region.current.name + + weighted_routing_policy { + weight = var.dns_weighting + } + + alias { + evaluate_target_health = true + name = aws_api_gateway_domain_name.lpa_store.regional_domain_name + zone_id = aws_api_gateway_domain_name.lpa_store.regional_zone_id + } + + provider = aws.management +} + +resource "aws_api_gateway_domain_name" "lpa_store" { + domain_name = local.domain_name + regional_certificate_arn = data.aws_acm_certificate.root.arn + security_policy = "TLS_1_2" + + endpoint_configuration { + types = ["REGIONAL"] + } + + provider = aws.region +} diff --git a/terraform/environment/region/outputs.tf b/terraform/environment/region/outputs.tf index b1237ada..83d052f6 100644 --- a/terraform/environment/region/outputs.tf +++ b/terraform/environment/region/outputs.tf @@ -1,3 +1,3 @@ output "base_url" { - value = aws_api_gateway_stage.current.invoke_url + value = "https://${local.domain_name}" } diff --git a/terraform/environment/region/variables.tf b/terraform/environment/region/variables.tf index 7afefc33..f3bcc27e 100644 --- a/terraform/environment/region/variables.tf +++ b/terraform/environment/region/variables.tf @@ -22,3 +22,9 @@ variable "allowed_arns" { description = "List of external ARNs allowed to access the API Gateway" type = list(string) } + +variable "dns_weighting" { + description = "What percentage of DNS traffic to send to this region" + type = number + default = 50 +} diff --git a/terraform/environment/regions.tf b/terraform/environment/regions.tf index d5f7d29a..95d966f7 100644 --- a/terraform/environment/regions.tf +++ b/terraform/environment/regions.tf @@ -6,6 +6,7 @@ module "eu_west_1" { dynamodb_name = aws_dynamodb_table.deeds_table.name environment_name = local.environment_name allowed_arns = local.environment.allowed_arns + dns_weighting = 100 providers = { aws.region = aws.eu_west_1 @@ -21,6 +22,7 @@ module "eu_west_2" { dynamodb_name = aws_dynamodb_table.deeds_table.name environment_name = local.environment_name allowed_arns = local.environment.allowed_arns + dns_weighting = 0 providers = { aws.region = aws.eu_west_2