From eb89698761bfdfb6a2e4a4aa9731d3b2f80cd617 Mon Sep 17 00:00:00 2001 From: Alexandre Henrique Afonso Campos Date: Fri, 5 Jan 2024 22:59:39 -0300 Subject: [PATCH 01/13] Add terraform file --- iac/main.tf | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 iac/main.tf diff --git a/iac/main.tf b/iac/main.tf new file mode 100644 index 000000000..1ccdd8dbb --- /dev/null +++ b/iac/main.tf @@ -0,0 +1,20 @@ +terraform { + backend "s3" { + bucket = "NON-EXISTING-BUCKET" + key = "tnoodle-web-scramble" + region = "us-west-2" + } +} + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } +} + +provider "aws" { + region = "us-west-2" +} From a60163e5d7605a10fa9729a6fd2b0d0245f6fe0b Mon Sep 17 00:00:00 2001 From: Alexandre Henrique Afonso Campos Date: Fri, 5 Jan 2024 23:02:34 -0300 Subject: [PATCH 02/13] Generate lock file --- .gitignore | 2 ++ iac/.terraform.lock.hcl | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 iac/.terraform.lock.hcl diff --git a/.gitignore b/.gitignore index f3fe0ca18..e0e81e577 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,5 @@ gradle.properties .idea/ .vscode/ + +.terraform/ diff --git a/iac/.terraform.lock.hcl b/iac/.terraform.lock.hcl new file mode 100644 index 000000000..c778d62e3 --- /dev/null +++ b/iac/.terraform.lock.hcl @@ -0,0 +1,25 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.31.0" + constraints = "~> 5.0" + hashes = [ + "h1:ltxyuBWIy9cq0kIKDJH1jeWJy/y7XJLjS4QrsQK4plA=", + "zh:0cdb9c2083bf0902442384f7309367791e4640581652dda456f2d6d7abf0de8d", + "zh:2fe4884cb9642f48a5889f8dff8f5f511418a18537a9dfa77ada3bcdad391e4e", + "zh:36d8bdd72fe61d816d0049c179f495bc6f1e54d8d7b07c45b62e5e1696882a89", + "zh:539dd156e3ec608818eb21191697b230117437a58587cbd02ce533202a4dd520", + "zh:6a53f4b57ac4eb3479fc0d8b6e301ca3a27efae4c55d9f8bd24071b12a03361c", + "zh:6faeb8ff6792ca7af1c025255755ad764667a300291cc10cea0c615479488c87", + "zh:7d9423149b323f6d0df5b90c4d9029e5455c670aea2a7eb6fef4684ba7eb2e0b", + "zh:8235badd8a5d0993421cacf5ead48fac73d3b5a25c8a68599706a404b1f70730", + "zh:860b4f60842b2879c5128b7e386c8b49adeda9287fed12c5cd74861bb659bbcd", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:b021fceaf9382c8fe3c6eb608c24d01dce3d11ba7e65bb443d51ca9b90e9b237", + "zh:b38b0bfc1c69e714e80cf1c9ea06e687ee86aa9f45694be28eb07adcebbe0489", + "zh:c972d155f6c01af9690a72adfb99cfc24ef5ef311ca92ce46b9b13c5c153f572", + "zh:e0dd29920ec84fdb6026acff44dcc1fb1a24a0caa093fa04cdbc713d384c651d", + "zh:e3127ebd2cb0374cd1808f911e6bffe2f4ac4d84317061381242353f3a7bc27d", + ] +} From b46214b8637320b5fea4ee366a76f200fe795fdf Mon Sep 17 00:00:00 2001 From: Alexandre Henrique Afonso Campos Date: Fri, 5 Jan 2024 23:08:51 -0300 Subject: [PATCH 03/13] Add ECS cluster --- iac/ecs.tf | 7 +++++++ iac/variable.tf | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 iac/ecs.tf create mode 100644 iac/variable.tf diff --git a/iac/ecs.tf b/iac/ecs.tf new file mode 100644 index 000000000..732445325 --- /dev/null +++ b/iac/ecs.tf @@ -0,0 +1,7 @@ +resource "aws_ecs_cluster" "keycloak_cluster" { + name = "tnoodle-cluster" + + tags = { + (var.type) = var.type_ecs + } +} diff --git a/iac/variable.tf b/iac/variable.tf new file mode 100644 index 000000000..da2eebdbf --- /dev/null +++ b/iac/variable.tf @@ -0,0 +1,7 @@ +variable "type" { + default = "Type" +} + +variable "type_ecs" { + default = "ECS" +} From 37602a4118d5a680f4e2d10b5d252e180d781e64 Mon Sep 17 00:00:00 2001 From: Alexandre Henrique Afonso Campos Date: Fri, 5 Jan 2024 23:29:05 -0300 Subject: [PATCH 04/13] Add ECR and ECS service --- iac/ecr.tf | 17 ++++++++++ iac/ecs.tf | 24 +++++++++++++- iac/role.tf | 33 +++++++++++++++++++ .../container-definitions/tnoodle.json | 23 +++++++++++++ iac/templates/ecr/expire-policy.json | 16 +++++++++ iac/variable.tf | 24 ++++++++++++++ 6 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 iac/ecr.tf create mode 100644 iac/role.tf create mode 100644 iac/templates/container-definitions/tnoodle.json create mode 100644 iac/templates/ecr/expire-policy.json diff --git a/iac/ecr.tf b/iac/ecr.tf new file mode 100644 index 000000000..48b336f50 --- /dev/null +++ b/iac/ecr.tf @@ -0,0 +1,17 @@ +resource "aws_ecr_repository" "tnoodle" { + name = "tnoodle" + + image_scanning_configuration { + scan_on_push = true + } + + tags = { + (var.type) = var.type_ecr + } +} + +resource "aws_ecr_lifecycle_policy" "expire_policy" { + repository = aws_ecr_repository.tnoodle.name + + policy = templatefile("./templates/ecr/expire-policy.json", {}) +} diff --git a/iac/ecs.tf b/iac/ecs.tf index 732445325..9c1a388c0 100644 --- a/iac/ecs.tf +++ b/iac/ecs.tf @@ -1,7 +1,29 @@ -resource "aws_ecs_cluster" "keycloak_cluster" { +resource "aws_ecs_cluster" "tnoodle_cluster" { name = "tnoodle-cluster" tags = { (var.type) = var.type_ecs } } + +resource "aws_ecs_task_definition" "tnoodle_task_definition" { + family = "tnoodle-task-definition" + network_mode = "awsvpc" + requires_compatibilities = ["FARGATE"] + cpu = var.fargate_cpu + memory = var.fargate_memory + execution_role_arn = aws_iam_role.ecs_task_execution_role.arn + task_role_arn = aws_iam_role.ecs_task_execution_role.arn + + container_definitions = templatefile("./templates/container-definitions/tnoodle.json", { + app_image = aws_ecr_repository.tnoodle.repository_url + aws_region = var.aws_region + app_port = var.tnoodle_port + container_name = var.tnoodle_name + fargate_cpu = var.fargate_cpu + fargate_memory = var.fargate_memory + }) + tags = { + (var.type) = var.type_ecs + } +} diff --git a/iac/role.tf b/iac/role.tf new file mode 100644 index 000000000..59692658c --- /dev/null +++ b/iac/role.tf @@ -0,0 +1,33 @@ +data "aws_iam_policy_document" "ecs_task_execution_role" { + version = "2012-10-17" + statement { + sid = "" + effect = "Allow" + actions = ["sts:AssumeRole"] + + principals { + type = "Service" + identifiers = ["ecs-tasks.amazonaws.com"] + } + } +} + +resource "aws_iam_role" "ecs_task_execution_role" { + name = "tnoodle-task-execution-role" + assume_role_policy = data.aws_iam_policy_document.ecs_task_execution_role.json + + inline_policy { + name = "tnoodle-task-execution-role-policy" + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = ["logs:*"] + Effect = "Allow" + Resource = "*" + } + ] + }) + } +} diff --git a/iac/templates/container-definitions/tnoodle.json b/iac/templates/container-definitions/tnoodle.json new file mode 100644 index 000000000..443c00b44 --- /dev/null +++ b/iac/templates/container-definitions/tnoodle.json @@ -0,0 +1,23 @@ +[ + { + "name": "${container_name}", + "image": "${app_image}", + "cpu": "${fargate_cpu}", + "memory": "${fargate_memory}", + "networkMode": "awsvpc", + "logConfiguration": { + "logDriver": "awslogs", + "options": { + "awslogs-group": "/ecs/${container_name}", + "awslogs-region": "${aws_region}", + "awslogs-stream-prefix": "ecs" + } + }, + "portMappings": [ + { + "containerPort": "${app_port}", + "hostPort": "${app_port}" + } + ] + } +] diff --git a/iac/templates/ecr/expire-policy.json b/iac/templates/ecr/expire-policy.json new file mode 100644 index 000000000..e5b5363c6 --- /dev/null +++ b/iac/templates/ecr/expire-policy.json @@ -0,0 +1,16 @@ +{ + "rules": [ + { + "rulePriority": 1, + "description": "Keep last 2 images", + "selection": { + "tagStatus": "any", + "countType": "imageCountMoreThan", + "countNumber": 2 + }, + "action": { + "type": "expire" + } + } + ] +} diff --git a/iac/variable.tf b/iac/variable.tf index da2eebdbf..0d0f9856f 100644 --- a/iac/variable.tf +++ b/iac/variable.tf @@ -5,3 +5,27 @@ variable "type" { variable "type_ecs" { default = "ECS" } + +variable "aws_region" { + default = "us-west-2" +} + +variable "tnoodle_name" { + default = "tnoodle" +} + +variable "type_ecr" { + default = "ECR" +} + +variable "tnoodle_port" { + default = "2014" +} + +variable "fargate_cpu" { + default = "1024" # 1 vCPU +} + +variable "fargate_memory" { + default = "2048" # 2 GB +} From eb44a5f0f6c1940a5de1be3309a69c577106d979 Mon Sep 17 00:00:00 2001 From: Alexandre Henrique Afonso Campos Date: Fri, 5 Jan 2024 23:42:28 -0300 Subject: [PATCH 05/13] Add remaining resources --- iac/alb.tf | 50 ++++++++++++++++ iac/certificate.tf | 4 ++ iac/ecs.tf | 27 ++++++++- iac/security-group.tf | 59 +++++++++++++++++++ iac/subnet.tf | 15 +++++ .../{tnoodle.json => tnoodle.json.tpl} | 8 +-- iac/variable.tf | 24 ++++++++ iac/vpc.tf | 5 ++ 8 files changed, 187 insertions(+), 5 deletions(-) create mode 100644 iac/alb.tf create mode 100644 iac/certificate.tf create mode 100644 iac/security-group.tf create mode 100644 iac/subnet.tf rename iac/templates/container-definitions/{tnoodle.json => tnoodle.json.tpl} (73%) create mode 100644 iac/vpc.tf diff --git a/iac/alb.tf b/iac/alb.tf new file mode 100644 index 000000000..87faf8b84 --- /dev/null +++ b/iac/alb.tf @@ -0,0 +1,50 @@ +resource "aws_alb" "tnoodle_load_balancer" { + name = "tnoodle-alb" + security_groups = [aws_security_group.http_security_group.id] + subnets = [aws_default_subnet.default_az1.id, aws_default_subnet.default_az2.id] + idle_timeout = 300 + + tags = { + (var.type) = var.type_alb + } +} + +resource "aws_alb_listener" "api_lb_listener" { + load_balancer_arn = aws_alb.tnoodle_load_balancer.arn + port = var.https_port + protocol = "HTTPS" + certificate_arn = data.aws_acm_certificate.certificate.arn + ssl_policy = "ELBSecurityPolicy-TLS-1-2-Ext-2018-06" + + default_action { + target_group_arn = aws_lb_target_group.tnoodle_tg.arn + type = "forward" + } +} + +resource "aws_lb_target_group" "tnoodle_tg" { + name_prefix = "kctg1" + port = var.tnoodle_port + protocol = "HTTP" + vpc_id = aws_default_vpc.default.id + target_type = "ip" + + lifecycle { + create_before_destroy = true + } + + health_check { + healthy_threshold = "3" + interval = "60" + protocol = "HTTP" + matcher = "200" + timeout = "3" + path = "/" + unhealthy_threshold = "2" + } + + tags = { + (var.type) = var.type_tg + } + depends_on = [aws_alb.tnoodle_load_balancer] +} diff --git a/iac/certificate.tf b/iac/certificate.tf new file mode 100644 index 000000000..8a28f8695 --- /dev/null +++ b/iac/certificate.tf @@ -0,0 +1,4 @@ +data "aws_acm_certificate" "certificate" { + domain = "*.worldcubeassociation.org" + statuses = ["ISSUED"] +} diff --git a/iac/ecs.tf b/iac/ecs.tf index 9c1a388c0..65da38129 100644 --- a/iac/ecs.tf +++ b/iac/ecs.tf @@ -15,7 +15,7 @@ resource "aws_ecs_task_definition" "tnoodle_task_definition" { execution_role_arn = aws_iam_role.ecs_task_execution_role.arn task_role_arn = aws_iam_role.ecs_task_execution_role.arn - container_definitions = templatefile("./templates/container-definitions/tnoodle.json", { + container_definitions = templatefile("./templates/container-definitions/tnoodle.json.tpl", { app_image = aws_ecr_repository.tnoodle.repository_url aws_region = var.aws_region app_port = var.tnoodle_port @@ -27,3 +27,28 @@ resource "aws_ecs_task_definition" "tnoodle_task_definition" { (var.type) = var.type_ecs } } + +resource "aws_ecs_service" "tnoodle_service" { + name = "tnoodle-service" + cluster = aws_ecs_cluster.tnoodle_cluster.id + desired_count = 1 + launch_type = "FARGATE" + + task_definition = aws_ecs_task_definition.tnoodle_task_definition.arn + + network_configuration { + subnets = [aws_default_subnet.default_az1.id] + security_groups = [aws_security_group.allow_tnoodle_default_port.id] + assign_public_ip = true + } + + load_balancer { + target_group_arn = aws_lb_target_group.tnoodle_tg.arn + container_name = var.tnoodle_name + container_port = var.tnoodle_port + } + + tags = { + (var.type) = var.type_ecs + } +} diff --git a/iac/security-group.tf b/iac/security-group.tf new file mode 100644 index 000000000..89b62f898 --- /dev/null +++ b/iac/security-group.tf @@ -0,0 +1,59 @@ +resource "aws_security_group" "http_security_group" { + name = "http-security-group-tnoodle" + description = "Allow HTTP" + vpc_id = aws_default_vpc.default.id + + ingress { + description = "HTTP" + from_port = var.http_port + to_port = var.http_port + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + ingress { + description = "HTTPS" + from_port = var.https_port + to_port = var.https_port + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + ipv6_cidr_blocks = ["::/0"] + } + + tags = { + (var.type) = var.type_sg + } +} + +resource "aws_security_group" "allow_tnoodle_default_port" { + name = "tnoodle-default-port" + description = "Allow connection to tnoodle default port" + vpc_id = aws_default_vpc.default.id + + ingress { + description = "tnoodle" + from_port = var.tnoodle_port + to_port = var.tnoodle_port + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + ipv6_cidr_blocks = ["::/0"] + } + + tags = { + (var.type) = var.type_sg + } +} diff --git a/iac/subnet.tf b/iac/subnet.tf new file mode 100644 index 000000000..e1640feb1 --- /dev/null +++ b/iac/subnet.tf @@ -0,0 +1,15 @@ +resource "aws_default_subnet" "default_az1" { + availability_zone = "us-west-2a" + + tags = { + (var.type) = var.type_subnet + } +} + +resource "aws_default_subnet" "default_az2" { + availability_zone = "us-west-2b" + + tags = { + (var.type) = var.type_subnet + } +} diff --git a/iac/templates/container-definitions/tnoodle.json b/iac/templates/container-definitions/tnoodle.json.tpl similarity index 73% rename from iac/templates/container-definitions/tnoodle.json rename to iac/templates/container-definitions/tnoodle.json.tpl index 443c00b44..01d3b1c30 100644 --- a/iac/templates/container-definitions/tnoodle.json +++ b/iac/templates/container-definitions/tnoodle.json.tpl @@ -2,8 +2,8 @@ { "name": "${container_name}", "image": "${app_image}", - "cpu": "${fargate_cpu}", - "memory": "${fargate_memory}", + "cpu": ${fargate_cpu}, + "memory": ${fargate_memory}, "networkMode": "awsvpc", "logConfiguration": { "logDriver": "awslogs", @@ -15,8 +15,8 @@ }, "portMappings": [ { - "containerPort": "${app_port}", - "hostPort": "${app_port}" + "containerPort": ${app_port}, + "hostPort": ${app_port} } ] } diff --git a/iac/variable.tf b/iac/variable.tf index 0d0f9856f..4640f7a1d 100644 --- a/iac/variable.tf +++ b/iac/variable.tf @@ -29,3 +29,27 @@ variable "fargate_cpu" { variable "fargate_memory" { default = "2048" # 2 GB } + +variable "type_subnet" { + default = "SUBNET" +} + +variable "type_sg" { + default = "SECURITY-GROUP" +} + +variable "type_tg" { + default = "TARGET-GROUP" +} + +variable "type_alb" { + default = "LOAD-BALANCER" +} + +variable "http_port" { + default = "80" +} + +variable "https_port" { + default = "443" +} diff --git a/iac/vpc.tf b/iac/vpc.tf new file mode 100644 index 000000000..0de2ad595 --- /dev/null +++ b/iac/vpc.tf @@ -0,0 +1,5 @@ +resource "aws_default_vpc" "default" { + tags = { + Name = "Default VPC" + } +} From 230cc30622c966e4d80f7336d9ada3197efd3a60 Mon Sep 17 00:00:00 2001 From: Alexandre Henrique Afonso Campos Date: Sat, 6 Jan 2024 00:08:11 -0300 Subject: [PATCH 06/13] Allow to create log groups --- iac/role.tf | 5 +++++ iac/templates/container-definitions/tnoodle.json.tpl | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/iac/role.tf b/iac/role.tf index 59692658c..64ccd04ef 100644 --- a/iac/role.tf +++ b/iac/role.tf @@ -26,6 +26,11 @@ resource "aws_iam_role" "ecs_task_execution_role" { Action = ["logs:*"] Effect = "Allow" Resource = "*" + }, + { + Action = ["ecr:GetAuthorizationToken"] + Effect = "Allow" + Resource = "*" } ] }) diff --git a/iac/templates/container-definitions/tnoodle.json.tpl b/iac/templates/container-definitions/tnoodle.json.tpl index 01d3b1c30..0ba5fcca7 100644 --- a/iac/templates/container-definitions/tnoodle.json.tpl +++ b/iac/templates/container-definitions/tnoodle.json.tpl @@ -10,7 +10,8 @@ "options": { "awslogs-group": "/ecs/${container_name}", "awslogs-region": "${aws_region}", - "awslogs-stream-prefix": "ecs" + "awslogs-stream-prefix": "ecs", + "awslogs-create-group": "true" } }, "portMappings": [ From ca972a04344a54c69c86943a0f530a8e46a84afa Mon Sep 17 00:00:00 2001 From: Alexandre Henrique Afonso Campos Date: Sat, 6 Jan 2024 00:39:41 -0300 Subject: [PATCH 07/13] Be more permissive with ecr, add latest to the image --- iac/role.tf | 2 +- iac/templates/container-definitions/tnoodle.json.tpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iac/role.tf b/iac/role.tf index 64ccd04ef..8b44d9ded 100644 --- a/iac/role.tf +++ b/iac/role.tf @@ -28,7 +28,7 @@ resource "aws_iam_role" "ecs_task_execution_role" { Resource = "*" }, { - Action = ["ecr:GetAuthorizationToken"] + Action = ["ecr:*"] Effect = "Allow" Resource = "*" } diff --git a/iac/templates/container-definitions/tnoodle.json.tpl b/iac/templates/container-definitions/tnoodle.json.tpl index 0ba5fcca7..33a4aad2d 100644 --- a/iac/templates/container-definitions/tnoodle.json.tpl +++ b/iac/templates/container-definitions/tnoodle.json.tpl @@ -1,7 +1,7 @@ [ { "name": "${container_name}", - "image": "${app_image}", + "image": "${app_image}:latest", "cpu": ${fargate_cpu}, "memory": ${fargate_memory}, "networkMode": "awsvpc", From e83fcb27a787e0589abdbb4dc87db8dc6af232cd Mon Sep 17 00:00:00 2001 From: Alexandre Henrique Afonso Campos Date: Sun, 5 May 2024 21:13:59 -0300 Subject: [PATCH 08/13] Ignore tag changes to avoid conflict with other iac in wca --- iac/subnet.tf | 8 ++++---- iac/vpc.tf | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iac/subnet.tf b/iac/subnet.tf index e1640feb1..cf898e670 100644 --- a/iac/subnet.tf +++ b/iac/subnet.tf @@ -1,15 +1,15 @@ resource "aws_default_subnet" "default_az1" { availability_zone = "us-west-2a" - tags = { - (var.type) = var.type_subnet + lifecycle { + ignore_changes = [tags] } } resource "aws_default_subnet" "default_az2" { availability_zone = "us-west-2b" - tags = { - (var.type) = var.type_subnet + lifecycle { + ignore_changes = [tags] } } diff --git a/iac/vpc.tf b/iac/vpc.tf index 0de2ad595..4d9541989 100644 --- a/iac/vpc.tf +++ b/iac/vpc.tf @@ -1,5 +1,5 @@ resource "aws_default_vpc" "default" { - tags = { - Name = "Default VPC" + lifecycle { + ignore_changes = [tags] } } From ce8db22e8c2b51b94f9216bf1205af123a744f19 Mon Sep 17 00:00:00 2001 From: Alexandre Henrique Afonso Campos Date: Sun, 5 May 2024 21:25:41 -0300 Subject: [PATCH 09/13] Add route 53 --- iac/data-ssm.tf | 3 +++ iac/route53.tf | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 iac/data-ssm.tf create mode 100644 iac/route53.tf diff --git a/iac/data-ssm.tf b/iac/data-ssm.tf new file mode 100644 index 000000000..9b27e5886 --- /dev/null +++ b/iac/data-ssm.tf @@ -0,0 +1,3 @@ +data "aws_ssm_parameter" "wca_zone_id" { + name = "/route53/wca-zone-id" +} diff --git a/iac/route53.tf b/iac/route53.tf new file mode 100644 index 000000000..e6be60ea0 --- /dev/null +++ b/iac/route53.tf @@ -0,0 +1,25 @@ +# tnoodle.worldcubeassociation.org +resource "aws_route53_record" "project_record" { + zone_id = data.aws_ssm_parameter.wca_zone_id.value + name = var.tnoodle_name + type = "A" + + alias { + name = "dualstack.${aws_alb.tnoodle_load_balancer.dns_name}" + evaluate_target_health = true + zone_id = aws_alb.tnoodle_load_balancer.zone_id + } +} + +# scramble.worldcubeassociation.org +resource "aws_route53_record" "project_record" { + zone_id = data.aws_ssm_parameter.wca_zone_id.value + name = "scramble" + type = "A" + + alias { + name = "dualstack.${aws_alb.tnoodle_load_balancer.dns_name}" + evaluate_target_health = true + zone_id = aws_alb.tnoodle_load_balancer.zone_id + } +} From 320f70089c10aef5c57899a55c33454487409a1f Mon Sep 17 00:00:00 2001 From: Alexandre Henrique Afonso Campos Date: Mon, 6 May 2024 07:59:48 -0300 Subject: [PATCH 10/13] Add DS Store to gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e0e81e577..f177148ef 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ gradle.properties .vscode/ .terraform/ + +.DS_Store From def6421c8160ea87279e6251b81b6d541f1ed0da Mon Sep 17 00:00:00 2001 From: Alexandre Henrique Afonso Campos Date: Mon, 6 May 2024 08:43:13 -0300 Subject: [PATCH 11/13] Add instructions for iac --- iac/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 iac/README.md diff --git a/iac/README.md b/iac/README.md new file mode 100644 index 000000000..8a5fc16f9 --- /dev/null +++ b/iac/README.md @@ -0,0 +1,17 @@ +# IAC for TNoodle + +## Requirements + +- Terraform +- AWS Account with credentials configured + +## Get started + +```bash +cd iac +terraform init +terraform apply -target='module.tnoodle_frontend.aws_s3_bucket.fontend_bucket' +terraform apply +``` + +If you agree with the plan in the output, type `yes`. From 6215443e74e6bc8e953230ecd5aee3f02187cf65 Mon Sep 17 00:00:00 2001 From: Alexandre Henrique Afonso Campos Date: Mon, 6 May 2024 08:44:32 -0300 Subject: [PATCH 12/13] Add frontend module --- iac/.terraform.lock.hcl | 60 ++++++++++++++++++++++++++++++ iac/certificate.tf | 15 +++++++- iac/frontend.tf | 10 +++++ iac/modules/frontend/README.md | 3 ++ iac/modules/frontend/cloudfront.tf | 37 ++++++++++++++++++ iac/modules/frontend/main.tf | 0 iac/modules/frontend/outputs.tf | 12 ++++++ iac/modules/frontend/route53.tf | 11 ++++++ iac/modules/frontend/s3.tf | 3 ++ iac/modules/frontend/variables.tf | 23 ++++++++++++ iac/outputs.tf | 3 ++ iac/route53.tf | 10 ++--- iac/variable.tf | 9 +++++ 13 files changed, 190 insertions(+), 6 deletions(-) create mode 100644 iac/frontend.tf create mode 100644 iac/modules/frontend/README.md create mode 100644 iac/modules/frontend/cloudfront.tf create mode 100644 iac/modules/frontend/main.tf create mode 100644 iac/modules/frontend/outputs.tf create mode 100644 iac/modules/frontend/route53.tf create mode 100644 iac/modules/frontend/s3.tf create mode 100644 iac/modules/frontend/variables.tf create mode 100644 iac/outputs.tf diff --git a/iac/.terraform.lock.hcl b/iac/.terraform.lock.hcl index c778d62e3..94d82bc64 100644 --- a/iac/.terraform.lock.hcl +++ b/iac/.terraform.lock.hcl @@ -23,3 +23,63 @@ provider "registry.terraform.io/hashicorp/aws" { "zh:e3127ebd2cb0374cd1808f911e6bffe2f4ac4d84317061381242353f3a7bc27d", ] } + +provider "registry.terraform.io/hashicorp/local" { + version = "2.5.1" + constraints = ">= 1.2.0" + hashes = [ + "h1:/GAVA/xheGQcbOZEq0qxANOg+KVLCA7Wv8qluxhTjhU=", + "zh:0af29ce2b7b5712319bf6424cb58d13b852bf9a777011a545fac99c7fdcdf561", + "zh:126063ea0d79dad1f68fa4e4d556793c0108ce278034f101d1dbbb2463924561", + "zh:196bfb49086f22fd4db46033e01655b0e5e036a5582d250412cc690fa7995de5", + "zh:37c92ec084d059d37d6cffdb683ccf68e3a5f8d2eb69dd73c8e43ad003ef8d24", + "zh:4269f01a98513651ad66763c16b268f4c2da76cc892ccfd54b401fff6cc11667", + "zh:51904350b9c728f963eef0c28f1d43e73d010333133eb7f30999a8fb6a0cc3d8", + "zh:73a66611359b83d0c3fcba2984610273f7954002febb8a57242bbb86d967b635", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:7ae387993a92bcc379063229b3cce8af7eaf082dd9306598fcd42352994d2de0", + "zh:9e0f365f807b088646db6e4a8d4b188129d9ebdbcf2568c8ab33bddd1b82c867", + "zh:b5263acbd8ae51c9cbffa79743fbcadcb7908057c87eb22fd9048268056efbc4", + "zh:dfcd88ac5f13c0d04e24be00b686d069b4879cc4add1b7b1a8ae545783d97520", + ] +} + +provider "registry.terraform.io/hashicorp/random" { + version = "3.6.1" + constraints = ">= 2.2.0" + hashes = [ + "h1:a+Goawwh6Qtg4/bRWzfDtIdrEFfPlnVy0y4LdUQY3nI=", + "zh:2a0ec154e39911f19c8214acd6241e469157489fc56b6c739f45fbed5896a176", + "zh:57f4e553224a5e849c99131f5e5294be3a7adcabe2d867d8a4fef8d0976e0e52", + "zh:58f09948c608e601bd9d0a9e47dcb78e2b2c13b4bda4d8f097d09152ea9e91c5", + "zh:5c2a297146ed6fb3fe934c800e78380f700f49ff24dbb5fb5463134948e3a65f", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:7ce41e26f0603e31cdac849085fc99e5cd5b3b73414c6c6d955c0ceb249b593f", + "zh:8c9e8d30c4ef08ee8bcc4294dbf3c2115cd7d9049c6ba21422bd3471d92faf8a", + "zh:93e91be717a7ffbd6410120eb925ebb8658cc8f563de35a8b53804d33c51c8b0", + "zh:982542e921970d727ce10ed64795bf36c4dec77a5db0741d4665230d12250a0d", + "zh:b9d1873f14d6033e216510ef541c891f44d249464f13cc07d3f782d09c7d18de", + "zh:cfe27faa0bc9556391c8803ade135a5856c34a3fe85b9ae3bdd515013c0c87c1", + "zh:e4aabf3184bbb556b89e4b195eab1514c86a2914dd01c23ad9813ec17e863a8a", + ] +} + +provider "registry.terraform.io/hashicorp/time" { + version = "0.11.1" + constraints = ">= 0.7.0" + hashes = [ + "h1:pQGSL9mdgw4qsLndFYsEF93mbsIxyxNoAyIbBqhS3Xo=", + "zh:19a393db736ec4fd024d098d55aefaef07056c37a448ece3b55b3f5f4c2c7e4a", + "zh:227fa1e221de2907f37be78d40c06ca6a6f7b243a1ec33ade014dfaf6d92cd9c", + "zh:29970fecbf4a3ca23bacbb05d6b90cdd33dd379f90059fe39e08289951502d9f", + "zh:65024596f22f10e7dcb5e0e4a75277f275b529daa0bc0daf34ca7901c678ab88", + "zh:694d080cb5e3bf5ef08c7409208d061c135a4f5f4cdc93ea8607860995264b2e", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:b29d15d13e1b3412e6a4e1627d378dbd102659132f7488f64017dd6b6d5216d3", + "zh:bb79f4cae9f8c17c73998edc54aa16c2130a03227f7f4e71fc6ac87e230575ec", + "zh:ceccf80e95929d97f62dcf1bb3c7c7553d5757b2d9e7d222518722fc934f7ad5", + "zh:f40e638336527490e294d9c938ae55919069e6987e85a80506784ba90348792a", + "zh:f99ef33b1629a3b2278201142a3011a8489e66d92da832a5b99e442204de18fb", + "zh:fded14754ea46fdecc62a52cd970126420d4cd190e598cb61190b4724a727edb", + ] +} diff --git a/iac/certificate.tf b/iac/certificate.tf index 8a28f8695..c22c10f70 100644 --- a/iac/certificate.tf +++ b/iac/certificate.tf @@ -1,4 +1,17 @@ data "aws_acm_certificate" "certificate" { - domain = "*.worldcubeassociation.org" + domain = "*.${var.domain_name}" statuses = ["ISSUED"] } + +provider "aws" { + region = "us-east-1" + alias = "us_east_1" +} + +data "aws_acm_certificate" "certificate_us_east_1" { + domain = "*.${var.domain_name}" + statuses = ["ISSUED"] + + provider = aws.us_east_1 +} + diff --git a/iac/frontend.tf b/iac/frontend.tf new file mode 100644 index 000000000..313585cad --- /dev/null +++ b/iac/frontend.tf @@ -0,0 +1,10 @@ +module "tnoodle_frontend" { + source = "./modules/frontend" + + aws_region = var.aws_region + project_name = var.tnoodle_name + zone_id = data.aws_ssm_parameter.wca_zone_id.value + domain_name = var.domain_name + org_name = var.org_name + certificate_arn = data.aws_acm_certificate.certificate_us_east_1.arn +} diff --git a/iac/modules/frontend/README.md b/iac/modules/frontend/README.md new file mode 100644 index 000000000..d555d7ef9 --- /dev/null +++ b/iac/modules/frontend/README.md @@ -0,0 +1,3 @@ +# Frontend Module + +This holds the infra to deploy TNoodle's frontend. diff --git a/iac/modules/frontend/cloudfront.tf b/iac/modules/frontend/cloudfront.tf new file mode 100644 index 000000000..ae70b30dd --- /dev/null +++ b/iac/modules/frontend/cloudfront.tf @@ -0,0 +1,37 @@ +module "cdn" { + source = "cloudposse/cloudfront-s3-cdn/aws" + + # Cloud Posse recommends pinning every module to a specific version + version = "0.92.0" + + origin_bucket = aws_s3_bucket.fontend_bucket.id + s3_access_logging_enabled = false + logging_enabled = false + cached_methods = ["HEAD", "GET", "OPTIONS"] + default_ttl = "86400" + name = "cdn" + stage = terraform.workspace + namespace = var.domain_name + error_document = "index.html" + aliases = ["${var.project_name}.${var.domain_name}"] + dns_alias_enabled = false + acm_certificate_arn = var.certificate_arn + minimum_protocol_version = "TLSv1.2_2021" + + custom_error_response = [ + { + error_caching_min_ttl = 10, + error_code = 403 + response_code = 403 + response_page_path = "/index.html" + }, + { + error_caching_min_ttl = 10, + error_code = 404 + response_code = 404 + response_page_path = "/index.html" + } + ] + + depends_on = [aws_s3_bucket.fontend_bucket] +} diff --git a/iac/modules/frontend/main.tf b/iac/modules/frontend/main.tf new file mode 100644 index 000000000..e69de29bb diff --git a/iac/modules/frontend/outputs.tf b/iac/modules/frontend/outputs.tf new file mode 100644 index 000000000..73b8b0b25 --- /dev/null +++ b/iac/modules/frontend/outputs.tf @@ -0,0 +1,12 @@ +output "deployment_bucket" { + value = aws_s3_bucket.fontend_bucket.bucket +} + +output "cf_distribution_id" { + value = module.cdn.cf_id +} + +output "cf_domain_name" { + value = module.cdn.cf_domain_name +} + diff --git a/iac/modules/frontend/route53.tf b/iac/modules/frontend/route53.tf new file mode 100644 index 000000000..7bbf1f892 --- /dev/null +++ b/iac/modules/frontend/route53.tf @@ -0,0 +1,11 @@ +resource "aws_route53_record" "project_record" { + zone_id = var.zone_id + name = var.project_name + type = "A" + + alias { + name = module.cdn.cf_domain_name + evaluate_target_health = true + zone_id = module.cdn.cf_hosted_zone_id + } +} diff --git a/iac/modules/frontend/s3.tf b/iac/modules/frontend/s3.tf new file mode 100644 index 000000000..125a24a53 --- /dev/null +++ b/iac/modules/frontend/s3.tf @@ -0,0 +1,3 @@ +resource "aws_s3_bucket" "fontend_bucket" { + bucket = "${var.org_name}-${var.project_name}-frontend" +} diff --git a/iac/modules/frontend/variables.tf b/iac/modules/frontend/variables.tf new file mode 100644 index 000000000..efccc2e8b --- /dev/null +++ b/iac/modules/frontend/variables.tf @@ -0,0 +1,23 @@ +variable "aws_region" { + description = "AWS Region" +} + +variable "project_name" { + description = "The name of this project" +} + +variable "zone_id" { + description = "The Route53 zone ID" +} + +variable "domain_name" { + description = "The domain name, web URL" +} + +variable "org_name" { + description = "The name of the organization" +} + +variable "certificate_arn" { + description = "The ARN of the ACM certificate" +} diff --git a/iac/outputs.tf b/iac/outputs.tf new file mode 100644 index 000000000..e128e8435 --- /dev/null +++ b/iac/outputs.tf @@ -0,0 +1,3 @@ +output "tnoodle_distribution_id" { + value = module.tnoodle_frontend.cf_distribution_id +} diff --git a/iac/route53.tf b/iac/route53.tf index e6be60ea0..18d551343 100644 --- a/iac/route53.tf +++ b/iac/route53.tf @@ -1,7 +1,7 @@ -# tnoodle.worldcubeassociation.org +# tnoodle-api.worldcubeassociation.org resource "aws_route53_record" "project_record" { zone_id = data.aws_ssm_parameter.wca_zone_id.value - name = var.tnoodle_name + name = "${var.tnoodle_name}-api" type = "A" alias { @@ -11,10 +11,10 @@ resource "aws_route53_record" "project_record" { } } -# scramble.worldcubeassociation.org -resource "aws_route53_record" "project_record" { +# scramble-api.worldcubeassociation.org +resource "aws_route53_record" "alternative_record" { zone_id = data.aws_ssm_parameter.wca_zone_id.value - name = "scramble" + name = "scramble-api" type = "A" alias { diff --git a/iac/variable.tf b/iac/variable.tf index 4640f7a1d..45e71d3b8 100644 --- a/iac/variable.tf +++ b/iac/variable.tf @@ -53,3 +53,12 @@ variable "http_port" { variable "https_port" { default = "443" } + +variable "domain_name" { + default = "worldcubeassociation.org" +} + +variable "org_name" { + description = "Organization's identifier" + default = "wca" +} From 72bb9a9152f04acef110c67e06778271058d6274 Mon Sep 17 00:00:00 2001 From: Alexandre Henrique Afonso Campos Date: Mon, 6 May 2024 09:40:12 -0300 Subject: [PATCH 13/13] Add a little more outputs --- iac/modules/frontend/outputs.tf | 3 --- iac/outputs.tf | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/iac/modules/frontend/outputs.tf b/iac/modules/frontend/outputs.tf index 73b8b0b25..c9b773951 100644 --- a/iac/modules/frontend/outputs.tf +++ b/iac/modules/frontend/outputs.tf @@ -6,7 +6,4 @@ output "cf_distribution_id" { value = module.cdn.cf_id } -output "cf_domain_name" { - value = module.cdn.cf_domain_name -} diff --git a/iac/outputs.tf b/iac/outputs.tf index e128e8435..26f104136 100644 --- a/iac/outputs.tf +++ b/iac/outputs.tf @@ -1,3 +1,7 @@ +output "tnoodle_deployment_bucket" { + value = module.tnoodle_frontend.deployment_bucket +} + output "tnoodle_distribution_id" { value = module.tnoodle_frontend.cf_distribution_id }