Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
AWS VPC VPN StrongSwan Virtual Tunnel Interface (VTI)
#@ /etc/quagga/bgpd.conf (Centos & Ubuntu)
hostname <Local OS hostname>
password <Any random phrase>
enable password <Any random phrase>
!
log file /var/log/quagga/bgpd
!debug bgp events
!debug bgp zebra
debug bgp updates
!
router bgp <Your Customer Gateway ASN>
bgp router-id <Any integer number - smaller means higher priority routes>
network <Your internal LAN subnet - e.g. 10.130.0.0/16>
!network 169.254.x.x/32
!network 169.254.x.x/32
!
! aws tunnel #1 neighbour
neighbor <Your VGW1 Inside IP> remote-as 17493
!
! aws tunnel #2 neighbour
neighbor <Your VGW2 Inside IP> remote-as 17493
!
! Uncomment the line below if you prefer to use 'Connection B' as your backup (Connection A will # be used as your primary for all traffic). By default if you do not uncomment the next lines, traffic can #be sent and received down both of your connections at any time (asymmetric routing).
!neighbor <Your VGW2 Inside IP> route-map RM_LOWER_PRIORITY out
!
route-map RM_LOWER_PRIORITY permit 10
set as-path prepend <Your Customer Gateway ASN> <Your Customer Gateway ASN> <Your Customer Gateway ASN>
!
line vty
# LEGEND
# https://s3-us-west-2.amazonaws.com/youtubetutorials/racoon_config.txt
#
# <Your Customer Gateway ASN> is the local autonomous system (Customer Gateway ASN)
# 17493 is the remote autonomous system of AWS (Virtual Private Gateway ASN)
#
# <Your VGW1 Inside IP> is the 169.x address on the REMOTE side of the first peer. (Neighbor IP Address)
# <Your VGW2 Inside IP> is the 169.x address on the REMOTE side of the second peer. (Neighbor IP Address)
#
# <Your internal LAN subnet - e.g. 10.0.0.0/16> is the local private subnet/LAN (Private Network Subnet)
# 169.254.x.x/32 is the 169.x address on LOCAL side of the first peer. Use /32
# 169.254.x.x/32 is the 169.x address on the LOCAL side of the second peer. Use /32
#@ /etc/strongswan/ipsec-vti.sh (Centos) or /etc/strongswan.d/ipsec-vti.sh (Ubuntu)
#!/bin/bash
# AWS VPC Hardware VPN Strongswan updown Script
# Usage Instructions:
# Add "install_routes = no" to /etc/strongswan/strongswan.d/charon.conf or /etc/strongswan.d/charon.conf
# Add "install_virtual_ip = no" to /etc/strongswan/strongswan.d/charon.conf or /etc/strongswan.d/charon.conf
# For Ubuntu: Add "leftupdown=/etc/strongswan.d/ipsec-vti.sh" to /etc/ipsec.conf
# For RHEL/Centos: Add "leftupdown=/etc/strongswan/ipsec-vti.sh" to /etc/strongswan/ipsec.conf
# For RHEL/Centos 6 and below: git clone git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git && cd iproute2 && make && cp ./ip/ip /usr/local/sbin/ip
# Adjust the below according to the Generic Gateway Configuration file provided to you by AWS.
# Sample: http://docs.aws.amazon.com/AmazonVPC/latest/NetworkAdminGuide/GenericConfig.html
IP=$(which ip)
IPTABLES=$(which iptables)
PLUTO_MARK_OUT_ARR=(${PLUTO_MARK_OUT//// })
PLUTO_MARK_IN_ARR=(${PLUTO_MARK_IN//// })
case "$PLUTO_CONNECTION" in
AWS-VPC-GW1)
VTI_INTERFACE=vti1
VTI_LOCALADDR=<Your CGW1 Inside IP 169.254.x.x/30>
VTI_REMOTEADDR=<Your VGW1 Inside IP 169.254.x.x/30>
;;
AWS-VPC-GW2)
VTI_INTERFACE=vti2
VTI_LOCALADDR=<Your CGW2 Inside IP 169.254.x.x/30>
VTI_REMOTEADDR=<Your VGW2 Inside IP 169.254.x.x/30>
;;
esac
case "${PLUTO_VERB}" in
up-client)
#$IP tunnel add ${VTI_INTERFACE} mode vti local ${PLUTO_ME} remote ${PLUTO_PEER} okey ${PLUTO_MARK_OUT_ARR[0]} ikey ${PLUTO_MARK_IN_ARR[0]}
$IP link add ${VTI_INTERFACE} type vti local ${PLUTO_ME} remote ${PLUTO_PEER} okey ${PLUTO_MARK_OUT_ARR[0]} ikey ${PLUTO_MARK_IN_ARR[0]}
sysctl -w net.ipv4.conf.${VTI_INTERFACE}.disable_policy=1
sysctl -w net.ipv4.conf.${VTI_INTERFACE}.rp_filter=2 || sysctl -w net.ipv4.conf.${VTI_INTERFACE}.rp_filter=0
$IP addr add ${VTI_LOCALADDR} remote ${VTI_REMOTEADDR} dev ${VTI_INTERFACE}
$IP link set ${VTI_INTERFACE} up mtu 1436
$IPTABLES -t mangle -I FORWARD -o ${VTI_INTERFACE} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
$IPTABLES -t mangle -I INPUT -p esp -s ${PLUTO_PEER} -d ${PLUTO_ME} -j MARK --set-xmark ${PLUTO_MARK_IN}
$IP route flush table 220
#/etc/init.d/bgpd reload || /etc/init.d/quagga force-reload bgpd
;;
down-client)
#$IP tunnel del ${VTI_INTERFACE}
$IP link del ${VTI_INTERFACE}
$IPTABLES -t mangle -D FORWARD -o ${VTI_INTERFACE} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
$IPTABLES -t mangle -D INPUT -p esp -s ${PLUTO_PEER} -d ${PLUTO_ME} -j MARK --set-xmark ${PLUTO_MARK_IN}
;;
esac
# Enable IPv4 forwarding
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.conf.eth1.disable_xfrm=1
sysctl -w net.ipv4.conf.eth1.disable_policy=1
# References:
# http://docs.aws.amazon.com/AmazonVPC/latest/NetworkAdminGuide/Introduction.html
# http://end.re/2015-01-06_vti-tunnel-interface-with-strongswan.html
# https://www-01.ibm.com/support/knowledgecenter/#!/SST55W_4.3.0/liaca/liaca_cfg_ipsec_vti.html
#@ /etc/strongswan/ipsec.conf (Centos) or /etc/ipsec.conf (Ubuntu)
# ipsec.conf - strongSwan IPsec configuration file
# basic configuration
config setup
charondebug="cfg 2, ike 3"
# strictcrlpolicy=yes
# uniqueids = no
# Add connections here.
# Sample VPN connections
#conn sample-self-signed
# leftsubnet=10.1.0.0/16
# leftcert=selfCert.der
# leftsendcert=never
# right=192.168.0.2
# rightsubnet=10.2.0.0/16
# rightcert=peerCert.der
# auto=start
#conn sample-with-ca-cert
# leftsubnet=10.1.0.0/16
# leftcert=myCert.pem
# right=192.168.0.2
# rightsubnet=10.2.0.0/16
# rightid="C=CH, O=Linux strongSwan CN=peer name"
# auto=start
# Usage Instructions:
# Adjust the below according to the Generic Gateway Configuration file provided to you by AWS.
# Sample: http://docs.aws.amazon.com/AmazonVPC/latest/NetworkAdminGuide/GenericConfig.html
conn %default
# Authentication Method : Pre-Shared Key
#authby=psk
leftauth=psk
rightauth=psk
# Encryption Algorithm : aes-128-cbc
# Authentication Algorithm : sha1
# Perfect Forward Secrecy : Diffie-Hellman Group 2
ike=aes256-sha256-modp2048s256,aes128-sha1-modp1024!
# Lifetime : 28800 seconds
ikelifetime=28800s
# Phase 1 Negotiation Mode : main
aggressive=no
# Protocol : esp
# Encryption Algorithm : aes-128-cbc
# Authentication Algorithm : hmac-sha1-96
# Perfect Forward Secrecy : Diffie-Hellman Group 2
esp=aes128-sha256-modp2048s256,aes128-sha1-modp1024!
# Lifetime : 3600 seconds
lifetime=3600s
# Mode : tunnel
type=tunnel
# DPD Interval : 10
dpddelay=10s
# DPD Retries : 3
dpdtimeout=30s
# Tuning Parameters for AWS Virtual Private Gateway:
keyexchange=ikev1
#keyingtries=%forever
rekey=yes
reauth=no
dpdaction=restart
closeaction=restart
left=%defaultroute
leftsubnet=0.0.0.0/0,::/0
rightsubnet=0.0.0.0/0,::/0
leftupdown=/etc/strongswan/ipsec-vti.sh
installpolicy=yes
compress=no
mobike=no
conn AWS-VPC-GW1
# Customer Gateway: : <Your Strongswan-CGW Public IP>
left=<Your Strongswan-CGW Public IP>
# Virtual Private Gateway : <Your VGW1 Outside IP>
right=<Your VGW1 Outside IP>
auto=start
mark=100
#reqid=1
conn AWS-VPC-GW2
# Customer Gateway: : <Your Strongswan-CGW Public IP>
left=<Your Strongswan-CGW Public IP>
# Virtual Private Gateway : <Your VGW2 Outside IP>
right=<Your VGW2 Outside IP>
auto=start
mark=200
#reqid=2
# References:
# http://docs.aws.amazon.com/AmazonVPC/latest/NetworkAdminGuide/Introduction.html
# http://end.re/2015-01-06_vti-tunnel-interface-with-strongswan.html
# https://www-01.ibm.com/support/knowledgecenter/#!/SST55W_4.3.0/liaca/liaca_cfg_ipsec_vti.html
# https://aravindkrishnaswamy.wordpress.com/tag/multiple-vpn-tunnels-with-strongswan/
# https://aravindkrishnaswamy.wordpress.com/2014/11/26/site-to-site-vpn-between-openvpn-and-aws/
# http://www.mynameistoby.com/blog/2015/01/21/setting-up-strongswan-on-centos-6-to-connect-to-your-amazon-vpc-vpn/
# https://wiki.strongswan.org/projects/strongswan/wiki/ConnSection
# https://wiki.strongswan.org/projects/strongswan/wiki/IKEv2CipherSuites
#@ /etc/strongswan/ipsec.secrets (Centos) or /etc/ipsec.secrets (Ubuntu)
<Your Strongswan-CGW Public IP> <Your VGW1 Outside IP> : PSK "<Replace with VGW1 secret phrase provided by AWS>"
<Your Strongswan-CGW Public IP> <Your VGW2 Outside IP> : PSK "<Replace with VGW2 secret phrase provided by AWS>"
#@ /etc/sysconfig/iptables (Centos) or /etc/iptables/rules.v4 (Ubuntu with iptables-persistent package)
# Generated by iptables-save v1.4.7
*filter
:INPUT DROP [1:60]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [21:2888]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-A INPUT -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j DROP
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -i eth0 -p esp -j ACCEPT
-A INPUT -i eth0 -p udp -m udp --sport 500 --dport 500 -j ACCEPT
-A INPUT -i eth0 -p udp -m udp --sport 4500 --dport 4500 -j ACCEPT
-A INPUT -i vti+ -p tcp -m tcp --dport 179 -j ACCEPT
-A INPUT -i eth+ -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A FORWARD -i eth1 -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A FORWARD -p icmp -m icmp --icmp-type 0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -p icmp -m icmp --icmp-type 0 -m state --state RELATED,ESTABLISHED -j ACCEPT
COMMIT
# Completed
#@ /etc/quagga/zebra.conf (Centos & Ubuntu)
hostname <Local OS hostname>
password <Any random phrase>
enable password <Any random phrase>
!
! Configure interfaces
interface lo
! Change preferred source ip address of received routes
route-map RM_SET_SRC permit 10
set src <Your host ip-address on Your internal LAN subnet interface - e.g. 10.130.0.5>
ip protocol bgp route-map RM_SET_SRC
!
line vty
@aprudnev

This comment has been minimized.

Copy link

@aprudnev aprudnev commented Nov 1, 2016

It was extremely useful. We used this information and built very stable VTI router, posted here - https://github.com/eis-group-opensource/vti-router . The changes was:

  • most important, CentOS7 native kernel is not compatible, you must update to non native kernel 4
  • we keep configs for each vti interface in separate files, 3 for each .init for IP config (used by script), .conf for ipsec conf, , and separate PSK file.
  • AWS description parser added
  • Interaction with quagga added, BGP added / removed, static to the far end is now via quagga not in sysconfig file
  • 4 states for each vti interface - available, disabled, enabled, removed
  • all changes are restart - less and interruption - less (so we can add / delete vti interfaces without disrupting others)
  • health script added which re-connect failed IPSEC-s
  • all tested under heavy load, with AWS and Azure, and 10 - 16 interfaces / 1 VTI router (total of 10+ routers are in use).
  • management scripts added - to make initial setup, enter VTI information manually or by AWS file parsing, add/delete/enable/disable tunnels (on the fly, without any restarts, check status).
@bittrance

This comment has been minimized.

Copy link

@bittrance bittrance commented Nov 10, 2016

In case you are trying this from a Amazon Linux AMI, e.g. connecting from one VPC to another, StrongSwan cannot be yum:d, since it depends on libtspi (secure hardware storage for RSA keys) which is in base RHEL, but not in Amazon's base. So you have to:

yum-config-manager --enable epel
yum install yum-utils
yumdownloader strongswan
rpm -i --nodeps strongswan-5.4.0-2.el6.x86_64.rpm 

With this and the config above, it is possible to get at least a static route setup (i.e. no Quagga) going with just ip route add 172.16.0.0 via 169.254.X.Y added to ipsec-vti.sh. Kudos to @heri16.

Also, the $IPTABLES -t mangle -I INPUT -p esp -s ${PLUTO_PEER} -d ${PLUTO_ME} -j MARK --set-xmark ${PLUTO_MARK_IN} assumes no NAT-T? Looking at my iptables -t mangle -n -L -v gives

Chain INPUT (policy ACCEPT 682 packets, 93160 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 MARK       esp  --  *      *       <VGW-IP>       172.31.10.6          MARK set 0x64

My setup is NAT-T:d, being inside another VPC. The script could be improved to handle this, according to StrongSwan 4.4 changelog

PLUTO_ESP_ENC environment variables can be used in a user-specific updown script to set marks on inbound ESP or ESP_IN_UDP packets.

The script could be extended to match such packets with -p udp --dport 4500 or something to that effect.

(Note also https://wiki.strongswan.org/issues/1497 which appears to be fixed in the epel 6 strongswan-5.4.0-2.el6.x86_64 that I am using.)

@miguelaustro

This comment has been minimized.

Copy link

@miguelaustro miguelaustro commented Nov 11, 2017

Why "$IP link set ${VTI_INTERFACE} up mtu 1436" ?
Linux EC2 instances use jumbo frames and interfaces are set to MTU 9001. I increased ${VTI_INTERFACE} to 8937, but traffic stopped.
Any suggestion?

@kaaelhaa

This comment has been minimized.

Copy link

@kaaelhaa kaaelhaa commented Feb 13, 2018

@miguelaustro, AWS VPC VPN only supports MTUs of 1436 bytes.
In order to utilize jumbo frames you need support for jumbo frames across public internet, which won't happen. All frames will be fragmented to 1436 bytes each.

@nicolaracco

This comment has been minimized.

Copy link

@nicolaracco nicolaracco commented Feb 20, 2020

God bless you! You leveled me from zero to vpn master in a gist 👍

Other helpful notes for anything noob like me in matter of VPNs:

@heri16

This comment has been minimized.

Copy link
Owner Author

@heri16 heri16 commented Feb 20, 2020

You're welcome @nicolaracco

Thanks for the nice pointers! @aprudnev @bittrance @kaaelhaa @nicolaracco

The above minimalist config has been used for many years with no issues. It's nice to see what @aprudnev has done with it.

I'm currently looking for a job after a misadventure with a Blockchain outfit, so if anyone has any job opening in any part of the world, please drop me a message at Twitter handle "heri16". Thanks!

@nicolaracco

This comment has been minimized.

Copy link

@nicolaracco nicolaracco commented Feb 21, 2020

What additional steps are required to make this vpn host act as a gateway for its lan?

In my case AWS network is 172.0.0.0/16 and on-prem LAN is 10.3.0.0/16. VPN Gateway is 10.3.128.164.
The VPN gateway is able to reach any host inside the VPC (e.g. it can ssh in EC2 instances).
On another host of the lan (10.3.128.160) I ran route add -net 172.0.0.0 netmask 255.255.0.0 gw 10.3.128.164 dev eth2. But if I try from this host to ssh into a VPC EC2 it cannot reach the instance.
Running tcpdump on VPN gateway shows this output:

09:41:39.924771 IP ip-10-3-128-160.eu-central-1.compute.internal.37058 > ip-172-0-4-64.eu-central-1.compute.internal.ssh: Flags [S], seq 3268810629, win 26880, options [mss 8960,sackOK,TS val 513820347 ecr 0,nop,wscale 7], length 0
09:41:48.116888 IP ip-10-3-128-160.eu-central-1.compute.internal.37058 > ip-172-0-4-64.eu-central-1.compute.internal.ssh: Flags [S], seq 3268810629, win 26880, options [mss 8960,sackOK,TS val 513828539 ecr 0,nop,wscale 7], length 0
09:42:04.245177 IP ip-10-3-128-160.eu-central-1.compute.internal.37058 > ip-172-0-4-64.eu-central-1.compute.internal.ssh: Flags [S], seq 3268810629, win 26880, options [mss 8960,sackOK,TS val 513844667 ecr 0,nop,wscale 7], length 0
09:42:37.525175 IP ip-10-3-128-160.eu-central-1.compute.internal.37058 > ip-172-0-4-64.eu-central-1.compute.internal.ssh: Flags [S], seq 3268810629, win 26880, options [mss 8960,sackOK,TS val 513877947 ecr 0,nop,wscale 7], length 0
09:42:42.645264 ARP, Request who-has ip-10-3-128-164.eu-central-1.compute.internal tell ip-10-3-128-160.eu-central-1.compute.internal, length 42
09:42:42.645298 ARP, Reply ip-10-3-128-164.eu-central-1.compute.internal is-at fa:16:3e:55:1e:35 (oui Unknown), length 28

Solution

I was just missing to configure iptables for allowing forwarding :)
By default it seems only ICMP is allowed for forwarding on eth1. So, to allow anything from private LAN to AWS should be something like:

iptables -A FORWARD -i eth1 -J ACCEPT
iptables -A FORWARD -o eth1 -J ACCEPT
@aprudnev

This comment has been minimized.

Copy link

@aprudnev aprudnev commented Feb 21, 2020

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.