Skip to content

appvia/terraform-aws-private-endpoints

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

83 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Appvia Banner

Terraform Registry Latest Release Slack Community Contributors

Github Actions

Terraform AWS Private Endpoints


AWS Private Endpoints

The diagram above is a high level representation of the module and the resources it creates; note in this design we DO NOT create an inbound resolver, as its not technically required

Description

Using 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.

How it works

  • 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 the var.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 from 10.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.

AWS References

Usage

## 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"
  }
}

Reuse Existing Network

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
  }
}

Update Documentation

The terraform-docs utility is used to generate this README. Follow the below steps to update:

  1. Make changes to the .terraform-docs.yml file
  2. Fetch the terraform-docs binary (https://terraform-docs.io/user-guide/installation/)
  3. Run terraform-docs markdown table --output-file ${PWD}/README.md --output-mode inject .

Providers

Name Version
aws >= 5.0.0

Inputs

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({
availability_zones = optional(number, 2)
# Indicates if we should create a new network or reuse an existing one
enable_default_route_table_association = optional(bool, true)
# Whether to associate the default route table
enable_default_route_table_propagation = optional(bool, true)
# Whether to propagate the default route table
enable_dynamodb_endpoint = optional(bool, false)
# Whether to enable the dynamodb endpoint
enable_route53_resolver_rules = optional(bool, false)
# Whether to enable the route53 resolver rules
enable_s3_endpoint = optional(bool, false)
# Whether to enable the s3 endpoint
ipam_pool_id = optional(string, null)
# The id of the ipam pool to use when creating the network
private_netmask = optional(number, 24)
# The subnet mask for private subnets, when creating the network i.e subnet-id => 10.90.0.0/24
private_subnet_cidr_by_id = optional(map(string), {})
# The ids of the private subnets to if we are reusing an existing network
transit_gateway_id = optional(string, null)
## The transit gateway id to use for the network
vpc_cidr = optional(string, "")
# The cidrws range to use for the VPC, when creating the network
vpc_dns_resolver = optional(string, null)
# The ip address to use for the vpc dns resolver
vpc_id = optional(string, "")
# The vpc id to use when reusing an existing network
vpc_netmask = optional(number, null)
# When using ipam this the netmask to use for the VPC
})
n/a yes
region The region to deploy the resources string 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({
# The route table ids to use for the endpoint, assuming a gateway endpoint
route_table_ids = optional(list(string), null)
# service_type of the endpoint i.e. Gateway, Interface
service_type = optional(string, "Interface")
# The security group ids to use for the endpoint, else create on the fly
security_group_ids = optional(list(string), null)
# The AWS service we are creating a endpoint for
service = string
# The IAM policy associated to the endpoint
policy = optional(string, null)
}))
{
"ec2": {
"service": "ec2"
},
"ec2messages": {
"service": "ec2messages"
},
"ssm": {
"service": "ssm"
},
"ssmmessages": {
"service": "ssmmessages"
}
}
no
resolver_rules The configuration for sharing the resolvers to other accounts
object({
principals = optional(list(string), [])
## The principals to share the resolvers with
share_prefix = optional(string, "resolvers")
# The preifx to use for the shared resolvers
})
{} no
resolvers The resolvers to provision
object({
outbound = object({
ip_address_offset = optional(number, 10)
# If creating the outbound resolver, the address offset to use i.e if 10.100.0.0/24, offset 10, ip address would be 10.100.0.10
protocols = optional(list(string), ["Do53", "DoH"])
# The protocols to use for the resolver
use_existing = optional(string, null)
# When not creating the resolver, this is the name of the resolver to use
})
# The configuration for the outbound resolver
})
null no

Outputs

Name Description
endpoints Array containing the full resource object and attributes for all endpoints created
hosted_zone A full list of the private hosted zones created
hosted_zone_map A map of the private hosted zones 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

About

Used to manage a shared private endpoints vpc

Topics

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

No packages published

Contributors 6