Skip to content

Latest commit

 

History

History
301 lines (241 loc) · 8.88 KB

.header.md

File metadata and controls

301 lines (241 loc) · 8.88 KB

AWS VPC Module

This module can be used to deploy a pragmatic VPC with various subnets types in # AZs. Common deployment examples can be found in examples/.

Note: For information regarding the 4.0 upgrade see our upgrade guide.

Usage

The example below builds a dual-stack VPC with public and private subnets in 3 AZs. Each subnet calculates an IPv4 CIDR based on the netmask argument passed, and an IPv6 CIDR with a /64 prefix length. The public subnets build NAT gateways in each AZ but optionally can be switched to single_az. An Egress-only Internet gateway is created by using the variable vpc_egress_only_internet_gateway.

module "vpc" {
  source   = "aws-ia/vpc/aws"
  version = ">= 4.2.0"

  name                                 = "multi-az-vpc"
  cidr_block                           = "10.0.0.0/16"
  vpc_assign_generated_ipv6_cidr_block = true
  vpc_egress_only_internet_gateway     = true
  az_count                             = 3

  subnets = {
    # Dual-stack subnet
    public = {
      name_prefix               = "my_public" # omit to prefix with "public"
      netmask                   = 24
      assign_ipv6_cidr          = true
      nat_gateway_configuration = "all_azs" # options: "single_az", "none"
    }
    # IPv4 only subnet
    private = {
      # omitting name_prefix defaults value to "private"
      # name_prefix  = "private_with_egress"
      netmask      = 24
      connect_to_public_natgw = true
    }
    # IPv6-only subnet
    private_ipv6 = {
      ipv6_native      = true
      assign_ipv6_cidr = true
      connect_to_eigw  = true
    }
  }

  vpc_flow_logs = {
    log_destination_type = "cloud-watch-logs"
    retention_in_days    = 180
  }
}

Reserved Subnet Key Names

There are 3 reserved keys for subnet key names in var.subnets corresponding to types "public", "transit_gateway", and "core_network" (an AWS Cloud WAN feature). Other custom subnet key names are valid are and those subnets will be private subnets.

