From f40dd21fd3a1a4a3c1043e359277411555661df4 Mon Sep 17 00:00:00 2001 From: Superblocks Admin Date: Mon, 29 Jul 2024 23:57:08 -0400 Subject: [PATCH] Migrate to managed module --- main.tf | 2 +- modules/ecs/main.tf | 4 +- modules/load-balancer/main.tf | 4 +- modules/security-group/main.tf | 125 ++++++++++++ modules/security-group/outputs.tf | 29 +++ modules/security-group/provider.tf | 10 + modules/security-group/variables.tf | 83 ++++++++ modules/vpc/main.tf | 294 ++++++++++++++++++++++++++-- modules/vpc/output.tf | 12 ++ modules/vpc/outputs.tf | 11 -- modules/vpc/variables.tf | 182 +++++++++++++++-- variables.tf | 6 +- 12 files changed, 717 insertions(+), 45 deletions(-) create mode 100644 modules/security-group/main.tf create mode 100644 modules/security-group/outputs.tf create mode 100644 modules/security-group/provider.tf create mode 100644 modules/security-group/variables.tf create mode 100644 modules/vpc/output.tf delete mode 100644 modules/vpc/outputs.tf diff --git a/main.tf b/main.tf index 8e33e1f..dd3b0f7 100644 --- a/main.tf +++ b/main.tf @@ -8,7 +8,7 @@ locals { module "vpc" { count = var.create_vpc ? 1 : 0 source = "./modules/vpc" - name_prefix = var.name_prefix + name = "${var.name_prefix}-vpc" } ################################################################# diff --git a/modules/ecs/main.tf b/modules/ecs/main.tf index 2144ea4..ad73979 100644 --- a/modules/ecs/main.tf +++ b/modules/ecs/main.tf @@ -196,8 +196,7 @@ resource "aws_appautoscaling_policy" "cpu" { module "ecs_security_group" { count = var.create_sg ? 1 : 0 - source = "terraform-aws-modules/security-group/aws" - version = ">=5.0.0" + source = "../security-group" name = "${var.name_prefix}-ecs-sg" vpc_id = var.vpc_id ingress_with_source_security_group_id = flatten([ @@ -220,5 +219,4 @@ module "ecs_security_group" { ]) egress_with_cidr_blocks = var.sg_egress_with_cidr_blocks tags = var.tags - use_name_prefix = true } diff --git a/modules/load-balancer/main.tf b/modules/load-balancer/main.tf index 8905263..f2ecf8a 100644 --- a/modules/load-balancer/main.tf +++ b/modules/load-balancer/main.tf @@ -87,12 +87,10 @@ resource "aws_lb_listener" "grpc" { module "loadbalancer_security_group" { count = var.create_sg ? 1 : 0 - source = "terraform-aws-modules/security-group/aws" - version = ">=5.0.0" + source = "../security-group" name = "${var.name_prefix}-lb-sg" vpc_id = var.vpc_id ingress_with_cidr_blocks = var.sg_ingress_with_cidr_blocks egress_with_cidr_blocks = var.sg_egress_with_cidr_blocks tags = var.tags - use_name_prefix = true } diff --git a/modules/security-group/main.tf b/modules/security-group/main.tf new file mode 100644 index 0000000..f9537f2 --- /dev/null +++ b/modules/security-group/main.tf @@ -0,0 +1,125 @@ +################################# +# Security group with name_prefix +################################# +resource "aws_security_group" "this_name_prefix" { + count = 1 + name_prefix = "${var.name}-" + vpc_id = var.vpc_id + revoke_rules_on_delete = false + + tags = merge( + { + "Name" = format("%s", var.name) + }, + var.tags, + ) + + lifecycle { + create_before_destroy = true + } + + timeouts { + create = var.create_timeout + delete = var.delete_timeout + } +} + +resource "aws_security_group_rule" "ingress_with_source_security_group_id" { + count = length(var.ingress_with_source_security_group_id) + + security_group_id = aws_security_group.this_name_prefix[0].id + type = "ingress" + + source_security_group_id = var.ingress_with_source_security_group_id[count.index]["source_security_group_id"] + prefix_list_ids = var.ingress_prefix_list_ids + description = lookup( + var.ingress_with_source_security_group_id[count.index], + "description", + "Ingress Rule", + ) + + from_port = lookup( + var.ingress_with_source_security_group_id[count.index], + "from_port", + ) + to_port = lookup( + var.ingress_with_source_security_group_id[count.index], + "to_port", + ) + protocol = lookup( + var.ingress_with_source_security_group_id[count.index], + "protocol", + ) +} + + +resource "aws_security_group_rule" "ingress_with_cidr_blocks" { + count = length(var.ingress_with_cidr_blocks) + + security_group_id = aws_security_group.this_name_prefix[0].id + type = "ingress" + + cidr_blocks = compact(split( + ",", + lookup( + var.ingress_with_cidr_blocks[count.index], + "cidr_blocks", + join(",", var.ingress_cidr_blocks), + ), + )) + prefix_list_ids = var.ingress_prefix_list_ids + description = lookup( + var.ingress_with_cidr_blocks[count.index], + "description", + "Ingress Rule", + ) + + from_port = lookup( + var.ingress_with_cidr_blocks[count.index], + "from_port", + ) + to_port = lookup( + var.ingress_with_cidr_blocks[count.index], + "to_port", + ) + protocol = lookup( + var.ingress_with_cidr_blocks[count.index], + "protocol", + ) +} + + +resource "aws_security_group_rule" "egress_with_cidr_blocks" { + count = length(var.egress_with_cidr_blocks) + + security_group_id = aws_security_group.this_name_prefix[0].id + type = "egress" + + cidr_blocks = compact(split( + ",", + lookup( + var.egress_with_cidr_blocks[count.index], + "cidr_blocks", + join(",", var.egress_cidr_blocks), + ), + )) + prefix_list_ids = var.egress_prefix_list_ids + description = lookup( + var.egress_with_cidr_blocks[count.index], + "description", + "Egress Rule", + ) + + from_port = lookup( + var.egress_with_cidr_blocks[count.index], + "from_port", + ) + to_port = lookup( + var.egress_with_cidr_blocks[count.index], + "to_port", + ) + protocol = lookup( + var.egress_with_cidr_blocks[count.index], + "protocol", + ) +} diff --git a/modules/security-group/outputs.tf b/modules/security-group/outputs.tf new file mode 100644 index 0000000..65ec4aa --- /dev/null +++ b/modules/security-group/outputs.tf @@ -0,0 +1,29 @@ +output "security_group_arn" { + description = "The ARN of the security group" + value = aws_security_group.this_name_prefix[0].arn +} + +output "security_group_id" { + description = "The ID of the security group" + value = aws_security_group.this_name_prefix[0].id +} + +output "security_group_vpc_id" { + description = "The VPC ID" + value = aws_security_group.this_name_prefix[0].vpc_id +} + +output "security_group_owner_id" { + description = "The owner ID" + value = aws_security_group.this_name_prefix[0].owner_id +} + +output "security_group_name" { + description = "The name of the security group" + value = aws_security_group.this_name_prefix[0].name +} + +output "security_group_description" { + description = "The description of the security group" + value = aws_security_group.this_name_prefix[0].description +} diff --git a/modules/security-group/provider.tf b/modules/security-group/provider.tf new file mode 100644 index 0000000..729454b --- /dev/null +++ b/modules/security-group/provider.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.0.0" + } + } +} diff --git a/modules/security-group/variables.tf b/modules/security-group/variables.tf new file mode 100644 index 0000000..16f2564 --- /dev/null +++ b/modules/security-group/variables.tf @@ -0,0 +1,83 @@ +################# +# Security group +################# + +variable "vpc_id" { + description = "ID of the VPC where to create security group" + type = string + default = null +} + +variable "name" { + description = "Name of security group - not required if create_sg is false" + type = string + default = null +} + +variable "tags" { + description = "A mapping of tags to assign to security group" + type = map(string) + default = {} +} + +variable "create_timeout" { + description = "Time to wait for a security group to be created" + type = string + default = "10m" +} + +variable "delete_timeout" { + description = "Time to wait for a security group to be deleted" + type = string + default = "15m" +} + +########## +# Ingress +########## + +variable "ingress_with_cidr_blocks" { + description = "List of ingress rules to create where 'cidr_blocks' is used" + type = list(map(string)) + default = [] +} + +variable "ingress_with_source_security_group_id" { + description = "List of ingress rules to create where 'source_security_group_id' is used" + type = list(map(string)) + default = [] +} + +variable "ingress_cidr_blocks" { + description = "List of IPv4 CIDR ranges to use on all ingress rules" + type = list(string) + default = [] +} + +variable "ingress_prefix_list_ids" { + description = "List of prefix list IDs (for allowing access to VPC endpoints) to use on all ingress rules" + type = list(string) + default = [] +} + +######### +# Egress +######### + +variable "egress_with_cidr_blocks" { + description = "List of egress rules to create where 'cidr_blocks' is used" + type = list(map(string)) + default = [] +} + +variable "egress_cidr_blocks" { + description = "List of IPv4 CIDR ranges to use on all egress rules" + type = list(string) + default = ["0.0.0.0/0"] +} + +variable "egress_prefix_list_ids" { + description = "List of prefix list IDs (for allowing access to VPC endpoints) to use on all egress rules" + type = list(string) + default = [] +} diff --git a/modules/vpc/main.tf b/modules/vpc/main.tf index 6ad1f02..0cdbb9a 100644 --- a/modules/vpc/main.tf +++ b/modules/vpc/main.tf @@ -1,16 +1,288 @@ +locals { + len_public_subnets = length(var.public_subnets) + len_private_subnets = length(var.private_subnets) + + max_subnet_length = max( + local.len_private_subnets, + local.len_public_subnets, + ) + + vpc_id = aws_vpc.this.id + + azs = length(var.azs) > 0 ? var.azs : data.aws_availability_zones.available.names +} + data "aws_availability_zones" "available" { state = "available" } -module "vpc" { - source = "terraform-aws-modules/vpc/aws" - version = "5.1.1" - name = "${var.name_prefix}-vpc" - cidr = var.cidr_block - azs = data.aws_availability_zones.available.names - private_subnets = var.private_subnets - public_subnets = var.public_subnets - enable_nat_gateway = true - enable_vpn_gateway = false - tags = var.tags + +################################################################################ +# VPC +################################################################################ + +resource "aws_vpc" "this" { + cidr_block = var.cidr + + assign_generated_ipv6_cidr_block = false + + instance_tenancy = "default" + enable_dns_hostnames = "true" + enable_dns_support = "true" + + tags = merge( + { "Name" = var.name }, + var.tags, + ) +} + +################################################################################ +# Publiс Subnets +################################################################################ + +resource "aws_subnet" "public" { + count = local.len_public_subnets + + availability_zone = length(regexall("^[a-z]{2}-", element(local.azs, count.index))) > 0 ? element(local.azs, count.index) : null + availability_zone_id = length(regexall("^[a-z]{2}-", element(local.azs, count.index))) == 0 ? element(local.azs, count.index) : null + cidr_block = element(concat(var.public_subnets, [""]), count.index) + vpc_id = local.vpc_id + + tags = merge( + { + Name = try( + format("${var.name}-public-%s", element(local.azs, count.index)) + ) + }, + var.tags, + ) +} + +locals { + num_public_route_tables = local.len_public_subnets +} + +resource "aws_route_table" "public" { + + vpc_id = local.vpc_id + + tags = merge( + { + "Name" = "${var.name}-public", + }, + var.tags, + ) +} + +resource "aws_route_table_association" "public" { + count = local.len_public_subnets + + subnet_id = element(aws_subnet.public[*].id, count.index) + route_table_id = aws_route_table.public.id +} + +resource "aws_route" "public_internet_gateway" { + route_table_id = aws_route_table.public.id + destination_cidr_block = "0.0.0.0/0" + gateway_id = aws_internet_gateway.this.id + + timeouts { + create = "5m" + } +} + +################################################################################ +# Private Subnets +################################################################################ + +resource "aws_subnet" "private" { + count = local.len_private_subnets + + availability_zone = length(regexall("^[a-z]{2}-", element(local.azs, count.index))) > 0 ? element(local.azs, count.index) : null + availability_zone_id = length(regexall("^[a-z]{2}-", element(local.azs, count.index))) == 0 ? element(local.azs, count.index) : null + cidr_block = element(concat(var.private_subnets, [""]), count.index) + vpc_id = local.vpc_id + + tags = merge( + { + Name = try( + format("${var.name}-private-%s", element(local.azs, count.index)) + ) + }, + var.tags, + ) +} + +# There are as many routing tables as the number of NAT gateways +resource "aws_route_table" "private" { + count = local.nat_gateway_count + + vpc_id = local.vpc_id + + tags = merge( + { + "Name" = format( + "${var.name}-private-%s", + element(local.azs, count.index), + ) + }, + var.tags, + ) +} + +resource "aws_route_table_association" "private" { + count = local.len_private_subnets + + subnet_id = element(aws_subnet.private[*].id, count.index) + route_table_id = element( + aws_route_table.private[*].id, + count.index, + ) +} + +################################################################################ +# Internet Gateway +################################################################################ + +resource "aws_internet_gateway" "this" { + vpc_id = local.vpc_id + + tags = merge( + { "Name" = var.name }, + var.tags, + ) +} + +################################################################################ +# NAT Gateway +################################################################################ + +locals { + nat_gateway_count = local.max_subnet_length + nat_gateway_ips = aws_eip.nat[*].id +} + +resource "aws_eip" "nat" { + count = local.nat_gateway_count + + domain = "vpc" + + tags = merge( + { + "Name" = format( + "${var.name}-%s", + element(local.azs, count.index), + ) + }, + var.tags, + ) + + depends_on = [aws_internet_gateway.this] +} + +resource "aws_nat_gateway" "this" { + count = local.nat_gateway_count + + allocation_id = element( + local.nat_gateway_ips, + count.index, + ) + subnet_id = element( + aws_subnet.public[*].id, + count.index, + ) + + tags = merge( + { + "Name" = format( + "${var.name}-%s", + element(local.azs, count.index), + ) + }, + var.tags, + ) + + depends_on = [aws_internet_gateway.this] +} + +resource "aws_route" "private_nat_gateway" { + count = local.nat_gateway_count + + route_table_id = element(aws_route_table.private[*].id, count.index) + destination_cidr_block = var.nat_gateway_destination_cidr_block + nat_gateway_id = element(aws_nat_gateway.this[*].id, count.index) + + timeouts { + create = "5m" + } +} + +################################################################################ +# Default Network ACLs +################################################################################ + +resource "aws_default_network_acl" "this" { + default_network_acl_id = aws_vpc.this.default_network_acl_id + + # subnet_ids is using lifecycle ignore_changes, so it is not necessary to list + # any explicitly. See https://github.com/terraform-aws-modules/terraform-aws-vpc/issues/736 + subnet_ids = null + + dynamic "ingress" { + for_each = var.default_network_acl_ingress + content { + action = ingress.value.action + cidr_block = lookup(ingress.value, "cidr_block", null) + from_port = ingress.value.from_port + icmp_code = lookup(ingress.value, "icmp_code", null) + icmp_type = lookup(ingress.value, "icmp_type", null) + ipv6_cidr_block = lookup(ingress.value, "ipv6_cidr_block", null) + protocol = ingress.value.protocol + rule_no = ingress.value.rule_no + to_port = ingress.value.to_port + } + } + dynamic "egress" { + for_each = var.default_network_acl_egress + content { + action = egress.value.action + cidr_block = lookup(egress.value, "cidr_block", null) + from_port = egress.value.from_port + icmp_code = lookup(egress.value, "icmp_code", null) + icmp_type = lookup(egress.value, "icmp_type", null) + ipv6_cidr_block = lookup(egress.value, "ipv6_cidr_block", null) + protocol = egress.value.protocol + rule_no = egress.value.rule_no + to_port = egress.value.to_port + } + } + + tags = merge( + { "Name" = "${var.name}-default" }, + var.tags, + ) + + lifecycle { + ignore_changes = [subnet_ids] + } +} + +################################################################################ +# Default Route +################################################################################ + +resource "aws_default_route_table" "default" { + + default_route_table_id = aws_vpc.this.default_route_table_id + propagating_vgws = [] + + timeouts { + create = "5m" + update = "5m" + } + + tags = merge( + { "Name" = "${var.name}-default" }, + var.tags, + ) } diff --git a/modules/vpc/output.tf b/modules/vpc/output.tf new file mode 100644 index 0000000..c950265 --- /dev/null +++ b/modules/vpc/output.tf @@ -0,0 +1,12 @@ +output "id" { + description = "The ID of the VPC" + value = aws_vpc.this.id +} + +output "lb_subnet_ids" { + value = aws_subnet.public[*].id +} + +output "ecs_subnet_ids" { + value = aws_subnet.private[*].id +} diff --git a/modules/vpc/outputs.tf b/modules/vpc/outputs.tf deleted file mode 100644 index 5370543..0000000 --- a/modules/vpc/outputs.tf +++ /dev/null @@ -1,11 +0,0 @@ -output "id" { - value = module.vpc.vpc_id -} - -output "lb_subnet_ids" { - value = module.vpc.public_subnets -} - -output "ecs_subnet_ids" { - value = module.vpc.private_subnets -} diff --git a/modules/vpc/variables.tf b/modules/vpc/variables.tf index cdf48c2..420c5f5 100644 --- a/modules/vpc/variables.tf +++ b/modules/vpc/variables.tf @@ -1,32 +1,188 @@ -variable "name_prefix" { - type = string - default = "superblocks" +################################################################################ +# VPC +################################################################################ + +variable "name" { + description = "Name to be used on all the resources as identifier" + type = string + default = "superblocks-vpc" } -variable "tags" { - type = map(string) - default = {} +variable "cidr" { + type = string + default = "10.0.0.0/20" +} + +variable "azs" { + description = "A list of availability zones names or ids in the region" + type = list(string) + default = [] } -variable "cidr_block" { - type = string - default = "10.0.0.0/20" +variable "tags" { + description = "A map of tags to add to all resources" + type = map(string) + default = {} } +################################################################################ +# Publiс Subnets +################################################################################ + variable "public_subnets" { - type = list(string) - default = [ + description = "A list of public subnets inside the VPC" + type = list(string) + default = [ "10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24", ] } -variable "private_subnets" { - type = list(string) +################################################################################ +# Public Network ACLs +################################################################################ + +variable "public_inbound_acl_rules" { + description = "Public subnets inbound network ACLs" + type = list(map(string)) default = [ + { + rule_number = 100 + rule_action = "allow" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_block = "0.0.0.0/0" + }, + ] +} + +variable "public_outbound_acl_rules" { + description = "Public subnets outbound network ACLs" + type = list(map(string)) + default = [ + { + rule_number = 100 + rule_action = "allow" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_block = "0.0.0.0/0" + }, + ] +} + +################################################################################ +# Private Subnets +################################################################################ + +variable "private_subnets" { + description = "A list of private subnets inside the VPC" + type = list(string) + default = [ "10.0.11.0/24", "10.0.12.0/24", "10.0.13.0/24", ] } + +################################################################################ +# Private Network ACLs +################################################################################ + +variable "private_dedicated_network_acl" { + description = "Whether to use dedicated network ACL (not default) and custom rules for private subnets" + type = bool + default = false +} + +variable "private_inbound_acl_rules" { + description = "Private subnets inbound network ACLs" + type = list(map(string)) + default = [ + { + rule_number = 100 + rule_action = "allow" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_block = "0.0.0.0/0" + }, + ] +} + +variable "private_outbound_acl_rules" { + description = "Private subnets outbound network ACLs" + type = list(map(string)) + default = [ + { + rule_number = 100 + rule_action = "allow" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_block = "0.0.0.0/0" + }, + ] +} + +################################################################################ +# NAT Gateway +################################################################################ + +variable "nat_gateway_destination_cidr_block" { + description = "Used to pass a custom destination route for private NAT Gateway. If not specified, the default 0.0.0.0/0 is used as a destination route" + type = string + default = "0.0.0.0/0" +} + +################################################################################ +# Default Network ACLs +################################################################################ + +variable "default_network_acl_ingress" { + description = "List of maps of ingress rules to set on the Default Network ACL" + type = list(map(string)) + default = [ + { + rule_no = 100 + action = "allow" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_block = "0.0.0.0/0" + }, + { + rule_no = 101 + action = "allow" + from_port = 0 + to_port = 0 + protocol = "-1" + ipv6_cidr_block = "::/0" + }, + ] +} + +variable "default_network_acl_egress" { + description = "List of maps of egress rules to set on the Default Network ACL" + type = list(map(string)) + default = [ + { + rule_no = 100 + action = "allow" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_block = "0.0.0.0/0" + }, + { + rule_no = 101 + action = "allow" + from_port = 0 + to_port = 0 + protocol = "-1" + ipv6_cidr_block = "::/0" + }, + ] +} diff --git a/variables.tf b/variables.tf index 3beefcb..85f56b9 100644 --- a/variables.tf +++ b/variables.tf @@ -141,7 +141,7 @@ variable "superblocks_agent_environment_variables" { ################################################################# variable "create_vpc" { type = bool - default = false + default = true description = "Whether to create default VPC or not." } @@ -174,7 +174,7 @@ variable "create_lb" { variable "lb_internal" { type = bool - default = true + default = false description = "When it's set to false, load balancer is accessible in public network." } @@ -263,7 +263,7 @@ variable "domain" { variable "subdomain" { type = string - default = "superblocks-agent" + default = "agent" description = <