GithubHelp home page GithubHelp logo

terraform-aws-ec2-wireguard's Introduction

A Terraform deployment for setting up a WireGuard server in AWS

This Terraform deployment sets up a WireGuard server in AWS, in a default subnet in the default VPC.

To avoid storing the WireGuard private key in the terraform.tfstate/terraform.tfvars file we store it as a SecureString in AWS SSM Parameter Store and inject it into WireGuard's wg0.conf on the first boot with our user-data script.

Due to the way Terraform handles changes to certain resource parameters, any changes to the wg_* variables will trigger a redeploy of the instance. This is intended behaviour.

On the first boot, the provided user-data script installs aws-cli (for fetching the server's private key from SSM), WireGuard and Unbound (so the server can act as a DNS resolver).

By default we do not open up SSH access to the internet, we instead rely on SSM Session Manager to be able to connect to the instance. To open up for SSH access, add your IP-address/network to the mgmt_allowed_hosts variable.

Created resources

  • EC2 instance, that is automatically configured with user-data.
  • A Elastic IP address, so our instance will keep the same public IP address.
  • A security group, that permits management access from a trusted network and WireGuard access from 0.0.0.0/0.
  • IAM roles.
  • (Optional) SSH key pair.
  • (Optional) A record in Route53 pointed at the elastic IP address. Note that this requires a Route53 hosted zone to already be present.

Generating private and public keys

WireGuard does not have usernames or passwords, instead it relies on public-key cryptography for authentication. The server has a pair with a private and public key, and the clients has their own pairs of private and public keys.

How to generate private and public keys

By running wg genkey | tee wg_private.key | wg pubkey > wg_public.key two sets of keys are written to your current folder. One consists of you private key and the other of your public key.

User management on the server side consists of addings peers to wg0.conf like so:

[Peer]
PublicKey = gN65BkIKy1eCE9pP1wdc8ROUtkHLF2PfAqYdyYBz6EA=
AllowedIPs = 10.10.10.230/32

and then running wg addconf wg0 <(wg-quick strip wg0) as root to add your peer to the running WireGuard instance. Note that wg addconf will not remove peers from the running instance if they were deleted from the configuration.

To restart WireGuard run sudo wg-quick down wg0 && sudo wg-quick up wg0.

Store your WireGuard private key in SSM

In the parameter store of your favorite region, create a SecureString parameter containing the private key you created for your server, and give it a name, like /ec2/vpn_node/server_privatekey.
The name of the parameter is the one you'll be referencing in the wg_privkey_ssm_path variable in terraform.tfvars.

Connecting to WireGuard

After your server is created, you can connect to it with the WireGuard clients.
Here is an example where we assume you set the allowed IP address for a client to 192.168.2.2/32.

[Interface]
PrivateKey = {your_client_private_key}
Address = 192.168.2.2/32
DNS = 192.168.2.1

[Peer]
PublicKey = {your_server_public_key}
AllowedIPs = 0.0.0.0/0 # Set to 0.0.0.0/0 to route all traffic via the tunnel.
Endpoint = {your_server_fqdn}:51820

Connecting to instance with SSM

You can run aws ssm start-session --target YOUR_INSTANCE_ID to connect to your instance. You'll be dropped in a sh-shell as the ssm-user user.

Example:

$ WG_INSTANCE_ID=$(aws ec2 describe-instances --filters "Name=tag:project,Values=WireGuard" --query 'Reservations[*].Instances[*].{Instance:InstanceId}[0].Instance' --output text)

$ aws ssm start-session --target $WG_INSTANCE_ID        

Starting session with SessionId: ove-0985344d46b163ff8

$ whoami
ssm-user
$ sudo wg
interface: wg0
  public key: kzVF236asdhasdhjferusaa/5VPQXmClH66ZRM=
  private key: (hidden)
  listening port: 51820

peer: sBh0OUvBp4uzxbasdhqsrhjxsffgas7UadOw3c=
  allowed ips: 192.168.2.3/32
  persistent keepalive: every 25 seconds

Example terraform.tfvars:

wg_client_public_keys is a map with maps, one for each client.

aws_region             = "eu-north-1"
aws_availability_zones = ["eu-north-1a", "eu-north-1b", "eu-north-1c"]
aws_account_id         = "some_account_id"

tags = {
  "project" = "WireGuard"
}

instance_type = "t3.micro"

wg_privkey_ssm_path = "/ec2/vpn_node/server_privatekey"

wg_client_public_keys = {
  "user1-desktop" = {
    "ip"         = "192.168.2.2/32"
    "public_key" = "cdcdcdcdcdcdcdcd"
  }
  "user1-phone" = {
    "ip"         = "192.168.2.3/32"
    "public_key" = "abababababababa"
  }
}

Adding SSH Public key

ssh_public_key = "ssh-rsa some-ssh-key"

Allowing SSH access

mgmt_allowed_hosts = [
   "8.8.8.8/32",
   "9.9.9.0/24"
]

Add DNS record

dns_zone = "some_domain.net"
dns_fqdn = "vpn.eun1.some_domain.net"

Inputs

Name Description Type Default Required
aws_account_id The AWS account ID this deployments belongs to. any n/a yes
aws_availability_zones The AWS availability zones to deploy resources in. list(string) n/a yes
aws_region The AWS region to deploy resources in. any n/a yes
dns_fqdn (Optional) The FQDN of the A record pointing to the EC2 instance. string n/a yes
dns_zone (Optional) The Route53 hosted zone to add DNS records to. string n/a yes
instance_name A name to attach to the EC2 instance. string "wireguard-vpn-node" no
instance_type The type of instance to start. Updates to this field will trigger a stop/start of the EC2 instance. string "t3.micro" no
mgmt_allowed_hosts A list of hosts/networks to open up SSH access to. list [] no
sg_wg_allowed_subnets A list of hosts/networks to open up WireGuard access to. list
[
"0.0.0.0/0"
]
no
ssh_public_key (Optional) A SSH public key to create a key pair for in AWS EC2. string n/a yes
tags A map with tags to attach to all created resources. map {} no
wg_client_public_keys List of maps of client IPs and public keys. See Usage in README for details. map(map(string)) n/a yes
wg_persistent_keepalive Persistent Keepalive - useful for helping connectiona stability over NATs number 25 no
wg_privkey_ssm_path The path to the WireGuard server's private key in SSM any n/a yes
wg_server_network_cidr The internal network to use for WireGuard. Remember to place the clients in the same subnet. string "192.168.2.0/24" no
wg_server_port The port WireGuard should listen on. number 51820 no

Outputs

Name Description
vpn_node_fqdn The FQDN of the EC2 instance.
vpn_node_public_ip The public IP of the EC2 instance.

terraform-aws-ec2-wireguard's People

Contributors

oroddlokken avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

vtknightmare

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.