Top-to-bottom OpenVPN setup for Ubuntu/AWS using Terraform/Ansible
This project is a top-to-bottom OpenVPN setup for Ubuntu on AWS, using Terraform to create the EC2 resources and security groups, and Ansible to setup VPN users.
In terms of server configuration, the heavy lifting for this project is mostly courtesy of the excellent Stouts.openvpn ansible role. What this repository does on top of that is:
Valid named AWS profiles should already be setup in your ~/.aws/credentials
file. We’ll assume in the rest of this guide that the profile you want to use is called MY_PROFILE
.
You’ll also need local copies of terraform
, ansible
, and jq
. My (confirmed working) version info follows:
$ terraform --version
Terraform v0.9.11
$ ansible --version
ansible 2.3.2.0
$ jq --version
jq-1.5
Terraform builds infrastructure resources on clouds like AWS. It can be downloaded here or you could use docker. If you prefer docker, just set an appropriate bash alias before using the Makefile.
Ansible configures resources on clouds with certain system packages, files, etc. Installation is described in detail here, but for platforms that already have a python stack you can probably just run pip install -r requirements.txt
in this directory.
Jq is a sed-like tool for parsing JSON from the command line. On OSX it can be installed with brew install jq
Edit the Makefile directly to change the primary VPN user’s default username/password. Edit the ansible file openvpn.yml to add additional VPN users.
Afterwards, run make vpn
and answer when it asks for the named AWS profile to use. When this finishes an OpenVPN server will be setup and ready to go, so you just need to configure a client.
As a VPN client, I recommend tunnelblick, where setup is especially easy. When step 2 above finished, you are left with several new files in the working directory which can be used to configure the client. Assuming you didn’t change the VPN_NAME
, one of these files is default.ovpn
. Simply drag the new default.ovpn
file onto the tunnelblick icon in the menubar and connect with the user/password you set in the Makefile. Done! You can verify your configuration by visiting a place like http://www.whatsmyip.org/.
This section is just a walk through of the individual steps you can run that make vpn
would do magically for you. Follow this instead of the quickstart above if you want to understand more about what’s going on.
Generate a new ssh-key for EC2/terraform:
$ make keypair
Set an environment variable that terraform will use for your AWS profile, and run terraform plan
via the Makefile. Inspect the plan and make sure it’s what you expected.
$ TF_VAR_aws_profile=MY_PROFILE make plan
Set an environment variable that terraform will use for your AWS profile, and run terraform apply
via the Makefile. This will create an EC2 server on AWS, together with the security groups and rules you’ll need to use OpenVPN.
$ TF_VAR_aws_profile=MY_PROFILE make apply
Edit the Makefile directly to change the primary VPN user’s default username/password. Edit the ansible file openvpn.yml to add additional VPN users. You can safely rerun the ansible provisioner as many times as you like to add/edit/remove VPN users (see the next step).
To reprovision the VPN server, use the command below. (The IP address of the host is determined automatically for you with the results of terraform output
)
$ make reprovision
If you need to connect to the OpenVPN server itself, there’s a make target for that which will use the correct ssh user/keys. (The IP address of the host is determined automatically for you with the results of terraform output
)
$ make ssh
If you want to tear things down again, you can use make plan-destroy
to show the plan, and make destroy
to actually clean up.
A Makefile is provided in this project to call Terraform and Ansible consistently, and with consistent environment variables. Not everyone who reads/writes terraform can read/write Ansible and vice versa, so as a compromise I’m mostly trying to use the Makefile to get information into both systems rather than using Ansible to drive Terraform or Terraform to drive Ansible.
I’ve also chosen to do a “two stage” setup with resource creation/provision handled separately, rather than using ansible via terraform’s local-exec provisioner. Reprovisioning in terraform is awkward at best, black magic at worst. See this discussion for some workarounds if this is intolerable for your use-case.
Terraform resources are also arranged as modules, partly just to demonstrate modules. Nevertheless this might be useful if you want to, for instance, eliminate bastions for multiple VPCs by instantiating multiple OpenVPN servers. Note that individual OpenVPN servers can also support multiple VPNs, but we use one by default.
There are a variety of ways to override things at the Terraform layer (i.e. AWS region etc) which can be potentially confusing. There’s the vars.tf file where you can modify things directly by changing/adding defaults. There’s also the TF_VAR_name trick, if you want to set values using environment variables. There’s also the openvpn
terraform module instantiation in main.tf which allows for overrides.
For overriding things at the OpenVPN configuration layer, things are simpler. Go have a close reading of the documentation for the Stouts.openvpn role, which does almost all the real work here anyway. Consider adding variables that it understands/supports. Otherwise, you can always just pile new Ansible into the openvpn.yml file to override cert files with your own uploads, etc.
Are welcome.