Open stumins opened 8 months ago
I would also appreciate this very much.
@dennisneuman i added your request to the existing feature request!
I have been able to get this working with an account customization.
I have a vpc module with this as the contents of main.tf
filter {
name = "locale"
values = [var.region]
}
filter {
name = "description"
values = [var.ipam_description]
}
filter {
name = "address-family"
values = ["ipv4"]
}
filter {
name = "ipam-scope-type"
values = ["private"]
}
}
resource "aws_vpc" "this" {
ipv4_ipam_pool_id = data.aws_vpc_ipam_pool.this.id
ipv4_netmask_length = var.ipv4_netmask_length
assign_generated_ipv6_cidr_block = var.enable_ipv6 ? true : null
ipv6_cidr_block = var.ipv6_cidr
ipv6_ipam_pool_id = var.ipv6_ipam_pool_id
ipv6_netmask_length = var.ipv6_netmask_length
ipv6_cidr_block_network_border_group = var.ipv6_cidr_block_network_border_group
instance_tenancy = var.instance_tenancy
enable_dns_hostnames = var.enable_dns_hostnames
enable_dns_support = var.enable_dns_support
enable_network_address_usage_metrics = var.enable_network_address_usage_metrics
tags = merge(
var.tags,
var.vpc_tags,
{ "Name" = var.name }
)
lifecycle {
ignore_changes = [
tags,
]
}
}
This how I call the module.
module "vpc" {
source = "./modules/vpc"
name = var.vpc_name
ipam_description = var.vpc_ipam_type
region = var.vpc_region
ipv4_netmask_length = var.vpc_netmask_length
vpc_tags = merge(
local.vpc_tags,
{
"Name" = var.vpc_name,
}
)
tags = local.vpc_tags
providers = {
aws = aws.custom
}
}
@mikeplem Which customizations repository did you put the VPC module and the call to it? Our IPAM is shared with the AFT account. Can you please expand on the solution?
I'm putting the VPC code in aft-account-provisioning-customizations repository but it's not able to get the IPAM pool id because the customizations are run from the new account. I also need to pass tags and other variables to the VPC module but not sure how to configure these properly. We're using Terraform Cloud on the backend.
@shahbhavik01 I put the VPC module in the aft-account-customizations
directory.
Out IPAM is configured in a separate Network AWS account and shared in our AWS Organization via RAM.
I took the Terraform AWS registry module as the basis and split up the VPC creation from the VPC configuration. This took some customization to get working.
This is what my vpc
module looks like.
data "aws_vpc_ipam_pool" "this" {
filter {
name = "locale"
values = [var.region]
}
filter {
name = "description"
values = [var.ipam_description]
}
filter {
name = "address-family"
values = ["ipv4"]
}
filter {
name = "ipam-scope-type"
values = ["private"]
}
}
resource "aws_vpc" "this" {
ipv4_ipam_pool_id = data.aws_vpc_ipam_pool.this.id
ipv4_netmask_length = var.ipv4_netmask_length
assign_generated_ipv6_cidr_block = var.enable_ipv6 ? true : null
ipv6_cidr_block = var.ipv6_cidr
ipv6_ipam_pool_id = var.ipv6_ipam_pool_id
ipv6_netmask_length = var.ipv6_netmask_length
ipv6_cidr_block_network_border_group = var.ipv6_cidr_block_network_border_group
instance_tenancy = var.instance_tenancy
enable_dns_hostnames = var.enable_dns_hostnames
enable_dns_support = var.enable_dns_support
enable_network_address_usage_metrics = var.enable_network_address_usage_metrics
tags = var.tags
lifecycle {
ignore_changes = [
tags,
]
}
}
The vars.tf
in the vpc module is as follows:
variable "region" {
description = "aws region"
type = string
default = ""
}
variable "ipam_description" {
description = "ipam description field value"
type = string
default = ""
}
variable "ipv4_netmask_length" {
description = "netmask_length - defaults to a /24"
type = number
default = 24
}
# - taken from AWS VPC module
# https://github.com/terraform-aws-modules/terraform-aws-vpc/blob/master/variables.tf
variable "name" {
description = "Name to be used on all the resources as identifier"
type = string
default = ""
}
variable "enable_ipv6" {
description = "Requests an Amazon-provided IPv6 CIDR block with a /56 prefix length for the VPC. You cannot specify the range of IP addresses, or the size of the CIDR block"
type = bool
default = false
}
variable "ipv6_cidr" {
description = "(Optional) IPv6 CIDR block to request from an IPAM Pool. Can be set explicitly or derived from IPAM using `ipv6_netmask_length`"
type = string
default = null
}
variable "ipv6_ipam_pool_id" {
description = "(Optional) IPAM Pool ID for a IPv6 pool. Conflicts with `assign_generated_ipv6_cidr_block`"
type = string
default = null
}
variable "ipv6_netmask_length" {
description = "(Optional) Netmask length to request from IPAM Pool. Conflicts with `ipv6_cidr_block`. This can be omitted if IPAM pool as a `allocation_default_netmask_length` set. Valid values: `56`"
type = number
default = null
}
variable "ipv6_cidr_block_network_border_group" {
description = "By default when an IPv6 CIDR is assigned to a VPC a default ipv6_cidr_block_network_border_group will be set to the region of the VPC. This can be changed to restrict advertisement of public addresses to specific Network Border Groups such as LocalZones"
type = string
default = null
}
variable "instance_tenancy" {
description = "A tenancy option for instances launched into the VPC"
type = string
default = "default"
}
variable "enable_dns_hostnames" {
description = "Should be true to enable DNS hostnames in the VPC"
type = bool
default = true
}
variable "enable_dns_support" {
description = "Should be true to enable DNS support in the VPC"
type = bool
default = true
}
variable "enable_network_address_usage_metrics" {
description = "Determines whether network address usage metrics are enabled for the VPC"
type = bool
default = null
}
variable "tags" {
description = "A map of tags to add to all resources"
type = map(string)
default = {}
}
The outputs.tf
in the vpc module is
################################################################################
# VPC
################################################################################
output "vpc_id" {
description = "The ID of the VPC"
value = try(aws_vpc.this.id, null)
}
output "vpc_arn" {
description = "The ARN of the VPC"
value = try(aws_vpc.this.arn, null)
}
output "vpc_cidr_block" {
description = "The CIDR block of the VPC"
value = try(aws_vpc.this.cidr_block, null)
}
output "default_security_group_id" {
description = "The ID of the security group created by default on VPC creation"
value = try(aws_vpc.this.default_security_group_id, null)
}
output "default_network_acl_id" {
description = "The ID of the default network ACL"
value = try(aws_vpc.this.default_network_acl_id, null)
}
output "default_route_table_id" {
description = "The ID of the default route table"
value = try(aws_vpc.this.default_route_table_id, null)
}
output "vpc_instance_tenancy" {
description = "Tenancy of instances spin up within VPC"
value = try(aws_vpc.this.instance_tenancy, null)
}
output "vpc_enable_dns_support" {
description = "Whether or not the VPC has DNS support"
value = try(aws_vpc.this.enable_dns_support, null)
}
output "vpc_enable_dns_hostnames" {
description = "Whether or not the VPC has DNS hostname support"
value = try(aws_vpc.this.enable_dns_hostnames, null)
}
output "vpc_main_route_table_id" {
description = "The ID of the main route table associated with this VPC"
value = try(aws_vpc.this.main_route_table_id, null)
}
output "vpc_ipv6_association_id" {
description = "The association ID for the IPv6 CIDR block"
value = try(aws_vpc.this.ipv6_association_id, null)
}
output "vpc_ipv6_cidr_block" {
description = "The IPv6 CIDR block"
value = try(aws_vpc.this.ipv6_cidr_block, null)
}
output "vpc_owner_id" {
description = "The ID of the AWS account that owns the VPC"
value = try(aws_vpc.this.owner_id, null)
}
Referring to my previous comment where I call aws.custom
as the provider, I have the following in the pre-api-helpers.sh
script. The value of VPC_REGION
is queried by pulling it from the account's SSM Parameter Store.
VPC_REGION=$(aws ssm get-parameter --query 'Parameter.Value' --output text --name "/aft/account-request/custom-fields/vpc_region)
The DEFAULT_PATH
and CUSTOMIZATION
are already in the environment variables so I do not have to provide them.
cat << EOF > "${DEFAULT_PATH}/${CUSTOMIZATION}/terraform/custom-provider.tf"
provider "aws" {
region = "${VPC_REGION}"
alias = "custom"
assume_role {
role_arn = "arn:aws:iam::${ACCOUNT_ID}:role/AWSAFTExecution"
}
default_tags {
tags = {
managed_by = "AFT"
ManagedBy = "Terraform"
GithubRepo = "https://github.com/bubblegroup/aft-account-customizations"
}
}
}
EOF
The value for VPC_REGION
comes from the custom_fields block in the aft-account-request
terraform.
custom_fields = {
vpc_name = "d999999"
vpc_ipam_type = "dedicated"
vpc_region = "us-west-1"
vpc_az_count = 2
use_tgw = "yes"
}
Another piece I also do is create a terraform.tfvars
file with the necessary variables that my Terraform needs. Since Terraform looks for terraform.tfvars
when it runs it will pick these up and use them automatically.
cat << EOF >> "${DEFAULT_PATH}/${CUSTOMIZATION}/terraform/terraform.tfvars"
vpc_name = "${VPC_NAME}"
vpc_ipam_type = "${IPAM_TYPE}"
vpc_region = "${VPC_REGION}"
vpc_az_count = ${VPC_AZ_COUNT}
EOF
@mikeplem Highly appreciated. Thank you so much. I was going around in circles.
Describe the outcome you'd like
I would like to use Amazon's IP Address Manager IPAM to manage VPC's in my Control Tower managed accounts.
Is your feature request related to a problem you are currently experiencing? If so, please describe.
AFT's current behavior is to create VPC's with the same default CIDR ranges.
Originally requested by @mbuotidem in https://github.com/aws-ia/terraform-aws-control_tower_account_factory/issues/152