AWS Terraform and Wireguard - part one

In my last post I worked with AWS CLI and Cloudformation to create a simple VPC and find a configuration drift.

In this post I'll show you how to build a VPC in AWS with all the elements necessary to lab Wireguard. We'll use Terraform to automate the creation of the VPC.

Prerequisites

To complete all the labs in this post you need an AWS account, an EC2 key pair, basic Linux skills, and AWS CLI optionally.

The plan

Terraform is an IaC tool that supports AWS and many other providers. For some uses it can be an alternative to AWS Cloudformation.

Wireguard is a new-ish VPN software that will be merged in the Linux kernel soon. It is widely appreciated for its peformances and easy to configure.

Terraform

The first step of our journey is the installation of Terraform.

We can use WSL on my Windows 10 or any flavour of Linux.

Installation is straightforward

wget https://releases.hashicorp.com/terraform/0.12.24/terraform_0.12.24_linux_amd64.zip
unzip terraform_0.12.24_linux_amd64.zip
mkdir ~/bin
mv terraform ~/bin

Avoid using snapcraft to install Terraform, the release is v0.11.11, we'll use v0.12 that has a different syntax.

We can verify the installation running

terraform version

Expected output

# Terraform v0.12.24

Creating a VPC with Terraform

The creation of the VPC and all the necessary elements requires some AWS skills. I will not discuss in detail the details of how AWS VPC works here. For anyone interested the topics are included in the AWS Certified Advanced Networking - Specialty training.

We start creating a Terraform configuration named awswire.tf. This file will contain the definition of the AWS infrastructure.

Another file named variables.tf will provide all the variables and their values.

Warning

I advise to keep code and variables in separate files for reusability, readability and to avoid sharing private information/credentials by mistake.

The file awswire.tf will include

  • a VPC with its CIDR
  • an EC2 instance for the Wireguard server
  • an EC2 instance for the internal client
  • a public subnet for the Wireguard server
  • a private subnet for the internal client
  • an internet gateway (IGW) to provide Internet access to the server
  • a default route for the public subnet pointing to the IGW
  • a custom route table for the client: the client will use the Wireguard server to reach the VPN clients
  • a security group (stateful firewall) to permit traffic to the server; ssh and udp 51820 will be permitted
  • a security group to permit access to the AWS client from the remote VPN clients

Hand-made diagram:

The files are long and inlcuded comments for all the sections to make them readable. They are available in my GitHub account.

This is the part that creates the VPC

resource "aws_vpc" "default" {
  cidr_block = var.vpc_subnet
  tags = {
    Name = "wireguard"
  }
}

This creates the private subnet

# private subnet for internal instances
resource "aws_subnet" "private" {
  vpc_id  = aws_vpc.default.id
  cidr_block  = var.private_subnet
  map_public_ip_on_launch = false
  tags = {
    Name = "private"
  }
}

You got the idea. All the details are in the docs about the AWS Provider.

Clone the repository

git clone https://github.com/routetonull/terrawire.git
cd terrawire

Edit variables.tf with your AWS credentials and favorite region

provider "aws" {
  region     = "eu-west-1"
  access_key = "01234567890"
  secret_key = "012345678900123456789001234567890"
}

Now we can initialize Terraform

terraform init

Output

Initializing the backend...

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "aws" (hashicorp/aws) 2.57.0...

The following providers do not have any version constraints in  configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain    breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.aws: version = "~> 2.57"

Validate the configuration

terraform validate

Output

Success! The configuration is valid.

Verify the changes that will be applied running

terraform plan

Output

<snip>

Plan: 12 to add, 0 to change, 0 to destroy.

</snip>
Warning

Verify you're working in a test AWS account to avoid any impact in a production infrastructure.

And finally we can run Terraform to create the VPC and all the objects

terraform apply

See it in action

That's it!

Now we can login to AWS Console to verify the results or use AWS CLI, using the commands below to start

aws ec2 describe-vpcs
aws ec2 describe-subnets
aws ec2 describe-internet-gateways
aws ec2 describe-instances
aws ec2 describe-route-tables
aws ec2 describe-security-groups

Terraform destroy

Warning

When we're done with the lab we must rember to run

terraform destroy

to remove all the resources created in AWS and avoid unexpected billing.

Alternate config: use env vars to provide AWS credentials to Terraform

If you prefer to use env vars to store AWS credentials for Terraform, instead of using variables.tf, create a new file named ~/aws.export.env and edit with your credentials and region

export AWS_ACCESS_KEY_ID=1234567890
export AWS_SECRET_ACCESS_KEY=123456789012345678901234567890
export AWS_DEFAULT_REGION=eu-west-1

Assign exec permission to the file

chmod +x ~/aws.export.env

And activate it running

source ~/aws.export.env

This command mut be run again every time a new terminal session is created, or after a reboot. Add the same lines in ~/.bashrc if you want to set the env vars permanently.

Last step: remove the provider section in variables.tf, it is not necessary anymore

provider "aws" {
  region = "eu-west-1"
  access_key = "1234567890"
  secret_key = "12345678901234567890"
}

Next post: Wireguard

We're done with part one of this post. The VPC is ready to use.

Stay tuned for part two where we'll install and configure Wireguard to provide a secure access to the private EC2 instances in AWS.