subnets = {
  public = {
    name_prefix               = "my-public" # omit to prefix with "public"
    netmask                   = 24
    nat_gateway_configuration = "all_azs" # options: "single_az", "none"
  }

  # naming private is not required, can use any key
  private = {
    # omitting name_prefix defaults value to "private"
    # name_prefix  = "private"
    netmask      = 24
    connect_to_public_natgw = true
  }

  # can be any valid key name
  privatetwo = {
    # omitting name_prefix defaults value to "privatetwo"
    # name_prefix  = "private"
    netmask      = 24
  }
transit_gateway_id = <>
transit_gateway_routes = {
  private = "0.0.0.0/0"
  vpce    = "pl-123"
}
transit_gateway_ipv6_routes = {
  private = "::/0"
}

subnets = {
  private = {
    netmask          = 24
    assign_ipv6_cidr = true
  }
  vpce = { netmask = 24}

  transit_gateway = {
    netmask                                         = 28
    assign_ipv6_cidr                                = true
    transit_gateway_default_route_table_association = true
    transit_gateway_default_route_table_propagation = true
    transit_gateway_appliance_mode_support          = "enable"
    transit_gateway_dns_support                     = "disable"

    tags = {
      subnet_type = "tgw"
    }
}
core_network = {
  id  = <>
  arn = <>
}
core_network_routes = {
  workload = "pl-123"
}
core_network_ipv6_routes = {
  workload = "::/0"
}

subnets = {
  workload = {
    name_prefix      = "workload-private"
    netmask          = 24
    assign_ipv6_cidr = true
  }

  core_network = {
    netmask                = 28
    assign_ipv6_cidr       = true
    appliance_mode_support = false
    require_acceptance     = true
    accept_attachment      = true

    tags = {
      env = "prod"
    }
}

Updating a VPC with new or removed subnets

If using netmask or assign_ipv6_cidr to calculate subnets and you wish to either add or remove subnets (ex: adding / removing an AZ), you may have to change from using netmask / assign_ipv6_cidr for some subnets and set to explicit instead. Private subnets are always calculated before public.

When changing to explicit cidrs, subnets are always ordered by AZ. 0 -> a, 1 -> b, etc.

Example: Changing from 2 azs to 3

Before:

cidr_block                           = "10.0.0.0/16"
vpc_assign_generated_ipv6_cidr_block = true
az_count                             = 2

subnets = {
  public = {
    netmask          = 24
    assign_ipv6_cidr = true
  }

  private = {
   netmask          = 24
   assign_ipv6_cidr = true
  }
}

After:

cidr_block                           = "10.0.0.0/16"
vpc_assign_generated_ipv6_cidr_block = true
az_count = 3

subnets = {
  public = {
    cidrs      = ["10.0.0.0/24", "10.0.1.0/24", "10.0.4.0/24"]
    ipv6_cidrs = ["2a05:d01c:bc3:b200::/64", "2a05:d01c:bc3:b201::/64", "2a05:d01c:bc3:b204::/64"]
  }

  private = {
    cidrs      = ["10.0.2.0/24", "10.0.3.0/24", "10.0.5.0/24"]
    ipv6_cidrs = ["2a05:d01c:bc3:b202::/64", "2a05:d01c:bc3:b203::/64", "2a05:d01c:bc3:b205::/64"]
  }
}

The above example will cause only creating 2 new subnets in az c of the region being used.

Output usage examples

The outputs in this module attempt to align to a methodology of outputting resource attributes in a reasonable collection. The benefit of this is that, most likely, attributes you want access to are already present without having to create new output {} for each possible attribute. The [potential] downside is that you will have to extract it yourself using HCL logic. Below are some common examples:

For more examples and explanation see [output docs]((https://github.com/aws-ia/terraform-aws-vpc/blob/main/docs/how-to-use-module-outputs.md)

Extracting subnet IDs for private subnets

Example Configuration:

module "vpc" {
  source  = "aws-ia/vpc/aws"
  version = ">= 4.2.0"

  name       = "multi-az-vpc"
  cidr_block = "10.0.0.0/20"
  az_count   = 3

  subnets = {
    private = { netmask = 24 }
  }
}

Extracting subnet_ids to a list (using terraform console for example output):

> [ for _, value in module.vpc.private_subnet_attributes_by_az: value.id]
[
  "subnet-04a86315c4839b519",
  "subnet-02a7249c8652a7136",
  "subnet-09af79b5329b3681f",
]

Alternatively, since these are maps, you can use key in another resource for_each loop. The benefit here is that your dependent resource will have keys that match the AZ the subnet is in:

resource "aws_route53recoveryreadiness_cell" "cell_per_az" {
  for_each = module.vpc.private_subnet_attributes_by_az

  cell_name = "${each.key}-failover-cell-for-subnet-${each.value.id}"
}
...

Terraform Plan:

# aws_route53recoveryreadiness_cell.cell_per_az["us-east-1a"] will be created
+ resource "aws_route53recoveryreadiness_cell" "cell_per_az" {
    + cell_name               = "us-east-1a-failover-cell-for-subnet-subnet-070696086c5864da1"
    ...
  }

# aws_route53recoveryreadiness_cell.cell_per_az["us-east-1b"] will be created
...

Common Errors and their Fixes

Error creating routes to Core Network

Error:

error creating Route in Route Table (rtb-xxx) with destination (YYY): InvalidCoreNetworkArn.NotFound: The core network arn 'arn:aws:networkmanager::XXXX:core-network/core-network-YYYYY' does not exist.

This happens when the Core Network's VPC attachment requires acceptance, so it's not possible to create the routes in the VPC until the attachment is accepted. Check the following:

  • If the VPC attachment requires acceptance and you want the module to automatically accept it, configure require_acceptance and accept_attachment to true.
subnets = {
  core_network = {
    netmask            = 28
    assign_ipv6_cidr   = true
    require_acceptance = true
    accept_attachment  = true
  }
}
  • If the VPC attachment requires acceptance but you want to accept it outside the module, first configure require_acceptance to true and accept_attachment to false.
subnets = {
  core_network = {
    netmask            = 28
    assign_ipv6_cidr   = true
    require_acceptance = true
    accept_attachment  = true
  }
}

After you apply and the attachment is accepted (outside the module), change the subnet configuration with require_acceptance to false.

subnets = {
  core_network = {
    netmask            = 28
    assign_ipv6_cidr   = true
    require_acceptance = false
  }
}
  • Alternatively, you can also not configure any subnet route (var.core_network_routes) to the Core Network until the attachment gets accepted.

Contributing

Please see our developer documentation for guidance on contributing to this module.