Creating a Core Network Foundation in AWS with SSH, VPN & NAT access

For both test and build purposes I often find myself reusing parts of past CloudFormation templates. Over time I’ve found that the foundation of the templates like VPC, subnets, routing tables etc remain roughly the same. I have also found that the AWS VPN solution often isn’t suitable because of e.g. NAT, lack of port forwaring, lack of “hardware VPN”, expertise etc.

I have therefore started to standardise the Core stack in a single – and simple – template; and rely on Cross Reference Stacks to build in layers/tiers.

The stack provides for:

  • A VPC
  • A 3-tier set of subnets (public, private and database) with requisite routing and Internet Gateway
  • 1 EC2 instance, which combines NAT (outbound traffic for private tier), bastion (SSH) and finally VPN (OpenVPN)

I have fully automated the OpenVPN set-up and all that’s required for VPN connectivity is an OpenVPN client and to generate the client configuration from the EC2 instance via a very simple script that takes as input an arbitrary client name.

The result and instructions can be found in the Virtuability cf-templates github repository.

Note that:

  • if the NAT EC2 instance is terminated then a new OpenVPN configuration is generated again at start-up and client configuration will need to be fetched again. There’s currently no provision for persisting OpenVPN CA, keys and certificates e.g. via an S3 bucket (that may happen in a future version)
  • The risk profile of running NAT, bastion and SSH server within the same EC2 instance may not suit your security needs in which case you should split out the functions to separate instances and into different security groups
    * The bastion/NAT/SSH server should not be exposed to the Internet at large (i.e. 0.0.0.0/0, which is the default) but be tied down to select public IP addresses
  • it is vitally important that the OpenVPN client parameters reflect those of the OpenVPN server. For instance, enabling compression (comp-lzo) on the server and failing to do so on the client will result in the ability for the client to connect to the server but no traffic will pass through