AWS Setup

Resources

Virtual Private Gateway

This resource is the AWS-side of the VPN connection. Once the tunnel is up, to successfully get instances to talk down the tunnel, the subnet route tables will need to reference this VPN Gateway resource to route specific CIDR destinations down the VPN tunnel.

resource "aws_vpn_gateway" "vpn_gateway" {
  vpc_id = aws_vpc.main.id
}

Customer Gateway

The customer gateway resource defines the customer-side of the connection. This will simply specify the public IP address of the customer-side of the connection.

resource "aws_customer_gateway" "customer_gateway" {
  bgp_asn    = 65000
  ip_address = ONPREM_PUBLIC_IP
  type       = "ipsec.1"
}

VPN Connection

This resource ties the previous 2 resources together, and defines the encryption and phase settings for the tunnel connection which will need to be recipricated on the on-prem setup to successfully initialise the tunnel.

resource "aws_vpn_connection" "main" {
  vpn_gateway_id      = aws_vpn_gateway.vpn_gateway.id
  customer_gateway_id = aws_customer_gateway.customer_gateway.id

  type               = "ipsec.1"
  static_routes_only = true

  # Forcefully use ikev2 over v1
  tunnel1_ike_versions                 = ["ikev2"]
  tunnel1_phase1_dh_group_numbers      = [14]
  tunnel1_phase1_encryption_algorithms = ["AES128"]
  tunnel1_phase1_integrity_algorithms  = ["SHA1"]

  tunnel1_phase2_dh_group_numbers      = [14]
  tunnel1_phase2_encryption_algorithms = ["AES128"]
  tunnel1_phase2_integrity_algorithms  = ["SHA1"]
}

Options

It is best to explicitly define a DH group of 14 and IKE version of v2. This is because Libreswan does not support DH group 2 by default, and defaults to using ikev2 for more secure connections.

You need to define options for both phases of the tunnel setup.

Definition of the phases from Libreswan:

Fully working VPN connections consist of an IKE SA (phase1) and an IPsec SA (phase2). The IKE SA refers to the > userland state and describes the endpoints IKE negotiation state. The IPsec SA refers to the kernel state that > is actually responsible for encrypting and decrypting the IP packets.

Static Routes

The connection specifies the use of static routes only, meaning the routes that get sent down the tunnel need to be explicitly specified.

resource "aws_vpn_connection_route" "onprem_route" {
  destination_cidr_block = ONPREM_PRIVATE_CIDR
  vpn_connection_id      = aws_vpn_connection.main.id
}

BGP Setup

To have AWS share and learn routes dynamically, the VPN gateways can be configured to use BGP. This setup requires static_routes_only = false and the bgp_asn configured on the customer gateway.

Libreswan Setup

Libreswan is an open-source IPSec VPN tunnel tool which can be used for setting up VPN tunnels using IKEv2.

On Linux, it can be installed with a simple apt install or dnf install.

Policy Based Routing

By default, libreswan uses policy-based routing descisions to determine where to send the traffic. You can view policies on linux with ip xfrm policy

Running ip xfrm state will show something like this:

src 172.32.0.178 dst 18.132.182.97
    proto esp spi 0xc9367acb reqid 16393 mode tunnel
    replay-window 0 flag af-unspec
    auth-trunc hmac(sha1) ...
    enc cbc(aes) ...
    ...

This shows the routing rules for the VPN setup, showing that if I need to get to

Setup

Firewall Rules

Use iptables to allow UPD connections to libreswan

sudo iptables -A INPUT -p udp --dport 500 -j ACCEPT
sudo iptables -A INPUT -p udp --dport 4500 -j ACCEPT
sudo iptables -A INPUT -p esp -j ACCEPT
sudo iptables -A INPUT -p ah -j ACCEPT

Kernel Parameter Configuration

You may be required to configure kernel parameters in /etc/sysctl.conf.

net.ipv4.ip_forward = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

ip_forward enables packet forwarding allowing them to move between the different interfaces on the Libreswan host.

accept_redirects=0 disables ICMP redirects due to the risk of dynamic route table changes on the host. The same applies for sending ICMP redirects.

Run sysctl -p to apply the changes

Connection Key

Add the connection secret key to /etc/ipsec.d/aws.conf

ONPREM_PUBLIC_IP AWS_PUBLIC_IP: PSK "SECRET_KEY"

Connection Config File

Define a connection configuration for a VPN in /etc/ipsec.d/VPN_NAME.conf.

conn aws
    authby=secret
    auto=start

    left=%defaultroute
    leftid=<ONPREM_PUBLIC_IP>
    leftsubnet=<LOCAL NETWORK>

    right=<AWS_PUBLIC_IP>
    rightsubnet=<REMOTE NETWORK>

    type=tunnel
    ikelifetime=8h
    keylife=1h
    phase2alg=aes128-sha1;modp2048
    ike=aes128-sha1;modp2048

    keyingtries=%forever
    keyexchange=ike
    dpddelay=10
    dpdtimeout=30
    dpdaction=restart_by_peer

"left" refers to the local/private network, where libreswan is running, while "right" represents the AWS network.

By default, libreswan does not support Diffie-Helman group 2, due to its weakness. Instead, we force the AWS VPN connection to use Diffie-Hellman group 14 (modp2048) to build a more secure tunnel which works with libreswan.

AWS does provide 2 tunnels per VPN connection to account for resiliency during maintenance, and failover tunnels. The second tunnel will come with a separate public IP and secret which can be added as a new ipsec connection in libreswan, the same way as the one above is setup.

Bring Up the Tunnel

You can verify ipsec config with ipsec verify. Providing all goes to plan the AWS connection can be added with:

ipsec addconn --config /etc/ipsec.conf aws

And then bring up the connection with:

ipsec auto --up aws

IPSec Commands

# Verify the ipsec setup
ipsec verify

# Add a connection
ipsec addconn --config /etc/ipsec.conf CONN_NAME

# View traffic status
ipsec trafficstatus

# Show routing policies
ip xfrm policy

Glossary

Word Description
ESP Encapsulating Security Payload is a protocol part of the IPSec suite. ESP encrypts the entire IP packet and adds a new IP header to allow it be securely transferred through the network.
AH Authentication Header is an authentication protocol used to provide data integrity, ensuring that data has not been chaned during transit.
Inside IP The IP addresses that AWS and on-premise sites use to communicate BGP information and tunnel data