In today’s digital age, where our online activities are constantly being tracked and monitored, it is more important than ever to take steps to protect our privacy and security. One of the most effective ways to do this is to use a personal VPN. A VPN, or virtual private network, is an invaluable tool for protecting your online activities by encrypting your internet traffic and routing it through a secure server, making it virtually impossible for anyone to track or intercept your data.
This technical article will guide you through the process of creating a personal VPN using Tailscale on Amazon Web Services (AWS) using Terraform. Throughout this tutorial, you will learn how to:
By following this comprehensive tutorial, you will gain hands-on experience in setting up your own personal VPN with Tailscale on AWS using Terraform, empowering you to safeguard your online activities and enhance your overall cybersecurity posture.
Provisioning and managing cloud infrastructure can be a complex and time-consuming task, especially when dealing with multiple resources and configurations. This is where Terraform, an infrastructure as code (IaC) tool, comes into play. Terraform simplifies the process of infrastructure management by allowing you to define and provision your cloud resources in a declarative and repeatable manner. By using Terraform, you can easily create and manage your Tailscale VPN infrastructure with minimal configuration effort.
Tailscale distinguishes itself with its intuitive user interface and straightforward zero-configuration process. Unlike OpenVPN, which requires complex configuration files and manual setup, Tailscale offers a user-friendly dashboard and simple installation procedures. This makes it easier for non-technical users to set up and manage their VPNs.
Tailscale utilises the WireGuard protocol, a modern VPN protocol known for its superior performance, reduced overhead, and robust security features. Compared to OpenVPN’s older protocols, WireGuard offers faster connection speeds, lower latency, and improved encryption algorithms.
AWS offers a wide range of pricing options that are cost-effective and flexible, allowing you to tailor your VPN infrastructure to your specific needs and budget. It has a well-established ecosystem of third-party tools, documentation, and tutorials specific to Terraform and VPN deployment. This extensive support network makes it easier to find resources and troubleshoot any issues that might arise.
Terraform can be installed on a variety of operating systems, including Linux, macOS, and Windows.
For Ubuntu and Debian-based distros, you can use the following command to install Terraform:
sudo apt-get install terraform
For Red Hat Enterprise Linux (RHEL) and CentOS-based distros, you can use the following command to install Terraform:
sudo yum install terraform
Alternatively, you can download the Terraform binary for your Linux distribution from the official Terraform website.
For more complex installation scenarios or configurations, please refer to the official Terraform documentation.
Use Homebrew to install Terraform:
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
Alternatively, you can download the Terraform binary for macOS from the official Terraform website.
terraform version
If you do have currently have a working AWS account, you may:
You will need to generate an Access Key ID and Secret Key pair to be used by Terraform for EC2 instance provisioning.
For detailed instructions and documentation, please refer to the official AWS documentation:
Creating a Tailscale account and obtaining an API key for creating a Tailscale VPN mesh network is a straightforward process that can be completed in a few simple steps.
The steps illustrated here are based on this code repository: https://github.com/ayltai/terraform-tailscale. For the sake of simplicity, only the most important parts are highlighted in this article. Please refer to the repository for a working example.
Create a Terraform configuration file named “main.tf
” in your project root directory. This file will define the infrastructure components for AWS resources and the Tailscale mesh network.
This is where your Terraform state resides. It can be a local file or an AWS S3 bucket. Here, I used Terraform Cloud.
terraform {
required_version = ">= 1.5.0"
backend "remote" {
hostname = "app.terraform.io"
organization = "tailscale"
workspaces {
name = "main"
}
}
...
We will use the AWS and Tailscale providers. Additionally, we will need the TLS and Null provider.
terraform {
...
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.6"
}
null = {
source = "hashicorp/null"
version = "~> 3.2"
}
tailscale = {
source = "tailscale/tailscale"
version = "~> 0.13"
}
tls = {
source = "hashicorp/tls"
version = "~> 4.0"
}
}
}
provider "aws" {
region = var.aws_region
}
provider "tailscale" {
api_key = var.tailscale_api_key
tailnet = var.tailscale_tailnet
}
resource "aws_vpc" "this" {
cidr_block = var.vpc_cidr_block
}
resource "aws_subnet" "this" {
vpc_id = aws_vpc.this.id
cidr_block = var.subnet_cidr_block
availability_zone = "${var.aws_region}a"
}
resource "aws_internet_gateway" "this" {
vpc_id = aws_vpc.this.id
}
resource "aws_eip" "this" {
instance = aws_instance.this.id
domain = "vpc"
depends_on = [
aws_internet_gateway.this,
]
lifecycle {
create_before_destroy = true
}
}
resource "aws_route_table" "this" {
vpc_id = aws_vpc.this.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.this.id
}
}
resource "aws_route_table_association" "this" {
route_table_id = aws_route_table.this.id
subnet_id = aws_subnet.this.id
}
resource "aws_security_group" "this" {
name = "${var.server_hostname}-${var.aws_region}"
vpc_id = aws_vpc.this.id
ingress {
description = "SSH"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [
"0.0.0.0/0",
]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = [
"0.0.0.0/0",
]
}
}
This will generate a key pair of length 4096 bytes using the RSA algorithm. The key pair will be stored in the AWS Systems Manager Parameter Store if you need to access your EC2 instance later.
resource "tls_private_key" "this" {
algorithm = "RSA"
rsa_bits = 4096
}
resource "aws_key_pair" "this" {
key_name = "${var.server_hostname}-${var.aws_region}"
public_key = tls_private_key.this.public_key_openssh
}
resource "aws_ssm_parameter" "this" {
name = "/tailscale/${var.server_hostname}-${var.aws_region}"
type = "SecureString"
value = tls_private_key.this.private_key_pem
}
resource "aws_instance" "this" {
ami = data.aws_ami.this.id
instance_type = var.server_instance_type
subnet_id = aws_subnet.this.id
key_name = aws_key_pair.this.key_name
vpc_security_group_ids = [
aws_security_group.this.id,
]
root_block_device {
volume_size = var.server_storage_size
}
}
You can customise the Terraform configuration to suit your specific requirements, such as using a different EC2 instance type or AMI.
Create a remote-exec
provisioner block within the null resource block. This provisioner will execute commands on the EC2 instance after it is provisioned. This provisioner will be used to download and install the Tailscale VPN daemon on the instance.
Here is a detailed explanation of what it does:
sudo apt update
sudo apt -qq install software-properties-common apt-transport-https ca-certificates lsb-release curl -y
curl -fsSL ${var.tailscale_package_url}.noarmor.gpg | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
curl -fsSL ${var.tailscale_package_url}.tailscale-keyring.list | sudo tee /etc/apt/sources.list.d/tailscale.list
sudo apt update
sudo apt -qq install tailscale -y
sudo sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf
sudo sed -i 's/#net.ipv6.conf.all.forwarding=1/net.ipv6.conf.all.forwarding=1/' /etc/sysctl.conf
sudo sysctl -p
sudo tailscale up — advertise-exit-node — hostname=${var.server_hostname}-${var.aws_region} — authkey=${tailscale_tailnet_key.this.key}
sudo systemctl enable — now tailscaled
resource "null_resource" "this" {
triggers = {
always_run = timestamp()
}
provisioner "remote-exec" {
inline = [
"sudo apt update",
"sudo apt -qq install software-properties-common apt-transport-https ca-certificates lsb-release curl -y",
"curl -fsSL ${var.tailscale_package_url}.noarmor.gpg | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null",
"curl -fsSL ${var.tailscale_package_url}.tailscale-keyring.list | sudo tee /etc/apt/sources.list.d/tailscale.list",
"sudo apt update",
"sudo apt -qq install tailscale -y",
"sudo sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf",
"sudo sed -i 's/#net.ipv6.conf.all.forwarding=1/net.ipv6.conf.all.forwarding=1/' /etc/sysctl.conf",
"sudo sysctl -p",
"sudo tailscale up --advertise-exit-node --hostname=${var.server_hostname}-${var.aws_region} --authkey=${tailscale_tailnet_key.this.key}",
"sudo systemctl enable --now tailscaled",
]
connection {
agent = false
timeout = var.timeout
host = aws_eip.this.public_ip
private_key = tls_private_key.this.private_key_pem
user = var.server_username
}
}
}
Create a Terraform configuration file named “variables.tf” like this one. Change the values to suit your purpose. These are the most common variables that you may want to change:
aws_region
: The location of your VPN. You can find the value in the “Region Code” column on this website.tailscale_api_ke
y: Your Tailscale API key.tailscale_tailnet
: Your Tailscale tailnet name.Additionally, Terraform will need your AWS Access Key ID and Secret Key to manage the resources on your behalf. You can provide them by setting the Access Key ID to AWS_ACCESS_KEY_ID
and the Secret Key to AWS_SECRET_ACCESS_KEY
environment variables.
Run the following commands to apply the Terraform configuration:
terraform init
terraform plan
terraform apply
This will provision the EC2 instance, install the Tailscale VPN daemon, and configure it to act as the exit node.
Once the Terraform apply process completes, verify that the EC2 instance has successfully requested to join the Tailscale mesh network. You can use the Tailscale web console to check the status of the mesh network and subsequently approve this newly provisioned EC2 instance to act as an exit node.
Congratulations on successfully creating your own personal VPN with Tailscale on AWS using Terraform. You have now set up a secure and private network that you can use to access the internet from any device, anywhere in the world.
In this tutorial, you learnt how to:
You can now enjoy the benefits of a personal VPN, such as:
I hope this tutorial has been helpful. If you have any questions, please feel free to leave a comment.
15 Nov 2023 by Alan Tai