From 9e151ad980df1abbb18ffb304686033ae7ad740a Mon Sep 17 00:00:00 2001 From: Pablo Sanchez Carmona Date: Fri, 21 Apr 2023 22:07:35 +0200 Subject: [PATCH 1/6] add connect_to_igw key in public subnets --- data.tf | 3 +++ main.tf | 4 ++-- variables.tf | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/data.tf b/data.tf index 8266403..feb6307 100644 --- a/data.tf +++ b/data.tf @@ -54,6 +54,9 @@ locals { create_acceptance = (local.require_acceptance == true && local.accept_attachment == true) create_cwan_routes = (local.require_acceptance == false) || local.create_acceptance + # default value for var.subnets.public.connect_to_igw (default to true) + connect_to_igw = try(var.subnets.public.connect_to_igw, true) + ################################################################## # NAT configurations options, maps user string input to HCL usable values. selected based on nat_gateway_configuration # null = none diff --git a/main.tf b/main.tf index e18105f..fd6c9c1 100644 --- a/main.tf +++ b/main.tf @@ -146,7 +146,7 @@ resource "aws_egress_only_internet_gateway" "eigw" { # Route: 0.0.0.0/0 from public subnets to the Internet gateway resource "aws_route" "public_to_igw" { - for_each = contains(local.subnet_keys, "public") && !local.public_ipv6only ? toset(local.azs) : toset([]) + for_each = contains(local.subnet_keys, "public") && !local.public_ipv6only && local.connect_to_igw ? toset(local.azs) : toset([]) route_table_id = aws_route_table.public[each.key].id destination_cidr_block = "0.0.0.0/0" @@ -155,7 +155,7 @@ resource "aws_route" "public_to_igw" { # Route: ::/0 from public subnets to the Internet gateway resource "aws_route" "public_ipv6_to_igw" { - for_each = contains(local.subnet_keys, "public") && (local.public_ipv6only || local.public_dualstack) ? toset(local.azs) : toset([]) + for_each = contains(local.subnet_keys, "public") && (local.public_ipv6only || local.public_dualstack) && local.connect_to_igw ? toset(local.azs) : toset([]) route_table_id = aws_route_table.public[each.key].id destination_ipv6_cidr_block = "::/0" diff --git a/variables.tf b/variables.tf index 672c34c..8e7e6d8 100644 --- a/variables.tf +++ b/variables.tf @@ -123,6 +123,7 @@ variable "subnets" { **public subnet type options:** - All shared keys above - `nat_gateway_configuration` = (Optional|string) Determines if NAT Gateways should be created and in how many AZs. Valid values = `"none"`, `"single_az"`, `"all_azs"`. Default = "none". Must also set `var.subnets.private.connect_to_public_natgw = true`. + - `connect_to_igw` = (Optional|bool) Determines if the default route (0.0.0.0/0 or ::/0) is created in the public subnets with destination the Internet gateway. Defaults to `true`. - `ipv6_native` = (Optional|bool) Indicates whether to create an IPv6-ony subnet. Either `var.assign_ipv6_cidr` or `var.ipv6_cidrs` should be defined to allocate an IPv6 CIDR block. **transit_gateway subnet type options:** @@ -184,11 +185,12 @@ EOF # All var.subnets.public valid keys validation { - error_message = "Invalid key in public subnets. Valid options include: \"cidrs\", \"netmask\", \"name_prefix\", \"nat_gateway_configuration\", \"ipv6_native\", \"assign_ipv6_cidr\", \"ipv6_cidrs\", \"tags\"." + error_message = "Invalid key in public subnets. Valid options include: \"cidrs\", \"netmask\", \"name_prefix\", \"connect_to_igw\", \"nat_gateway_configuration\", \"ipv6_native\", \"assign_ipv6_cidr\", \"ipv6_cidrs\", \"tags\"." condition = length(setsubtract(keys(try(var.subnets.public, {})), [ "cidrs", "netmask", "name_prefix", + "connect_to_igw", "nat_gateway_configuration", "ipv6_native", "assign_ipv6_cidr", From 5590df98af3591b870f923ba5804155691da441b Mon Sep 17 00:00:00 2001 From: Pablo Sanchez Carmona Date: Wed, 3 May 2023 20:14:42 +0200 Subject: [PATCH 2/6] vpc lattice support --- README.md | 4 ++ data.tf | 11 +++++ examples/vpc_lattice/.header.md | 9 ++++ examples/vpc_lattice/README.md | 49 ++++++++++++++++++++++ examples/vpc_lattice/main.tf | 69 +++++++++++++++++++++++++++++++ examples/vpc_lattice/outputs.tf | 6 +++ examples/vpc_lattice/providers.tf | 15 +++++++ examples/vpc_lattice/variables.tf | 7 ++++ main.tf | 14 +++++++ outputs.tf | 9 +++- test/examples_vpc_lattice_test.go | 17 ++++++++ variables.tf | 23 +++++++++++ 12 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 examples/vpc_lattice/.header.md create mode 100644 examples/vpc_lattice/README.md create mode 100644 examples/vpc_lattice/main.tf create mode 100644 examples/vpc_lattice/outputs.tf create mode 100644 examples/vpc_lattice/providers.tf create mode 100644 examples/vpc_lattice/variables.tf create mode 100644 test/examples_vpc_lattice_test.go diff --git a/README.md b/README.md index 9238a57..7909138 100644 --- a/README.md +++ b/README.md @@ -323,6 +323,7 @@ Please see our [developer documentation](https://github.com/aws-ia/terraform-aws | [flow\_logs](#module\_flow\_logs) | ./modules/flow_logs | n/a | | [subnet\_tags](#module\_subnet\_tags) | aws-ia/label/aws | 0.0.5 | | [tags](#module\_tags) | aws-ia/label/aws | 0.0.5 | +| [vpc\_lattice\_tags](#module\_vpc\_lattice\_tags) | aws-ia/label/aws | 0.0.5 | ## Resources @@ -363,6 +364,7 @@ Please see our [developer documentation](https://github.com/aws-ia/terraform-aws | [aws_subnet.tgw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | | [aws_vpc.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) | resource | | [aws_vpc_ipv4_cidr_block_association.secondary](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_ipv4_cidr_block_association) | resource | +| [aws_vpclattice_service_network_vpc_association.vpc_lattice_service_network_association](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpclattice_service_network_vpc_association) | resource | | [aws_availability_zones.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | | [aws_vpc.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc) | data source | @@ -393,6 +395,7 @@ Please see our [developer documentation](https://github.com/aws-ia/terraform-aws | [vpc\_ipv6\_cidr\_block](#input\_vpc\_ipv6\_cidr\_block) | IPv6 CIDR range to assign to VPC if creating VPC. You need to use `vpc_ipv6_ipam_pool_id` and set explicitly the CIDR block to use, or derived from IPAM using using `vpc_ipv6_netmask_lenght`. | `string` | `null` | no | | [vpc\_ipv6\_ipam\_pool\_id](#input\_vpc\_ipv6\_ipam\_pool\_id) | Set to use IPAM to get an IPv6 CIDR block. | `string` | `null` | no | | [vpc\_ipv6\_netmask\_length](#input\_vpc\_ipv6\_netmask\_length) | Set to use IPAM to get an IPv6 CIDR block using a specified netmask. Must be set with `var.vpc_ipv6_ipam_pool_id`. | `string` | `null` | no | +| [vpc\_lattice](#input\_vpc\_lattice) | Amazon VPC Lattice Service Network VPC association. You can only associate one Service Network to the VPC. This association also support Security Groups (more than 1).
This variable expects the following attributes:
- `service_network_identifier` = (Required\|string) The ID or ARN of the Service Network to associate. You must use the ARN if the Service Network and VPC resources are in different AWS Accounts.
- `security_group_ids = (Optional|list(string)) The IDs of the security groups to attach to the association.
- `tags` = = (Optional|map(string)) Tags to set on the Lattice VPC association resource.
` | `any` | `{}` | no | | [vpc\_secondary\_cidr](#input\_vpc\_secondary\_cidr) | If `true` the module will create a `aws_vpc_ipv4_cidr_block_association` and subnets for that secondary cidr. If using IPAM for both primary and secondary CIDRs, you may only call this module serially (aka using `-target`, etc). | `bool` | `false` | no | | [vpc\_secondary\_cidr\_natgw](#input\_vpc\_secondary\_cidr\_natgw) | If attaching a secondary IPv4 CIDR instead of creating a VPC, you can map private/ tgw subnets to your public NAT GW with this argument. Simply pass the output `nat_gateway_attributes_by_az`, ex: `vpc_secondary_cidr_natgw = module.vpc.natgw_id_per_az`. If you did not build your primary with this module, you must construct a map { az : { id : nat-123asdb }} for each az. | `any` | `{}` | no | @@ -413,4 +416,5 @@ Please see our [developer documentation](https://github.com/aws-ia/terraform-aws | [tgw\_subnet\_attributes\_by\_az](#output\_tgw\_subnet\_attributes\_by\_az) | Map of all tgw subnets containing their attributes.

Example:
tgw_subnet_attributes = {
"us-east-1a" = {
"arn" = "arn:aws:ec2:us-east-1:<>:subnet/subnet-04a86315c4839b519"
"assign_ipv6_address_on_creation" = false
...

}
"us-east-1b" = {...)
}
| | [transit\_gateway\_attachment\_id](#output\_transit\_gateway\_attachment\_id) | Transit gateway attachment id. | | [vpc\_attributes](#output\_vpc\_attributes) | VPC resource attributes. Full output of aws\_vpc. | +| [vpc\_lattice\_service\_network\_association](#output\_vpc\_lattice\_service\_network\_association) | VPC Lattice Service Network VPC association. Full output of aws\_vpclattice\_service\_network\_vpc\_association | \ No newline at end of file diff --git a/data.tf b/data.tf index feb6307..411b239 100644 --- a/data.tf +++ b/data.tf @@ -112,6 +112,10 @@ locals { private_subnets_egress_routed = [for type in local.private_subnet_names : type if try(var.subnets[type].connect_to_eigw == true, false)] # private subnets with cidrs per az if connect_to_public_eigw = true ... "privatetwo/us-east-1a" private_subnet_names_egress_routed = [for subnet in local.private_per_az : subnet if contains(local.private_subnets_egress_routed, split("/", subnet)[0])] + + # VPC LATTICE ############################################################ + # If var.vpc_lattice is defined (default = {}), the VPC association is created. + lattice_association = length(keys(var.vpc_lattice)) > 0 } data "aws_availability_zones" "current" {} @@ -140,3 +144,10 @@ module "subnet_tags" { tags = each.value } + +module "vpc_lattice_tags" { + source = "aws-ia/label/aws" + version = "0.0.5" + + tags = try(var.vpc_lattice.tags, {}) +} diff --git a/examples/vpc_lattice/.header.md b/examples/vpc_lattice/.header.md new file mode 100644 index 0000000..b3c05c6 --- /dev/null +++ b/examples/vpc_lattice/.header.md @@ -0,0 +1,9 @@ +# Creating Amazon VPC Lattice Service Network VPC Assocation + +This example shows how you can use this module to create a [VPC Lattice]() Service Network VPC association. The example creates: + +* VPC Lattice Service Network. +* Security Group (allowing HTTP and HTTPS traffic from the local CIDR). Used to attach it to the VPC Lattice association +* The VPC module creates the following: + * One set of subnets (*workload*) + * VPC Lattice Service Network VPC association. \ No newline at end of file diff --git a/examples/vpc_lattice/README.md b/examples/vpc_lattice/README.md new file mode 100644 index 0000000..d9bf938 --- /dev/null +++ b/examples/vpc_lattice/README.md @@ -0,0 +1,49 @@ + +# Creating Amazon VPC Lattice Service Network VPC Assocation + +This example shows how you can use this module to create a [VPC Lattice]() Service Network VPC association. The example creates: + +* VPC Lattice Service Network. +* Security Group (allowing HTTP and HTTPS traffic from the local CIDR). Used to attach it to the VPC Lattice association +* The VPC module creates the following: + * One set of subnets (*workload*) + * VPC Lattice Service Network VPC association. + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.3.0 | +| [aws](#requirement\_aws) | >= 4.65.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 4.65.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [vpc](#module\_vpc) | ../.. | n/a | + +## Resources + +| Name | Type | +|------|------| +| [aws_security_group.security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | +| [aws_vpclattice_service_network.service_network](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpclattice_service_network) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [aws\_region](#input\_aws\_region) | AWS Region. | `string` | `"eu-west-1"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [vpc\_lattice\_service\_network\_association](#output\_vpc\_lattice\_service\_network\_association) | VPC Lattice Service Network VPC association. | + \ No newline at end of file diff --git a/examples/vpc_lattice/main.tf b/examples/vpc_lattice/main.tf new file mode 100644 index 0000000..9ab9d80 --- /dev/null +++ b/examples/vpc_lattice/main.tf @@ -0,0 +1,69 @@ + + +# VPC module +module "vpc" { + #source = "aws-ia/vpc/aws" + #version = ">= 4.3.0" + source = "../.." + + name = "tgw" + cidr_block = "10.0.0.0/24" + az_count = 2 + + vpc_lattice = { + service_network_identifier = aws_vpclattice_service_network.service_network.id + security_group_ids = [aws_security_group.security_group.id] + tags = { + vpc_lattice = true + } + } + + subnets = { + workload = { netmask = 28 } + } + + tags = { + vpc_module = true + } +} + +# VPC Lattice Service Network +resource "aws_vpclattice_service_network" "service_network" { + name = "example-service-network" + auth_type = "NONE" +} + +# Security Group +resource "aws_security_group" "security_group" { + name = "lattice-sg" + description = "Lattice Securigy Group." + vpc_id = module.vpc.vpc_attributes.id + + ingress { + description = "Allow HTTP" + from_port = 80 + to_port = 80 + protocol = "tcp" + cidr_blocks = ["10.0.0.0/24"] + } + + ingress { + description = "Allow HTTPS" + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = ["10.0.0.0/24"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} + + + + + diff --git a/examples/vpc_lattice/outputs.tf b/examples/vpc_lattice/outputs.tf new file mode 100644 index 0000000..35e79f5 --- /dev/null +++ b/examples/vpc_lattice/outputs.tf @@ -0,0 +1,6 @@ +## Used for Testing, do not delete + +output "vpc_lattice_service_network_association" { + description = "VPC Lattice Service Network VPC association." + value = module.vpc.vpc_lattice_service_network_association.id +} diff --git a/examples/vpc_lattice/providers.tf b/examples/vpc_lattice/providers.tf new file mode 100644 index 0000000..ae67b93 --- /dev/null +++ b/examples/vpc_lattice/providers.tf @@ -0,0 +1,15 @@ +terraform { + required_version = ">= 1.3.0" + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 4.65.0" + } + } +} + +# Provider definition +provider "aws" { + region = var.aws_region +} + diff --git a/examples/vpc_lattice/variables.tf b/examples/vpc_lattice/variables.tf new file mode 100644 index 0000000..6b49389 --- /dev/null +++ b/examples/vpc_lattice/variables.tf @@ -0,0 +1,7 @@ + +variable "aws_region" { + description = "AWS Region." + type = string + + default = "eu-west-1" +} \ No newline at end of file diff --git a/main.tf b/main.tf index a99757c..5bf91a7 100644 --- a/main.tf +++ b/main.tf @@ -508,3 +508,17 @@ module "flow_logs" { tags = module.tags.tags_aws } + +# ---------- VPC LATTICE SERVICE NETWORK VPC ASSOCIATION ---------- +resource "aws_vpclattice_service_network_vpc_association" "vpc_lattice_service_network_association" { + count = local.lattice_association ? 1 : 0 + + vpc_identifier = aws_vpc.main[0].id + service_network_identifier = var.vpc_lattice.service_network_identifier + security_group_ids = try(var.vpc_lattice.security_group_ids, null) + + tags = merge( + module.tags.tags_aws, + module.vpc_lattice_tags.tags_aws + ) +} \ No newline at end of file diff --git a/outputs.tf b/outputs.tf index 96e2bf1..6f9f9e6 100644 --- a/outputs.tf +++ b/outputs.tf @@ -179,11 +179,16 @@ EOF } output "internet_gateway" { - value = try(aws_internet_gateway.main, null) + value = try(aws_internet_gateway.main[0], null) description = "Internet gateway attributes. Full output of aws_internet_gateway." } output "egress_only_internet_gateway" { - value = try(aws_egress_only_internet_gateway.eigw, null) + value = try(aws_egress_only_internet_gateway.eigw[0], null) description = "Egress-only Internet gateway attributes. Full output of aws_egress_only_internet_gateway." } + +output "vpc_lattice_service_network_association" { + value = try(aws_vpclattice_service_network_vpc_association.vpc_lattice_service_network_association[0], null) + description = "VPC Lattice Service Network VPC association. Full output of aws_vpclattice_service_network_vpc_association" +} \ No newline at end of file diff --git a/test/examples_vpc_lattice_test.go b/test/examples_vpc_lattice_test.go new file mode 100644 index 0000000..76c1260 --- /dev/null +++ b/test/examples_vpc_lattice_test.go @@ -0,0 +1,17 @@ +package test + +import ( + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" +) + +func TestExamplesVPCLattice(t *testing.T) { + + terraformOptions := &terraform.Options{ + TerraformDir: "../examples/vpc_lattice", + } + + defer terraform.Destroy(t, terraformOptions) + terraform.InitAndApply(t, terraformOptions) +} \ No newline at end of file diff --git a/variables.tf b/variables.tf index 8e7e6d8..37453d1 100644 --- a/variables.tf +++ b/variables.tf @@ -371,3 +371,26 @@ EOF type = any default = {} } + +variable "vpc_lattice" { + description = <<-EOF + Amazon VPC Lattice Service Network VPC association. You can only associate one Service Network to the VPC. This association also support Security Groups (more than 1). + This variable expects the following attributes: + - `service_network_identifier` = (Required|string) The ID or ARN of the Service Network to associate. You must use the ARN if the Service Network and VPC resources are in different AWS Accounts. + - `security_group_ids = (Optional|list(string)) The IDs of the security groups to attach to the association. + - `tags` = = (Optional|map(string)) Tags to set on the Lattice VPC association resource. +EOF + type = any + + default = {} + + # All var.vpc_lattice valid keys + validation { + error_message = "Invalid key in var.vpc_lattice. Valid options include: \"service_network_identifier\", \"security_group_ids\", \"tags\"." + condition = length(setsubtract(keys(var.vpc_lattice), [ + "service_network_identifier", + "security_group_ids", + "tags" + ])) == 0 + } +} From 8d9c198e8997edbeaeec96d2cabf2c911744b71c Mon Sep 17 00:00:00 2001 From: Pablo Sanchez Carmona Date: Wed, 3 May 2023 20:27:43 +0200 Subject: [PATCH 3/6] fixing tfsec findings --- examples/vpc_lattice/main.tf | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/examples/vpc_lattice/main.tf b/examples/vpc_lattice/main.tf index 9ab9d80..d76c5ca 100644 --- a/examples/vpc_lattice/main.tf +++ b/examples/vpc_lattice/main.tf @@ -56,10 +56,19 @@ resource "aws_security_group" "security_group" { } egress { + description = "Allowing inter-VPC traffic." from_port = 0 to_port = 0 protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] + cidr_blocks = ["10.0.0.0/24"] + } + + egress { + description = "Allowing VPC Lattice traffic." + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["169.254.171.0/24"] } } From e3ab801355217d34fab1456493b0a52823fd7295 Mon Sep 17 00:00:00 2001 From: Pablo Sanchez Carmona Date: Thu, 4 May 2023 09:46:31 +0200 Subject: [PATCH 4/6] filter in az data source - to only get AZ IDs --- data.tf | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/data.tf b/data.tf index 411b239..901e139 100644 --- a/data.tf +++ b/data.tf @@ -118,7 +118,12 @@ locals { lattice_association = length(keys(var.vpc_lattice)) > 0 } -data "aws_availability_zones" "current" {} +data "aws_availability_zones" "current" { + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} # search for existing vpc with var.vpc_id if not creating data "aws_vpc" "main" { From 8610776b179c11b01e6ae65caa7e786ee6cc3424 Mon Sep 17 00:00:00 2001 From: Pablo Sanchez Carmona Date: Mon, 12 Jun 2023 19:39:41 +0200 Subject: [PATCH 5/6] fixing vpc_lattice example --- examples/vpc_lattice/main.tf | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/vpc_lattice/main.tf b/examples/vpc_lattice/main.tf index d76c5ca..70d944e 100644 --- a/examples/vpc_lattice/main.tf +++ b/examples/vpc_lattice/main.tf @@ -1,10 +1,8 @@ - # VPC module module "vpc" { - #source = "aws-ia/vpc/aws" - #version = ">= 4.3.0" - source = "../.." + source = "aws-ia/vpc/aws" + version = ">= 4.3.0" name = "tgw" cidr_block = "10.0.0.0/24" From 4d72ea648e2e6931840b9a8d135df820b8eb7d56 Mon Sep 17 00:00:00 2001 From: Pablo Sanchez Carmona Date: Mon, 12 Jun 2023 19:40:45 +0200 Subject: [PATCH 6/6] README update --- examples/vpc_lattice/.terraform-docs.yaml | 21 +++++++++++++++++++++ examples/vpc_lattice/README.md | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 examples/vpc_lattice/.terraform-docs.yaml diff --git a/examples/vpc_lattice/.terraform-docs.yaml b/examples/vpc_lattice/.terraform-docs.yaml new file mode 100644 index 0000000..6dc99de --- /dev/null +++ b/examples/vpc_lattice/.terraform-docs.yaml @@ -0,0 +1,21 @@ +formatter: markdown +header-from: .header.md +settings: + anchor: true + color: true + default: true + escape: true + html: true + indent: 2 + required: true + sensitive: true + type: true + lockfile: false + +sort: + enabled: true + by: required + +output: + file: README.md + mode: replace diff --git a/examples/vpc_lattice/README.md b/examples/vpc_lattice/README.md index d9bf938..6abc4ea 100644 --- a/examples/vpc_lattice/README.md +++ b/examples/vpc_lattice/README.md @@ -26,7 +26,7 @@ This example shows how you can use this module to create a [VPC Lattice]() Servi | Name | Source | Version | |------|--------|---------| -| [vpc](#module\_vpc) | ../.. | n/a | +| [vpc](#module\_vpc) | aws-ia/vpc/aws | >= 4.3.0 | ## Resources