Skip to content

Commit

Permalink
feat(MAJOR): Refactor module vpc, remove module subnet_set (#68)
Browse files Browse the repository at this point in the history
* remove subnet_set module
* extend vpc module to create subnets and route tables
* simplify subnets creation (not using complex locals from subnet_set module)
* adjust the variables in variables.tf and outputs inoutputs.tf in order that makes sense
* refactor variables e.g. create new variable internet_gateway, which defines object with attributes for IGW creation/usage
* adjust variables description to standard from Major refactor for modules and examples #53
* adjust all examples to new approach with vpc module
* adjust CloudNGFW examples to changes delivered for other examples in fix(examples): Refactor examples for reference architectures #49
* change approach for CloudWatch logs group in CloudNGFW (as the same name PaloAltoCloudNGFW has to be used for both examples, groups was created on account used in workflows and in TFVARS we are not creating new log group, we are reusing existing one)
* added support for all possible attributes for every resource used in module
* README changed to new standard with new file .header.md

Co-authored-by: michalbil <[email protected]>
  • Loading branch information
sebastianczech and michalbil authored Aug 29, 2024
1 parent ded78a9 commit 1c4112b
Show file tree
Hide file tree
Showing 65 changed files with 3,962 additions and 3,870 deletions.
6 changes: 5 additions & 1 deletion .releaserc.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"branches": [
"main"
"main",
{
"name": "rc",
"prerelease": true
}
],
"plugins": [
[
Expand Down
5 changes: 2 additions & 3 deletions examples/centralized_design/README.md

Large diffs are not rendered by default.

322 changes: 160 additions & 162 deletions examples/centralized_design/example.tfvars

Large diffs are not rendered by default.

126 changes: 35 additions & 91 deletions examples/centralized_design/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,74 +5,18 @@ module "vpc" {

for_each = var.vpcs

name = "${var.name_prefix}${each.value.name}"
cidr_block = each.value.cidr
nacls = each.value.nacls
security_groups = each.value.security_groups
create_internet_gateway = true
enable_dns_hostnames = true
enable_dns_support = true
instance_tenancy = "default"
}

### SUBNETS ###

locals {
# Flatten the VPCs and their subnets into a list of maps, each containing the VPC name, subnet name, and subnet details.
subnets_in_vpcs = flatten([for vk, vv in var.vpcs : [for sk, sv in vv.subnets :
{
cidr = sk
nacl = sv.nacl
az = sv.az
subnet = sv.subnet_group
vpc = vk
create_subnet = try(sv.create_subnet, true)
create_route_table = try(sv.create_route_table, sv.create_subnet, true)
existing_route_table_id = try(sv.existing_route_table_id, null)
associate_route_table = try(sv.associate_route_table, true)
route_table_name = try(sv.route_table_name, null)
local_tags = try(sv.local_tags, {})
}
]])
# Create a map of subnets, keyed by the VPC name and subnet name.
subnets_with_lists = { for subnet_in_vpc in local.subnets_in_vpcs : "${subnet_in_vpc.vpc}-${subnet_in_vpc.subnet}" => subnet_in_vpc... }
subnets = { for key, value in local.subnets_with_lists : key => {
vpc = distinct([for v in value : v.vpc])[0] # VPC name (always take first from the list as key is limitting number of VPCs)
subnet = distinct([for v in value : v.subnet])[0] # Subnet name (always take first from the list as key is limitting number of subnets)
az = [for v in value : v.az] # List of AZs
cidr = [for v in value : v.cidr] # List of CIDRs
nacl = compact([for v in value : v.nacl]) # List of NACLs
create_subnet = [for v in value : try(v.create_subnet, true)] # List of create_subnet flags
create_route_table = [for v in value : try(v.create_route_table, v.create_subnet, true)] # List of create_route_table flags
existing_route_table_id = [for v in value : try(v.existing_route_table_id, null)] # List of existing_route_table_id values
associate_route_table = [for v in value : try(v.associate_route_table, true)] # List of associate_route_table flags
route_table_name = [for v in value : try(v.route_table_name, null)] # List of route_table_name values
local_tags = [for v in value : try(v.local_tags, {})] # List of local_tags maps
} }
}

module "subnet_sets" {
source = "../../modules/subnet_set"

for_each = local.subnets

name = each.value.subnet
vpc_id = module.vpc[each.value.vpc].id
has_secondary_cidrs = module.vpc[each.value.vpc].has_secondary_cidrs
nacl_associations = {
for index, az in each.value.az : az =>
lookup(module.vpc[each.value.vpc].nacl_ids, each.value.nacl[index], null) if length(each.value.nacl) > 0
region = var.region
name = "${var.name_prefix}${each.value.name}"
cidr_block = each.value.cidr_block
subnets = each.value.subnets
nacls = each.value.nacls
security_groups = each.value.security_groups

options = {
enable_dns_hostnames = true
enable_dns_support = true
instance_tenancy = "default"
}
cidrs = {
for index, cidr in each.value.cidr : cidr => {
az = each.value.az[index]
create_subnet = each.value.create_subnet[index]
create_route_table = each.value.create_route_table[index]
existing_route_table_id = each.value.existing_route_table_id[index]
associate_route_table = each.value.associate_route_table[index]
route_table_name = each.value.route_table_name[index]
local_tags = each.value.local_tags[index]
} }
}

### ROUTES ###
Expand All @@ -83,7 +27,7 @@ locals {
#
# tgw_default = {
# vpc = "security_vpc"
# subnet = "tgw_attach"
# subnet_group = "tgw_attach"
# to_cidr = "0.0.0.0/0"
# next_hop_key = "security_gwlb_outbound"
# next_hop_type = "gwlbe_endpoint"
Expand All @@ -106,7 +50,7 @@ locals {
for vk, vv in var.vpcs : [
for rk, rv in vv.routes : {
vpc = rv.vpc
subnet = rv.subnet_group
subnet_group = rv.subnet_group
to_cidr = rv.to_cidr
next_hop_type = rv.next_hop_type
next_hop_map = {
Expand All @@ -118,9 +62,9 @@ locals {
}
]]))
vpc_routes = {
for route in local.vpc_routes_with_next_hop_map : "${route.vpc}-${route.subnet}-${route.to_cidr}" => {
for route in local.vpc_routes_with_next_hop_map : "${route.vpc}-${route.subnet_group}-${route.to_cidr}" => {
vpc = route.vpc
subnet = route.subnet
subnet_group = route.subnet_group
to_cidr = route.to_cidr
next_hop_set = lookup(route.next_hop_map, route.next_hop_type, null)
}
Expand All @@ -132,7 +76,7 @@ module "vpc_routes" {

for_each = local.vpc_routes

route_table_ids = module.subnet_sets["${each.value.vpc}-${each.value.subnet}"].unique_route_table_ids
route_table_ids = { for k, v in module.vpc[each.value.vpc].route_tables : v.az => v.id if v.subnet_group == each.value.subnet_group }
to_cidr = each.value.to_cidr
next_hop_set = each.value.next_hop_set
}
Expand All @@ -144,7 +88,7 @@ module "natgw_set" {

for_each = var.natgws

subnets = module.subnet_sets["${each.value.vpc}-${each.value.subnet_group}"].subnets
subnets = { for k, v in module.vpc[each.value.vpc].subnets : v.az => v if v.subnet_group == each.value.subnet_group }
}

### TGW ###
Expand All @@ -167,8 +111,8 @@ module "transit_gateway_attachment" {
for_each = var.tgw.attachments

name = "${var.name_prefix}${each.value.name}"
vpc_id = module.subnet_sets["${each.value.vpc}-${each.value.subnet_group}"].vpc_id
subnets = module.subnet_sets["${each.value.vpc}-${each.value.subnet_group}"].subnets
vpc_id = module.vpc[each.value.vpc].id
subnets = { for k, v in module.vpc[each.value.vpc].subnets : k => v if v.subnet_group == each.value.subnet_group }
transit_gateway_route_table = module.transit_gateway.route_tables[each.value.route_table]
propagate_routes_to = {
to1 = module.transit_gateway.route_tables[each.value.propagate_routes_to].id
Expand Down Expand Up @@ -198,8 +142,8 @@ module "gwlb" {
for_each = var.gwlbs

name = "${var.name_prefix}${each.value.name}"
vpc_id = module.subnet_sets["${each.value.vpc}-${each.value.subnet_group}"].vpc_id
subnets = module.subnet_sets["${each.value.vpc}-${each.value.subnet_group}"].subnets
vpc_id = module.vpc[each.value.vpc].id
subnets = { for k, v in module.vpc[each.value.vpc].subnets : v.az => v if v.subnet_group == each.value.subnet_group }
}

resource "aws_lb_target_group_attachment" "this" {
Expand All @@ -221,13 +165,13 @@ module "gwlbe_endpoint" {

name = "${var.name_prefix}${each.value.name}"
gwlb_service_name = module.gwlb[each.value.gwlb].endpoint_service.service_name
vpc_id = module.subnet_sets["${each.value.vpc}-${each.value.subnet_group}"].vpc_id
subnets = module.subnet_sets["${each.value.vpc}-${each.value.subnet_group}"].subnets
vpc_id = module.vpc[each.value.vpc].id
subnets = { for k, v in module.vpc[each.value.vpc].subnets : v.az => v if v.subnet_group == each.value.subnet_group }

act_as_next_hop_for = each.value.act_as_next_hop ? {
"from-igw-to-lb" = {
route_table_id = module.vpc[each.value.vpc].internet_gateway_route_table.id
to_subnets = module.subnet_sets["${each.value.from_igw_to_vpc}-${each.value.from_igw_to_subnet_group}"].subnets
to_subnets = { for k, v in module.vpc[each.value.from_igw_to_vpc].subnets : v.az => v if v.subnet_group == each.value.from_igw_to_subnet_group }
}
# The routes in this section are special in that they are on the "edge", that is they are part of an IGW route table,
# and AWS allows their destinations to only be:
Expand Down Expand Up @@ -336,7 +280,7 @@ module "vmseries" {
device_index = v.device_index
security_group_ids = try([module.vpc[each.value.common.vpc].security_group_ids[v.security_group]], [])
source_dest_check = try(v.source_dest_check, false)
subnet_id = module.subnet_sets["${v.vpc}-${v.subnet_group}"].subnets[each.value.az].id
subnet_id = module.vpc[v.vpc].subnets["${v.subnet_group}${each.value.az}"].id
create_public_ip = try(v.create_public_ip, false)
}
}
Expand All @@ -345,7 +289,7 @@ module "vmseries" {

iam_instance_profile = aws_iam_instance_profile.vm_series_iam_instance_profile.name
ssh_key_name = var.ssh_key_name
tags = var.global_tags
tags = var.tags
}

### Public ALB and NLB used in centralized model ###
Expand All @@ -356,13 +300,13 @@ module "public_alb" {
for_each = { for k, v in var.vmseries : k => v }

lb_name = "${var.name_prefix}${each.value.application_lb.name}"
subnets = { for k, v in module.subnet_sets["${each.value.vpc}-${each.value.application_lb.subnet_group}"].subnets : k => { id = v.id } }
subnets = { for k, v in module.vpc[each.value.vpc].subnets : k => { id = v.id } if v.subnet_group == each.value.application_lb.subnet_group }
vpc_id = module.vpc[each.value.vpc].id
security_groups = [module.vpc[each.value.vpc].security_group_ids[each.value.application_lb.security_group]]
rules = each.value.application_lb.rules
targets = { for vmseries in local.vmseries_instances : "${vmseries.group}-${vmseries.instance}" => module.vmseries["${vmseries.group}-${vmseries.instance}"].interfaces["public"].private_ip }

tags = var.global_tags
tags = var.tags
}

module "public_nlb" {
Expand All @@ -372,7 +316,7 @@ module "public_nlb" {

name = "${var.name_prefix}${each.value.network_lb.name}"
internal_lb = false
subnets = { for k, v in module.subnet_sets["${each.value.vpc}-${each.value.network_lb.subnet_group}"].subnets : k => { id = v.id } }
subnets = { for k, v in module.vpc[each.value.vpc].subnets : k => { id = v.id } if v.subnet_group == each.value.network_lb.subnet_group }
vpc_id = module.vpc[each.value.vpc].id

balance_rules = { for k, v in each.value.network_lb.rules : k => {
Expand All @@ -384,7 +328,7 @@ module "public_nlb" {
targets = { for vmseries in local.vmseries_instances : "${vmseries.group}-${vmseries.instance}" => module.vmseries["${vmseries.group}-${vmseries.instance}"].interfaces["public"].private_ip }
} }

tags = var.global_tags
tags = var.tags
}

### SPOKE VM INSTANCES ####
Expand Down Expand Up @@ -446,9 +390,9 @@ resource "aws_instance" "spoke_vms" {
ami = data.aws_ami.this.id
instance_type = each.value.type
key_name = var.ssh_key_name
subnet_id = module.subnet_sets["${each.value.vpc}-${each.value.subnet_group}"].subnets[each.value.az].id
subnet_id = module.vpc[each.value.vpc].subnets["${each.value.subnet_group}${each.value.az}"].id
vpc_security_group_ids = [module.vpc[each.value.vpc].security_group_ids[each.value.security_group]]
tags = merge({ Name = "${var.name_prefix}${each.key}" }, var.global_tags)
tags = merge({ Name = "${var.name_prefix}${each.key}" }, var.tags)
iam_instance_profile = aws_iam_instance_profile.spoke_vm_iam_instance_profile.name

root_block_device {
Expand Down Expand Up @@ -485,8 +429,8 @@ module "app_lb" {

name = "${var.name_prefix}${each.key}"
internal_lb = true
subnets = { for k, v in module.subnet_sets["${each.value.vpc}-${each.value.subnet_group}"].subnets : k => { id = v.id } }
vpc_id = module.subnet_sets["${each.value.vpc}-${each.value.subnet_group}"].vpc_id
subnets = { for k, v in module.vpc[each.value.vpc].subnets : k => { id = v.id } if v.subnet_group == each.value.subnet_group }
vpc_id = module.vpc[each.value.vpc].id

balance_rules = {
"SSH-traffic" = {
Expand All @@ -512,5 +456,5 @@ module "app_lb" {
}
}

tags = var.global_tags
tags = var.tags
}
61 changes: 42 additions & 19 deletions examples/centralized_design/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/PaloAltoNetworks/terraform-modules-swfw-tests-skeleton/pkg/testskeleton"
"github.com/gruntwork-io/terratest/modules/logger"
"github.com/gruntwork-io/terratest/modules/terraform"
"gotest.tools/v3/assert"
)

func CreateTerraformOptions(t *testing.T) *terraform.Options {
Expand All @@ -29,33 +30,55 @@ func CreateTerraformOptions(t *testing.T) *terraform.Options {
return terraformOptions
}

func checkIfTerraformVersionIsSupported(t *testing.T) bool {
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: ".",
Logger: logger.Discard,
Lock: true,
})
_, err := terraform.InitE(t, terraformOptions)
if err != nil {
assert.ErrorContains(t, err, "Unsupported Terraform Core version")
return false
}
return true
}

func TestValidate(t *testing.T) {
testskeleton.ValidateCode(t, nil)
if checkIfTerraformVersionIsSupported(t) {
testskeleton.ValidateCode(t, nil)
}
}

func TestPlan(t *testing.T) {
// define options for Terraform
terraformOptions := CreateTerraformOptions(t)
// prepare list of items to check
assertList := []testskeleton.AssertExpression{}
// plan test infrastructure and verify outputs
testskeleton.PlanInfraCheckErrors(t, terraformOptions, assertList, "No errors are expected")
if checkIfTerraformVersionIsSupported(t) {
// define options for Terraform
terraformOptions := CreateTerraformOptions(t)
// prepare list of items to check
assertList := []testskeleton.AssertExpression{}
// plan test infrastructure and verify outputs
testskeleton.PlanInfraCheckErrors(t, terraformOptions, assertList, "No errors are expected")
}
}

func TestApply(t *testing.T) {
// define options for Terraform
terraformOptions := CreateTerraformOptions(t)
// prepare list of items to check
assertList := []testskeleton.AssertExpression{}
// deploy test infrastructure and verify outputs and check if there are no planned changes after deployment
testskeleton.DeployInfraCheckOutputs(t, terraformOptions, assertList)
if checkIfTerraformVersionIsSupported(t) {
// define options for Terraform
terraformOptions := CreateTerraformOptions(t)
// prepare list of items to check
assertList := []testskeleton.AssertExpression{}
// deploy test infrastructure and verify outputs and check if there are no planned changes after deployment
testskeleton.DeployInfraCheckOutputs(t, terraformOptions, assertList)
}
}

func TestIdempotence(t *testing.T) {
// define options for Terraform
terraformOptions := CreateTerraformOptions(t)
// prepare list of items to check
assertList := []testskeleton.AssertExpression{}
// deploy test infrastructure and verify outputs and check if there are no planned changes after deployment
testskeleton.DeployInfraCheckOutputsVerifyChanges(t, terraformOptions, assertList)
if checkIfTerraformVersionIsSupported(t) {
// define options for Terraform
terraformOptions := CreateTerraformOptions(t)
// prepare list of items to check
assertList := []testskeleton.AssertExpression{}
// deploy test infrastructure and verify outputs and check if there are no planned changes after deployment
testskeleton.DeployInfraCheckOutputsVerifyChanges(t, terraformOptions, assertList)
}
}
Loading

0 comments on commit 1c4112b

Please sign in to comment.