From 80f916feeefbda51ba395ae0d7eefe8dcebf9ee7 Mon Sep 17 00:00:00 2001 From: Siddharth Singh Date: Fri, 6 Dec 2024 23:08:00 +0530 Subject: [PATCH] working modules --- .../.terraform.lock.hcl | 0 .../container_definition.json.tftpl | 4 +- example/complete/main.tf | 55 +-- example/ecs-cluster/main.tf | 20 +- example/ecs-cluster/variables.tf | 68 --- example/ecs-service/.terraform.lock.hcl | 25 ++ .../main.tf | 9 +- iam.tf | 29 -- locals.tf | 74 ---- main.tf | 296 +++----------- modules/alb/main.tf | 7 - modules/alb/outputs.tf | 4 + modules/alb/variables.tf | 4 +- modules/ecs-cluster/main.tf | 14 +- modules/ecs-cluster/variables.tf | 8 +- .../{health-check => ecs-service}/README.md | 0 modules/ecs-service/cloudwatch.tf | 4 + modules/{health-check => ecs-service}/data.tf | 20 +- modules/{health-check => ecs-service}/iam.tf | 0 .../json/container_definition.json.tftpl | 26 ++ .../json/execution_role.json | 0 .../{health-check => ecs-service}/locals.tf | 6 + modules/{health-check => ecs-service}/main.tf | 36 +- .../{health-check => ecs-service}/outputs.tf | 11 +- modules/ecs-service/variables.tf | 65 +++ modules/health-check/variables.tf | 65 --- outputs.tf | 63 --- variables.tf | 387 +++++++++--------- version.tf | 10 + 29 files changed, 464 insertions(+), 846 deletions(-) rename example/{health-check-service => complete}/.terraform.lock.hcl (100%) rename {modules/health-check/json => example/complete/container}/container_definition.json.tftpl (80%) delete mode 100644 example/ecs-cluster/variables.tf create mode 100644 example/ecs-service/.terraform.lock.hcl rename example/{health-check-service => ecs-service}/main.tf (74%) delete mode 100644 iam.tf delete mode 100644 locals.tf rename modules/{health-check => ecs-service}/README.md (100%) create mode 100644 modules/ecs-service/cloudwatch.tf rename modules/{health-check => ecs-service}/data.tf (64%) rename modules/{health-check => ecs-service}/iam.tf (100%) create mode 100644 modules/ecs-service/json/container_definition.json.tftpl rename modules/{health-check => ecs-service}/json/execution_role.json (100%) rename modules/{health-check => ecs-service}/locals.tf (85%) rename modules/{health-check => ecs-service}/main.tf (76%) rename modules/{health-check => ecs-service}/outputs.tf (81%) create mode 100644 modules/ecs-service/variables.tf delete mode 100644 modules/health-check/variables.tf delete mode 100644 outputs.tf create mode 100644 version.tf diff --git a/example/health-check-service/.terraform.lock.hcl b/example/complete/.terraform.lock.hcl similarity index 100% rename from example/health-check-service/.terraform.lock.hcl rename to example/complete/.terraform.lock.hcl diff --git a/modules/health-check/json/container_definition.json.tftpl b/example/complete/container/container_definition.json.tftpl similarity index 80% rename from modules/health-check/json/container_definition.json.tftpl rename to example/complete/container/container_definition.json.tftpl index be7be08..e7f5685 100644 --- a/modules/health-check/json/container_definition.json.tftpl +++ b/example/complete/container/container_definition.json.tftpl @@ -17,9 +17,9 @@ "logConfiguration": { "logDriver": "awslogs", "options": { - "awslogs-group": "/aws/ecs/${cluster_name_full}/${service_name_full}", + "awslogs-group": "${log_group_name}", "awslogs-region": "${aws_region}", - "awslogs-stream-prefix": "proxy" + "awslogs-stream-prefix" : "ecs" } } } diff --git a/example/complete/main.tf b/example/complete/main.tf index 64c525f..2ce34ae 100644 --- a/example/complete/main.tf +++ b/example/complete/main.tf @@ -12,14 +12,16 @@ terraform { } } +provider "aws" { + region = "us-east-1" +} + ################################################################################ ## ecs cluster ################################################################################ -module "ecs" { - source = "../modules/ecs" - - create = true +module "ecs-cluster" { + source = "../../modules/ecs-cluster" ecs_cluster = { name = "arc-ecs-module-poc" @@ -37,14 +39,11 @@ module "ecs" { } capacity_provider = { - autoscaling_capacity_providers = {} + autoscaling_capacity_providers = {} default_capacity_provider_use_fargate = true fargate_capacity_providers = { fargate_cp = { name = "FARGATE" - tags = { - Environment = "develop" - } } } } @@ -62,7 +61,7 @@ module "ecs" { module "alb" { source = "../../modules/alb" - vpc_id = "vpc-12345" + vpc_id = "vpc-123445" alb = { name = "arc-poc-alb" @@ -71,10 +70,11 @@ module "alb" { } alb_target_group = [{ - name = "arc-poc-alb-tg" - port = 80 - protocol = "HTTP" - vpc_id = "vpc-12345" + name = "arc-poc-alb-tg" + port = 80 + protocol = "HTTP" + vpc_id = "vpc-123445" + target_type = "ip" health_check = { enabled = true path = "/" @@ -86,30 +86,35 @@ module "alb" { ################################################################################ -## health check service +## ecs service ################################################################################ -module "health-check" { - source = "../../modules/health-check" +module "ecs-service" { + source = "../../modules/ecs-service" - vpc_id = "vpc-12345" + vpc_id = "vpc-123445" environment = "develop" ecs = { - cluster_name = module.ecs.ecs_cluster.name - service_name = "arc-ecs-module-service-poc" - repository_name = "12345.dkr.ecr.us-east-1.amazonaws.com/arc/arc-poc-ecs" - enable_load_balancer = false + cluster_name = module.ecs-cluster.ecs_cluster.name + service_name = "arc-ecs-module-service-poc" + repository_name = "23112.dkr.ecr.us-east-1.amazonaws.com/arc/arc-poc-ecs" + enable_load_balancer = false + aws_lb_target_group_name = "arc-poc-alb-tg" } task = { - container_port = 8100 + tasks_desired = 1 + container_port = 8100 + container_memory = 1024 + container_vcpu = 256 + container_definition = "container/container_definition.json.tftpl" } alb = { - name = module.alb.name + name = module.alb.alb.name listener_port = 8100 - security_group_id = "" + security_group_id = module.alb.alb_security_group_id } - depends_on = [ module.alb ] + depends_on = [module.alb] } diff --git a/example/ecs-cluster/main.tf b/example/ecs-cluster/main.tf index 2c36cd0..97be16a 100644 --- a/example/ecs-cluster/main.tf +++ b/example/ecs-cluster/main.tf @@ -12,27 +12,11 @@ terraform { } } -module "tags" { - source = "sourcefuse/arc-tags/aws" - version = "1.2.3" - environment = var.environment - project = "Example" - - extra_tags = { - RepoName = "terraform-aws-refarch-ecs" - Example = "true" - } -} - -provider "aws" { - region = var.region -} - ################################################################################ ## ecs ################################################################################ -module "ecs" { - source = "../modules/ecs" +module "ecs-cluster" { + source = "../modules/ecs-cluster" create = true diff --git a/example/ecs-cluster/variables.tf b/example/ecs-cluster/variables.tf deleted file mode 100644 index 2ae840b..0000000 --- a/example/ecs-cluster/variables.tf +++ /dev/null @@ -1,68 +0,0 @@ -################################################################################ -## shared -################################################################################ -variable "region" { - type = string - default = "us-east-1" - description = "AWS region" -} - -variable "environment" { - description = "ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT'" - type = string - default = "poc" -} - -variable "namespace" { - type = string - description = "Namespace for the resources." - default = "arc" -} - -################################################################################ -## network / security -################################################################################ -variable "private_subnet_names" { - description = <<-EOF - List of Private Subnet names in the VPC where the network resources currently exist. - If not defined, the default value from `terraform-aws-ref-arch-network` will be used. - From that module's example, the value is: [`example-dev-private-us-east-1a`, `example-dev-private-us-east-1b`] - EOF - type = list(string) - default = [] -} - -variable "public_subnet_names" { - description = <<-EOF - List of Public Subnet names in the VPC where the network resources currently exist. - If not defined, the default value from `terraform-aws-ref-arch-network` will be used. - From that module's example, the value is: [`example-dev-public-us-east-1a`, `example-dev-public-us-east-1b`] - EOF - type = list(string) - default = [] -} - -variable "vpc_name" { - description = <<-EOF - Name of the VPC where the network resources currently exist. - If not defined, the default value from `terraform-aws-ref-arch-network` will be used. - From that module's example, the name `example-dev-vpc` is used. - EOF - type = string - default = null -} - -################################################################################ -## acm -################################################################################ -variable "acm_domain_name" { - description = "Domain name the ACM Certificate belongs to" - type = string - default = "sourcefuse.arc-poc.link" ///specify an acm domain name it will create for you -} - -variable "route_53_zone" { - type = string - description = "route53 zone name required to fetch the hosted zoneid" - default = "arc-poc.link" // change the route53 zone name -} diff --git a/example/ecs-service/.terraform.lock.hcl b/example/ecs-service/.terraform.lock.hcl new file mode 100644 index 0000000..dac6f65 --- /dev/null +++ b/example/ecs-service/.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.80.0" + constraints = "~> 5.0" + hashes = [ + "h1:q2pqSs7uPWvxunrBYjyirXARlxFIoxn2Lju42uJbxk4=", + "zh:0b1655e39639d60f2de2860a5df8642f9556ba0ca04529c1b861fde4935cb0df", + "zh:13dc0155e0a11edceee29ce687fc04c5a5a85f3324c67556472713cfd52e5807", + "zh:180f6cb2be44be14cfe329e0649121b774319f083b6e4e8fb749f85090d73121", + "zh:3158d44b74c67465f7f19f22c42b643840c8d18ce833e2ec86e8d93085b06926", + "zh:6351b5bf7cde5dc83e926944891570636069e05ca43341f4d1feda67773469bf", + "zh:6fa9db1532096ba50e842d369b6688979306d2295c7ead49b8a266b0d60962cc", + "zh:85d2fe75def7619ff2cc29102048875039cad088fafb62ecc14c3763e7b1e9d9", + "zh:9028d653f1d7341c6dfe2afe961b6541581e9043a474eac2faf90e6426a24f6d", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:9c4e248c442bc60f07f9f089e5361f19936833370dc3c04b27916672b765f0e1", + "zh:a710a3979596e3f3938c3ec6bb748e604724d3a4afa96ed2c14f0a245cc41a11", + "zh:c27936bdf447779d0c0833bf52a9ef618985f5ea8e3e243d6266513520ca31c4", + "zh:c7681134a123486e72eaedc3f8d2d75e267dbbfd45fa7de5aea8f757af57f89b", + "zh:ea717ebad3561fd02591f9eecf30f3df5635405556fba2bdbf29fd42691bebac", + "zh:f4e1e8f23c58c3e8f4371f9c3379a723ab4155246e6b6daad8eb99e16666b2cb", + ] +} diff --git a/example/health-check-service/main.tf b/example/ecs-service/main.tf similarity index 74% rename from example/health-check-service/main.tf rename to example/ecs-service/main.tf index e4ff824..b62a318 100644 --- a/example/health-check-service/main.tf +++ b/example/ecs-service/main.tf @@ -12,17 +12,16 @@ terraform { } } -module "health-check" { - source = "../../modules/health-check" +module "ecs-service" { + source = "../../modules/ecs-service" - vpc_id = "vpc-0e6c09980580ecbf6" + vpc_id = "vpc-12345" environment = "develop" - aws_region = "us-east-1" ecs = { cluster_name = "arc-ecs-module-poc" service_name = "arc-ecs-module-service-poc" - repository_name = "884360309640.dkr.ecr.us-east-1.amazonaws.com/arc/arc-poc-ecs" + repository_name = "12345.dkr.ecr.us-east-1.amazonaws.com/arc/arc-poc-ecs" enable_load_balancer = false } diff --git a/iam.tf b/iam.tf deleted file mode 100644 index 9396ee5..0000000 --- a/iam.tf +++ /dev/null @@ -1,29 +0,0 @@ -################################################################################ -## task execution role -################################################################################ -data "aws_iam_policy_document" "assume" { - statement { - actions = ["sts:AssumeRole"] - - principals { - type = "Service" - identifiers = ["ecs-tasks.amazonaws.com"] - } - } -} - -resource "aws_iam_role" "execution" { - name = "${local.cluster_name}-execution" - assume_role_policy = data.aws_iam_policy_document.assume.json - - tags = merge(var.tags, tomap({ - Name = "${local.cluster_name}-execution" - })) -} - -resource "aws_iam_role_policy_attachment" "execution" { - for_each = toset(var.execution_policy_attachment_arns) - - policy_arn = each.value - role = aws_iam_role.execution.name -} diff --git a/locals.tf b/locals.tf deleted file mode 100644 index 58e2103..0000000 --- a/locals.tf +++ /dev/null @@ -1,74 +0,0 @@ -locals { - ## cluster - cluster_name = var.cluster_name_override != null ? var.cluster_name_override : "${var.namespace}-${var.environment}-cluster" - - ## ssm - ssm_params = concat(var.additional_ssm_params, [ - # alb - { - name = "/${var.namespace}/${var.environment}/alb/${module.alb.alb_name}/endpoint" - value = module.alb.alb_dns_name - description = "ALB DNS Endpoint" - type = "String" - }, - { - name = "/${var.namespace}/${var.environment}/alb/${module.alb.alb_name}/arn" - value = module.alb.alb_arn - description = "ALB ARN" - type = "String" - }, - { - name = "/${var.namespace}/${var.environment}/alb/${module.alb.alb_name}/dns_zone_id" - value = module.alb.alb_zone_id - description = "ALB Zone ID" - type = "String" - }, - { - name = "/${var.namespace}/${var.environment}/alb/${module.alb.alb_name}/health_check_fqdn" - value = length(module.health_check.route_53_fqdn) > 0 ? join(", ", module.health_check.route_53_fqdn) : "No health check FQDN" - description = "ALB Health Check FQDN." - type = "String" - }, - ## listeners - { - name = "/${var.namespace}/${var.environment}/alb/${module.alb.alb_name}/http-listener/arn" - value = aws_lb_listener.http.arn - description = "ARN of the HTTP listener" - type = "String" - }, - { - name = "/${var.namespace}/${var.environment}/alb/${module.alb.alb_name}/https-listener/arn" - value = aws_lb_listener.https.arn - description = "ARN of the HTTPS listener" - type = "String" - }, - - ## acm - { - name = "/${var.namespace}/${var.environment}/alb/${module.alb.alb_name}/certificate_arn" - value = try(module.acm.arn, "Not Assigned") - description = "ACM Certificate ARN." - type = "String" - }, - - ## ecs - { - name = "/${var.namespace}/${var.environment}/ecs/${module.ecs.cluster_name}/cluster_name" - value = module.ecs.cluster_name - description = "ECS Cluster Name" - type = "String" - }, - { - name = "/${var.namespace}/${var.environment}/ecs/${module.ecs.cluster_name}/id" - value = module.ecs.cluster_id - description = "ECS Cluster ID" - type = "String" - }, - { - name = "/${var.namespace}/${var.environment}/ecs/${module.ecs.cluster_name}/arn" - value = module.ecs.cluster_arn - description = "ECS Cluster ARN" - type = "String" - } - ]) -} diff --git a/main.tf b/main.tf index b5b246d..c4db1d2 100644 --- a/main.tf +++ b/main.tf @@ -1,274 +1,88 @@ ################################################################################ -## defaults +## ecs cluster ################################################################################ -terraform { - required_version = ">= 1.4, < 2.0.0" - required_providers { - aws = { - source = "hashicorp/aws" - version = ">= 4.0, < 6.0" - } - } -} - -################################################################################ -## cluster -################################################################################ -module "ecs" { - source = "./modules/ecs" - - create = true +module "ecs-cluster" { + source = "../../modules/ecs-cluster" ecs_cluster = { - cluster_name = "my-ecs-cluster" - cluster_service_connect_defaults = [] - create_cloudwatch_log_group = false - - } - - cloudwatch = { - log_group_name = "my-cloudwatch-log-group" - log_group_retention_in_days = 7 - log_group_kms_key_id = null - log_group_tags = { Environment = "production" } + name = var.ecs_cluster.name + create_cloudwatch_log_group = var.ecs_cluster.create_cloudwatch_log_group + service_connect_defaults = var.ecs_cluster.service_connect_defaults + settings = var.ecs_cluster.settings } capacity_provider = { - autoscaling_capacity_providers = { - my-provider = { - name = "my-autoscaling-provider" - auto_scaling_group_arn = "arn:aws:autoscaling:region:account-id:autoScalingGroup:autoScalingGroupName/my-asg" - managed_scaling = { instance_warmup_period = 300, maximum_scaling_step_size = 10, minimum_scaling_step_size = 1, status = "ENABLED", target_capacity = 100 } - managed_termination_protection = "ENABLED" - managed_draining = "ENABLED" - tags = { Environment = "production" } - } - } - fargate_capacity_providers = {} - default_capacity_provider_use_fargate = false - } - - tags = { - Project = "MyProject" - Environment = "production" + autoscaling_capacity_providers = var.capacity_provider.autoscaling_capacity_providers + default_capacity_provider_use_fargate = var.capacity_provider.default_capacity_provider_use_fargate } } -## logging -resource "aws_cloudwatch_log_group" "this" { - name = "/${var.namespace}/${var.environment}/ecs/${local.cluster_name}" - - retention_in_days = var.log_group_retention_days - skip_destroy = var.log_group_skip_destroy - - tags = merge(var.tags, tomap({ - Name = "/${var.namespace}/${var.environment}/ecs/${local.cluster_name}" - })) -} - ################################################################################ -## load balancer +## ALB ################################################################################ -## certificate -module "acm" { - source = "git::https://github.com/cloudposse/terraform-aws-acm-request-certificate?ref=0.17.0" - count = var.create_acm_certificate == true ? 1 : 0 - - name = "${var.environment}-${var.namespace}-acm-certificate" - namespace = var.namespace - environment = var.environment - zone_name = var.route_53_zone_name - domain_name = var.acm_domain_name - subject_alternative_names = var.acm_subject_alternative_names - process_domain_validation_options = var.acm_process_domain_validation_options - ttl = var.acm_process_domain_validation_record_ttl - - tags = var.tags -} -module "alb_sg" { - source = "git::https://github.com/cloudposse/terraform-aws-security-group?ref=2.0.0" - - # Security Group names must be unique within a VPC. - # This module follows Cloud Posse naming conventions and generates the name - # based on the inputs to the null-label module, which means you cannot - # reuse the label as-is for more than one security group in the VPC. - # - # Here we add an attribute to give the security group a unique name. - attributes = ["${local.cluster_name}-alb"] - - # Allow unlimited egress - allow_all_egress = true - - rules = [ - { - key = "alb-ingress-80" - type = "ingress" - from_port = 80 - protocol = "tcp" - to_port = 80 - cidr_blocks = ["0.0.0.0/0"] - ipv6_cidr_blocks = ["::/0"] - self = null # preferable to self = false - description = "Allow port 80 from anywhere" - }, - { - key = "alb-ingress-443" - type = "ingress" - from_port = 443 - protocol = "tcp" - to_port = 443 - cidr_blocks = ["0.0.0.0/0"] - ipv6_cidr_blocks = ["::/0"] - self = null # preferable to self = false - description = "Allow port 443 from anywhere" - } - ] - - vpc_id = var.vpc_id - - tags = merge(var.tags, tomap({ - Name = "${local.cluster_name}-alb" - })) -} - -## alb module "alb" { - source = "./modules/alb" - - name = local.cluster_name - vpc_id = var.vpc_id - subnet_ids = var.alb_subnet_ids - security_group_ids = [module.alb_sg.id] + source = "../../modules/alb" - access_logs_enabled = var.access_logs_enabled - alb_access_logs_s3_bucket_force_destroy = var.alb_access_logs_s3_bucket_force_destroy - alb_access_logs_s3_bucket_force_destroy_enabled = var.alb_access_logs_s3_bucket_force_destroy_enabled - internal = var.alb_internal - idle_timeout = var.alb_idle_timeout + vpc_id = var.vpc_id - // TODO - change to variable - http_ingress_cidr_blocks = [ - "0.0.0.0/0" - ] + alb = { + name = var.alb.name + internal = var.alb.internal + port = var.alb.port + } - // TODO - change to variable - https_ingress_cidr_blocks = [ - "0.0.0.0/0" - ] + alb_target_group = [{ + name = var.alb_target_group.name + port = var.alb_target_group.port + protocol = var.alb_target_group.protocol + vpc_id = var.vpc_id + target_type = var.alb_target_group.target_type + health_check = { + enabled = var.alb_target_group.health_check.enabled + path = var.alb_target_group.health_check.path + } + }] - tags = var.tags + listener_rules = [{ + priority = var.listener_rules.priority + }] } -module "health_check" { - source = "./modules/health-check" - - vpc_id = var.vpc_id - subnet_ids = length(var.health_check_subnet_ids) > 0 ? var.health_check_subnet_ids : var.alb_subnet_ids - - cluster_id = module.ecs.cluster_id - cluster_name = module.ecs.cluster_name - - lb_listener_arn = aws_lb_listener.https.arn - lb_security_group_ids = [module.alb_sg.id] - - ## for alb alias records - alb_dns_name = module.alb.alb_dns_name - alb_zone_id = module.alb.alb_zone_id - - externally_managed_route_53_record = var.externally_managed_route_53_record - - ## health check - route_53_zone_id = var.route_53_zone_id - health_check_route_53_records = var.health_check_route_53_records - - task_execution_role_arn = aws_iam_role.execution.arn - - tags = var.tags - - depends_on = [ - module.ecs, - module.alb - ] -} ################################################################################ -## listeners +## ecs service ################################################################################ -## http -resource "aws_lb_listener" "http" { - load_balancer_arn = module.alb.alb_arn - port = "80" - protocol = "HTTP" - default_action { - type = "redirect" +module "ecs-service" { + source = "../../modules/ecs-service" - redirect { - port = "443" - protocol = "HTTPS" - status_code = "HTTP_301" - } - } - - tags = merge(var.tags, tomap({ - Name = "${local.cluster_name}-http-redirect" - })) -} + vpc_id = var.vpc_id + environment = var.environment -## https -resource "aws_lb_listener" "https" { - load_balancer_arn = module.alb.alb_arn - port = "443" - protocol = "HTTPS" - ssl_policy = var.alb_ssl_policy - certificate_arn = try(module.acm[0].arn, var.alb_certificate_arn) - - default_action { - type = "fixed-response" - - fixed_response { - content_type = "text/html" - message_body = "Forbidden" - status_code = "403" - } + ecs = { + cluster_name = module.ecs-cluster.ecs_cluster.name + service_name = var.ecs.service_name + repository_name = var.ecs.repository_name + enable_load_balancer = var.ecs.enable_load_balancer + aws_lb_target_group_name = var.ecs.aws_lb_target_group_name } - tags = merge(var.tags, tomap({ - Name = "${local.cluster_name}-https-forward" - })) - - depends_on = [ - module.acm - ] -} - -################################################################################ -## service discovery namespaces -################################################################################ -resource "aws_service_discovery_private_dns_namespace" "this" { - for_each = toset(var.service_discovery_private_dns_namespace) + task = { + tasks_desired = var.task.tasks_desired + container_port = var.task.container_port + container_memory = var.task.container_memory + container_vcpu = var.task.container_vcpu + container_definition = var.task.container_definition + } - name = each.value - description = "Service discovery for ${each.value}" - vpc = var.vpc_id + alb = { + name = module.alb.alb.name + listener_port = var.alb.listener_port + security_group_id = module.alb.alb_security_group_id + } + depends_on = [module.alb] } -################################################################################ -## ssm parameters -################################################################################ -resource "aws_ssm_parameter" "this" { - for_each = { for x in local.ssm_params : x.name => x } - - name = each.value.name - value = each.value.value - description = try(each.value.description, "Managed by Terraform") - type = try(each.value.type, "SecureString") - overwrite = try(each.value.overwrite, true) - - tags = merge(var.tags, tomap({ - Name = each.value.name - })) -} diff --git a/modules/alb/main.tf b/modules/alb/main.tf index af2d32b..87c8529 100644 --- a/modules/alb/main.tf +++ b/modules/alb/main.tf @@ -11,9 +11,6 @@ terraform { } } } -provider "aws" { - region = data.aws_region.current -} ################################################################### ## Load balancer Security Group @@ -43,10 +40,6 @@ resource "aws_security_group" "lb_sg" { protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } - - tags = { - Name = "${var.alb.name}-sg" - } } ################################################################### diff --git a/modules/alb/outputs.tf b/modules/alb/outputs.tf index d8541c2..ab92b36 100644 --- a/modules/alb/outputs.tf +++ b/modules/alb/outputs.tf @@ -31,3 +31,7 @@ output "alb" { output "public_subnets" { value = local.public_subnets } + +output "alb_security_group_id" { + value = aws_security_group.lb_sg.id +} diff --git a/modules/alb/variables.tf b/modules/alb/variables.tf index 3e9ec87..55ccfcd 100644 --- a/modules/alb/variables.tf +++ b/modules/alb/variables.tf @@ -40,7 +40,7 @@ variable "alb_target_group" { protocol = optional(string, null) protocol_version = optional(string, "HTTP1") vpc_id = optional(string, "") - target_type = optional(string, "instance") + target_type = optional(string, "ip") ip_address_type = optional(string, "ipv4") load_balancing_algorithm_type = optional(string, "round_robin") load_balancing_cross_zone_enabled = optional(string, "use_load_balancer_configuration") @@ -98,8 +98,6 @@ variable "listener_rules" { message_body = optional(string) status_code = optional(string) }), null) - })) - })) } diff --git a/modules/ecs-cluster/main.tf b/modules/ecs-cluster/main.tf index 492aa5d..03ce4ab 100644 --- a/modules/ecs-cluster/main.tf +++ b/modules/ecs-cluster/main.tf @@ -18,12 +18,12 @@ terraform { resource "aws_cloudwatch_log_group" "this" { count = var.ecs_cluster.create_cloudwatch_log_group ? 1 : 0 - name = var.ecs_cluster.configuration.log_configuration.log_group_name != null ? var.ecs_cluster.configuration.log_configuration.log_group_name : "/aws/ecs/${var.ecs_cluster.name}" + name = var.ecs_cluster.configuration.execute_command_configuration.log_configuration.log_group_name != null ? var.ecs_cluster.configuration.execute_command_configuration.log_configuration.log_group_name : "/aws/ecs/${var.ecs_cluster.name}" - retention_in_days = var.ecs_cluster.configuration.log_configuration.log_group_retention_in_days - kms_key_id = var.ecs_cluster.configuration.log_configuration.log_group_kms_key_id + retention_in_days = var.ecs_cluster.configuration.execute_command_configuration.log_configuration.log_group_retention_in_days + kms_key_id = var.ecs_cluster.configuration.execute_command_configuration.log_configuration.log_group_kms_key_id - tags = merge(var.tags, var.ecs_cluster.configuration.log_configuration.log_group_tags) + tags = merge(var.tags, var.ecs_cluster.configuration.execute_command_configuration.log_configuration.log_group_tags) } @@ -49,8 +49,8 @@ resource "aws_ecs_cluster" "this" { for_each = var.ecs_cluster.create_cloudwatch_log_group && length(execute_command_configuration.value.log_configuration) > 0 ? [execute_command_configuration.value.log_configuration] : [] content { - cloud_watch_encryption_enabled = log_configuration.value.cloud_watch_encryption_enabled - cloud_watch_log_group_name = log_configuration.value.cloud_watch_log_group_name + cloud_watch_encryption_enabled = log_configuration.value.cloudwatch_encryption_enabled + cloud_watch_log_group_name = log_configuration.value.log_group_name s3_bucket_name = log_configuration.value.s3_bucket_name s3_bucket_encryption_enabled = log_configuration.value.s3_bucket_encryption_enabled s3_key_prefix = log_configuration.value.s3_key_prefix @@ -79,8 +79,6 @@ resource "aws_ecs_cluster" "this" { } tags = merge(var.tags, var.ecs_cluster.tags) - - depends_on = [ aws_cloudwatch_log_group.this ] } ################################################################################ diff --git a/modules/ecs-cluster/variables.tf b/modules/ecs-cluster/variables.tf index 9a8106d..8f9ee6d 100644 --- a/modules/ecs-cluster/variables.tf +++ b/modules/ecs-cluster/variables.tf @@ -43,15 +43,15 @@ Keys: EOT default = { - cluster_name = "" - cluster_configuration = {} - cluster_settings = [ + name = "" + configuration = {} + settings = [ { name = "containerInsights" value = "enabled" } ] - cluster_service_connect_defaults = {} + service_connect_defaults = {} create_cloudwatch_log_group = true } } diff --git a/modules/health-check/README.md b/modules/ecs-service/README.md similarity index 100% rename from modules/health-check/README.md rename to modules/ecs-service/README.md diff --git a/modules/ecs-service/cloudwatch.tf b/modules/ecs-service/cloudwatch.tf new file mode 100644 index 0000000..b42bb24 --- /dev/null +++ b/modules/ecs-service/cloudwatch.tf @@ -0,0 +1,4 @@ +resource "aws_cloudwatch_log_group" "this" { + name = "/ecs/${local.service_name_full}" + retention_in_days = 7 +} diff --git a/modules/health-check/data.tf b/modules/ecs-service/data.tf similarity index 64% rename from modules/health-check/data.tf rename to modules/ecs-service/data.tf index 2a38065..d3c1ce6 100644 --- a/modules/health-check/data.tf +++ b/modules/ecs-service/data.tf @@ -5,19 +5,19 @@ data "aws_vpc" "vpc" { data "aws_region" "current" {} data "aws_subnets" "private" { + filter { name = "vpc-id" - values = [data.aws_vpc.vpc.id] + values = [var.vpc_id] } - tags = { - Type = "private" - } -} + filter { + name = "tag:Name" -data "aws_subnet" "private" { - for_each = toset(data.aws_subnets.private.ids) - id = each.value + values = [ + "*private*", + ] + } } data "aws_lb" "service" { @@ -30,4 +30,8 @@ data "aws_security_group" "alb_sg" { data "aws_ecs_cluster" "cluster" { cluster_name = var.ecs.cluster_name +} + +data "aws_lb_target_group" "ecs_target_group" { + name = var.ecs.aws_lb_target_group_name } \ No newline at end of file diff --git a/modules/health-check/iam.tf b/modules/ecs-service/iam.tf similarity index 100% rename from modules/health-check/iam.tf rename to modules/ecs-service/iam.tf diff --git a/modules/ecs-service/json/container_definition.json.tftpl b/modules/ecs-service/json/container_definition.json.tftpl new file mode 100644 index 0000000..0b5fd18 --- /dev/null +++ b/modules/ecs-service/json/container_definition.json.tftpl @@ -0,0 +1,26 @@ +[ + { + "name": "${service_name_full}", + "image": "${repository_name}:${environment}", + "essential": true, + "portMappings": [ + { + "hostPort": ${alb_port}, + "protocol": "tcp", + "containerPort": ${container_port} + } + ], + "environment": ${environment_vars}, + "compatibilities": [ + "FARGATE" + ], + "logConfiguration": { + "logDriver": "awslogs", + "options": { + "awslogs-group": "${log_group_name}", + "awslogs-region": "${aws_region}", + "awslogs-stream-prefix": "ecs" + } + } + } +] \ No newline at end of file diff --git a/modules/health-check/json/execution_role.json b/modules/ecs-service/json/execution_role.json similarity index 100% rename from modules/health-check/json/execution_role.json rename to modules/ecs-service/json/execution_role.json diff --git a/modules/health-check/locals.tf b/modules/ecs-service/locals.tf similarity index 85% rename from modules/health-check/locals.tf rename to modules/ecs-service/locals.tf index e85a2f8..6da4bf3 100644 --- a/modules/health-check/locals.tf +++ b/modules/ecs-service/locals.tf @@ -18,4 +18,10 @@ locals { Name = name Value = value }] + + /* private_subnets = [ + for s in data.aws_subnet.private : + s.id if lookup(s.tags, "Type", "") == "private" + ] */ + } diff --git a/modules/health-check/main.tf b/modules/ecs-service/main.tf similarity index 76% rename from modules/health-check/main.tf rename to modules/ecs-service/main.tf index 091eedb..9235ac1 100644 --- a/modules/health-check/main.tf +++ b/modules/ecs-service/main.tf @@ -12,27 +12,9 @@ terraform { } } -provider "aws" { - region = data.aws_region.current -} - -/* module "ecs_cluster" { - source = "../ecs" - - ecs_cluster = { - cluster_name = "healthcheck-poc-cluster" - } - - capacity_provider = { - default_capacity_provider_use_fargate = true - } - cloudwatch = {} - -} */ - resource "aws_ecs_service" "this" { name = local.service_name_full - cluster = data.aws_ecs_cluster.cluster + cluster = data.aws_ecs_cluster.cluster.cluster_name task_definition = aws_ecs_task_definition.this.arn desired_count = var.task.tasks_desired launch_type = "FARGATE" @@ -45,18 +27,19 @@ resource "aws_ecs_service" "this" { content { container_name = var.ecs.cluster_name container_port = var.task.container_port - target_group_arn = var.ecs.aws_lb_target_group_arn + target_group_arn = data.aws_lb_target_group.ecs_target_group.arn } } network_configuration { - subnets = [for s in data.aws_subnet.private : s.id] + subnets = data.aws_subnets.private.ids security_groups = [aws_security_group.ecs.id] } propagate_tags = "TASK_DEFINITION" depends_on = [ - aws_security_group.ecs + aws_security_group.ecs, + aws_ecs_task_definition.this ] } @@ -71,7 +54,7 @@ resource "aws_ecs_task_definition" "this" { container_definitions = templatefile(var.task.container_definition, { alb_port = var.alb.listener_port, - aws_region = data.aws_region.current, + aws_region = data.aws_region.current.name, cluster_name_full = local.cluster_name_full, container_port = var.task.container_port, environment = var.environment, @@ -79,7 +62,8 @@ resource "aws_ecs_task_definition" "this" { repository_name = var.ecs.repository_name, service_name_full = local.service_name_full, cluster_name = var.ecs.cluster_name, - service_name = var.ecs.service_name + service_name = var.ecs.service_name, + log_group_name = aws_cloudwatch_log_group.this.name }) } @@ -94,8 +78,8 @@ resource "aws_security_group" "ecs" { from_port = var.task.container_port to_port = var.task.container_port protocol = "tcp" - cidr_blocks = [for s in data.aws_subnet.private : s.cidr_block] - #security_groups = [data.aws_security_group.alb_sg] + #cidr_blocks = [for subnet in data.aws_subnet.private : subnet.cidr_block] + security_groups = [var.alb.security_group_id] } egress { diff --git a/modules/health-check/outputs.tf b/modules/ecs-service/outputs.tf similarity index 81% rename from modules/health-check/outputs.tf rename to modules/ecs-service/outputs.tf index 090dc47..1546f9b 100644 --- a/modules/health-check/outputs.tf +++ b/modules/ecs-service/outputs.tf @@ -28,4 +28,13 @@ output "route_53_fqdn" { description = "Health check FQDN record created in Route 53." value = try([for x in aws_route53_record.this : x.fqdn], []) } - */ \ No newline at end of file + */ + + output "private_subnets" { + value = data.aws_subnets.private +} + +output "private_subnet_ids" { + value = data.aws_subnets.private.ids +} + diff --git a/modules/ecs-service/variables.tf b/modules/ecs-service/variables.tf new file mode 100644 index 0000000..4250a7f --- /dev/null +++ b/modules/ecs-service/variables.tf @@ -0,0 +1,65 @@ +# General variables +variable "vpc_id" { + type = string + description = "The VPC the service will be deployed in" +} + +variable "environment" { + type = string + description = "The environment associated with the service" +} + +# ECS-specific variables +variable "ecs" { + type = object({ + cluster_name = string + service_name = string + repository_name = string + enable_load_balancer = bool + aws_lb_target_group_name = optional(string) + }) + description = "The ECS-specific values to use such as cluster, service, and repository names." +} + +# Task-specific variables +variable "task" { + type = object({ + tasks_desired = optional(number) + container_vcpu = optional(number) + container_memory = optional(number) + container_port = number + container_health_check_path = optional(string) + container_definition = optional(string) + environment_variables = optional(map(string)) + task_execution_role = optional(string) + }) + + description = "Task-related information (vCPU, memory, # of tasks, port, and health check info.)" + + default = { + tasks_desired = 1 // Default number of tasks + container_vcpu = 512 // Default vCPU allocation + container_memory = 1024 // Default memory allocation + container_port = 80 // Example default port (you can change this) + container_health_check_path = "/health" // Example health check path (you can change this) + environment_variables = {} // Default to an empty map + } +} + +# Load balancer +variable "alb" { + type = object({ + name = string + listener_port = number + deregistration_delay = optional(number) + security_group_id = string + }) + description = "ALB-related information (listening port, deletion protection, security group)" + default = { + name = "" // Default ALB name + listener_port = 80 // Default listener port + deregistration_delay = 300 // Default deregistration delay + security_group_id = "" // Example default security group ID + } +} + diff --git a/modules/health-check/variables.tf b/modules/health-check/variables.tf deleted file mode 100644 index 1f98480..0000000 --- a/modules/health-check/variables.tf +++ /dev/null @@ -1,65 +0,0 @@ -# General variables -variable "vpc_id" { - type = string - description = "The VPC the service will be deployed in" -} - -variable "environment" { - type = string - description = "The environment associated with the service" -} - -# ECS-specific variables -variable "ecs" { - type = object({ - cluster_name = string - service_name = string - repository_name = string - enable_load_balancer = bool - aws_lb_target_group_arn = optional(string) - }) - description = "The ECS-specific values to use such as cluster, service, and repository names." -} - -# Task-specific variables -variable "task" { - type = object({ - tasks_desired = optional(number) // Default will be set below in locals - container_vcpu = optional(number) // Default will be set below in locals - container_memory = optional(number) // Default will be set below in locals - container_port = number // Required, no default needed - container_health_check_path = optional(string) // Default will be set below in locals - container_definition = optional(string) // Default will be set below in locals - environment_variables = optional(map(string)) // Default will be set below in locals - task_execution_role = optional(string) // Default will be set below in locals - }) - - description = "Task-related information (vCPU, memory, # of tasks, port, and health check info.)" - - default = { - tasks_desired = 1 // Default number of tasks - container_vcpu = 512 // Default vCPU allocation - container_memory = 1024 // Default memory allocation - container_port = 80 // Example default port (you can change this) - container_health_check_path = "/health" // Example health check path (you can change this) - environment_variables = {} // Default to an empty map - } -} - -# Load balancer -variable "alb" { - type = object({ - name = string - listener_port = number - deregistration_delay = optional(number) - security_group_id = string - }) - description = "ALB-related information (listening port, deletion protection, security group)" - default = { - name = "" // Default ALB name - listener_port = 80 // Default listener port - deregistration_delay = 300 // Default deregistration delay - security_group_id = "" // Example default security group ID - } -} - diff --git a/outputs.tf b/outputs.tf deleted file mode 100644 index 884942a..0000000 --- a/outputs.tf +++ /dev/null @@ -1,63 +0,0 @@ -################################################################################ -## cluster -################################################################################ -output "cluster_arn" { - description = "ECS Cluster ARN" - value = module.ecs.cluster_arn -} - -output "cluster_id" { - description = "ECS Cluster ID" - value = module.ecs.cluster_id -} - -output "cluster_name" { - description = "ECS Cluster name" - value = module.ecs.cluster_name -} - -################################################################################ -## alb -################################################################################ -output "alb_arn" { - description = "ARN to the ALB" - value = module.alb.alb_arn -} - -output "alb_dns_name" { - description = "External DNS name to the ALB" - value = module.alb.alb_dns_name -} - -output "alb_dns_zone_id" { - description = "External DNS name to the ALB" - value = module.alb.alb_zone_id -} - -output "health_check_fqdn" { - description = "Health check FQDN record created in Route 53." - value = module.health_check.route_53_fqdn -} - -output "alb_https_listener_arn" { - value = aws_lb_listener.https.arn - description = "HTTPS listener ARN for downstream services to use" -} - -output "alb_http_listener_arn" { - value = aws_lb_listener.http.arn - description = "HTTP listener ARN for downstream services to use" -} - -output "alb_security_group_id" { - value = module.alb_sg.id - description = "ALB Security Group" -} - -################################################################################ -## acm -################################################################################ -output "alb_certificate_arn" { - description = "ACM Certificate ARN" - value = try(module.acm[0].arn, var.alb_certificate_arn) -} diff --git a/variables.tf b/variables.tf index 3ea986f..7fc33ea 100644 --- a/variables.tf +++ b/variables.tf @@ -1,219 +1,208 @@ ################################################################################ -## shared +## ecs cluster +################################################################################ + +variable "ecs_cluster" { + type = object({ + name = string + configuration = optional(object({ + execute_command_configuration = optional(object({ + kms_key_id = optional(string, "") + logging = optional(string, "DEFAULT") + log_configuration = optional(object({ + cloudwatch_encryption_enabled = optional(bool, null) + log_group_name = optional(string, null) + log_group_retention_in_days = optional(number, null) + log_group_kms_key_id = optional(string, null) + log_group_tags = optional(map(string), null) + s3_bucket_name = optional(string, null) + s3_bucket_encryption_enabled = optional(bool, null) + s3_key_prefix = optional(string, null) + }), {}) + }), {}) + }), {}) + create_cloudwatch_log_group = bool + service_connect_defaults = optional(map(string), null) + settings = optional(any, null) + tags = optional(map(string), null) + }) + description = <