The following module provides a AWS recommended pattern for sharing private endpoint services across multiple VPCs, interconnected via a transit gateway. The intent is to retain as much of the traffic directed to AWS services, private and off the internet. Used in combination with the terraform-aws-connectivity.
- A shared vpc called
var.name
is created and attached to the transit gateway. Note, this module does not perform any actions on the transit gateway, it is assumed the correct settings to enable connectivity between thevar.name
vpc and the spokes is in place. - Inside the shared vpc the private endpoints are created, one for each service defined in
var.endpoints
. The default security groups permits all https traffic from10.0.0.0/8
to ingress. - Optionally, depending on the configuration of the module, a outbound resolver is created. The outbound resolver is used to resolve the AWS services, against the default VPC resolver (VPC+2 ip)
- Route53 resolver rules are created for each of the shared private endpoints, allowing the consumer to pick and choose which endpoints they want to resolve to the shared vpc.
- The endpoints are shared using AWS RAM to the all the principals defined in the
var.sharing.principals
list e.g. a collection of organizational units. - The spoke vpc's are responsible for associating the resolver rules with their vpc.
- These rules intercept the DNS queries and route them to the shared vpc resolvers, returning the private endpoint ip address located within them.
- Traffic from the spoke to the endpoints once resolved, is routed via the transit gateway.
## Provision the endpoints and resolvers
module "endpoints" {
source = "../.."
name = "endpoints"
tags = var.tags
endpoints = {
"s3" = {
service = "s3"
},
"ec2" = {
service = "ec2"
},
"ec2messages" = {
service = "ec2messages"
},
"ssm" = {
service = "ssm"
},
"ssmmessages" = {
service = "ssmmessages"
},
"logs" = {
service = "logs"
},
"kms" = {
service = "kms"
},
"secretsmanager" = {
service = "secretsmanager"
}
}
sharing = {
principals = values(var.ram_principals)
}
resolvers = {
outbound = {
create = true
ip_address_offset = 12
}
}
network = {
# Name of the network to create
name = "endpoints"
# Number of availability zones to create subnets in
private_netmask = 24
# The transit gateway to connect
transit_gateway_id = var.transit_gateway_id
# The cider range to use for the VPC
vpc_cidr = "10.20.0.0/21"
}
}
In order to reuse and existing network (vpc), we need to pass the vpc_id and the subnets ids where the outbound resolver will be provisioned (assuming you are not reusing an existing resolver as well).
## Provision the endpoints and resolvers
module "endpoints" {
source = "../.."
name = "endpoints"
tags = var.tags
endpoints = {
"ec2" = {
service = "ec2"
},
"ec2messages" = {
service = "ec2messages"
},
"ssm" = {
service = "ssm"
},
"ssmmessages" = {
service = "ssmmessages"
},
}
sharing = {
principals = values(var.ram_principals)
}
resolvers = {
outbound = {
create = true
ip_address_offset = 10
}
}
network = {
## The vpc_cidr of the network we are reusing
vpc_cidr = <VPC_CIDR>
## Reuse the network we created above
vpc_id = <VPC_ID>
## Reuse the private subnets we created above i.e subnet-id => cidr
private_subnet_cidrs_by_id = module.network.private_subnet_cidrs_by_id
## Do not create a new network
create = false
}
}
The terraform-docs
utility is used to generate this README. Follow the below steps to update:
- Make changes to the
.terraform-docs.yml
file - Fetch the
terraform-docs
binary (https://terraform-docs.io/user-guide/installation/) - Run
terraform-docs markdown table --output-file ${PWD}/README.md --output-mode inject .
Name | Version |
---|---|
terraform | >= 1.0.7 |
aws | >= 5.0.0 |
Name | Version |
---|---|
aws | >= 5.0.0 |
Name | Source | Version |
---|---|---|
dns_security_group | terraform-aws-modules/security-group/aws | 5.2.0 |
ram_share | ./modules/ram_share | n/a |
vpc | appvia/network/aws | 0.3.1 |
Name | Type |
---|---|
aws_ram_resource_association.endpoints | resource |
aws_ram_resource_share.endpoints | resource |
aws_route53_resolver_endpoint.outbound | resource |
aws_route53_resolver_rule.endpoints | resource |
aws_route53_resolver_rule.endpoints_single | resource |
aws_security_group.this | resource |
aws_vpc_endpoint.this | resource |
aws_vpc_security_group_egress_rule.allow_https_egress | resource |
aws_vpc_security_group_ingress_rule.allow_https_ingress | resource |
aws_route53_resolver_endpoint.outbound | data source |
Name | Description | Type | Default | Required |
---|---|---|---|---|
name | The name of the environment | string |
n/a | yes |
network | The network to use for the endpoints and optinal resolvers | object({ |
n/a | yes |
region | The region to deploy the resources | string |
n/a | yes |
resolvers | The resolvers to provision | object({ |
n/a | yes |
tags | The tags to apply to the resources | map(string) |
n/a | yes |
endpoints | The private endpoints to provision within the shared vpc | map(object({ |
{ |
no |
sharing | The configuration for sharing the resolvers to other accounts | object({ |
{ |
no |
Name | Description |
---|---|
endpoints | Array containing the full resource object and attributes for all endpoints created |
outbound_resolver_endpoint_id | The id of the outbound resolver if we created one |
outbound_resolver_ip_addresses | The ip addresses of the outbound resolver if we created one |
private_subnet_attributes_by_az | The attributes of the private subnets |
resolver_security_group_id | The id of the security group we created for the endpoints if we created one |
rt_attributes_by_type_by_az | The attributes of the route tables |
transit_gateway_attachment_id | The id of the transit gateway we used to provision the endpoints |
vpc_attributes | The attributes of the vpc we created |
vpc_id | The id of the vpc we used to provision the endpoints |