AWS + StrongSwan

Sometimes you need to connect two AWS networks without using AWS managed VPN services. Most tutorials show a simple tunnel between two instances, but they ignore high availability. That usually leads to asymmetric routing or a single point of failure.

In this example we build a small HA setup using strongSwan for IPsec and keepalived to control routing. Each side has two instances, so traffic can fail over automatically if one node goes down.

Network layout

AC1 net 10.1.1.0/24
instance A1 EIP 1.1.1.1 IP 10.1.1.11
instance A2 EIP 1.1.1.2 IP 10.1.1.12
AC2 net 10.2.1.0/24
instance B1 EIP 1.1.2.1 IP 10.2.1.11
instance B2 EIP 1.1.2.2 IP 10.2.1.12

Install required packages

apt-get install strongswan keepalived

strongSwan configuration

# cat /etc/ipsec.conf
# ipsec.conf - strongSwan IPsec configuration file

config setup
  strictcrlpolicy=no
  charondebug=all
conn %default
  ikelifetime=60m
  keylife=20m
  rekeymargin=3m
  keyingtries=1
  keyexchange=ikev2
conn aws2aws
  authby=secret
  auto=start
  type=tunnel
  left=10.1.1.11
  leftid=1.1.1.1
  leftsubnet=10.1.1.0/24
  leftauth=psk
  right=10.1.2.11
  rightsubnet=10.1.2.0/24
  rightauth=psk
  ike=aes128-sha1-modp1024
  esp=aes128-sha1-modp1024

include /var/lib/strongswan/ipsec.conf.inc

IPsec secrets

# cat /etc/ipsec.secrets

1.1.1.1 : PSK "7sMH9Sb5cWh7"
1.1.2.1 : PSK "A4zsR9DtceYY"

include /var/lib/strongswan/ipsec.secrets.inc

Enable forwarding

# cat /etc/sysctl.conf
net.ipv4.ip_forward=1

Firewall rules

/sbin/iptables -N SW
/sbin/iptables -A INPUT -j SW
/sbin/iptables -A INPUT -p tcp -j SW
/sbin/iptables -A INPUT -p udp -j SW
/sbin/iptables -A INPUT -p icmp -j SW
/sbin/iptables -A INPUT -p ah -j SW
/sbin/iptables -A INPUT -p esp -j SW
/sbin/iptables -A FORWARD -j SW

/sbin/iptables -A SW -s 1.1.1.1 -j ACCEPT
/sbin/iptables -A SW -s 1.1.2.1 -j ACCEPT

Keepalived configuration

# cat /etc/keepalived/keepalived.conf

vrrp_script check_sw {
    script "/usr/sbin/ipsec statusall | grep ESTABLISHED"
    interval 2
    timeout 5
    fall 2
    rise 2
}

vrrp_instance VI_vip1 {
    state BACKUP
    interface eth0
    virtual_router_id 1
    priority 1
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass LvTZHnXZDNbk
    }

    unicast_peer {
        10.1.1.11
        10.1.1.12
    }

    track_script {
        check_sw
    }

    notify_master "/etc/keepalived/scripts/t1-1.sh"
}

Routing scripts

t1-1.sh A1 -> B1 (default)
t1-2.sh A2 -> B2 (failover)
t2-1.sh B1 -> A1 (failover)
t2-2.sh B2 -> A2 (default)

AWS route update example

aws ec2 replace-route --region us-east-1 --route-table-id rtb-00000 --destination-cidr-block 10.1.2.0/24 --instance-id i-00000

Connection status

# /usr/sbin/ipsec statusall
Status of IKE charon daemon (strongSwan 5.2.1, Linux 3.16.0-4-amd64, x86_64):
  uptime: 35 days, since Sep 19 09:39:10 2018
  malloc: sbrk 2539520, mmap 0, used 333632, free 2205888
  worker threads: 11 of 16 idle, 5/0/0/0 working, job queue: 0/0/0/0, scheduled: 3
  loaded plugins: charon aes rc2 sha1 sha2 md5 random nonce x509 revocation constraints pubkey pkcs1 pkcs7 pkcs8 pkcs12 pgp dnskey sshkey pem openssl fips-prf gmp agent xcbc hmac gcm attr kernel-netlink resolve socket-default stroke updown
Listening IP addresses:
  10.1.1.11
Connections:
     aws2aws:  10.1.1.11...1.1.1.1  IKEv2
     aws2aws:   local:  [1.1.1.1] uses pre-shared key authentication
     aws2aws:   remote: [1.1.1.2] uses pre-shared key authentication
     aws2aws:   child:  10.1.1.0/24 === 10.1.2.0/24 TUNNEL
Security Associations (1 up, 0 connecting):
     aws2aws[971]: ESTABLISHED 20 minutes ago, 10.1.1.11[1.1.1.1]...1.1.2.1[1.1.2.1]
...
     aws2aws{971}:   10.1.1.0/24 === 10.1.2.0/24
Human Logic, AI Syntax... Note on Content: I'm a Systems Engineer, not a native English writer. To ensure my technical ideas are clear and accessible, I use AI tools to polish the grammar and style. The workflow is simple: I provide the logic, the code, and the real-world experience. The AI handles the "English-to-Human" translation layer. If you find a bug, that's on me. If you find a perfectly placed comma, that's probably the AI.

Comments

Popular posts from this blog

FreeRadius with Google Workspace LDAP

Fixing pssh (parallel-ssh) Problems on Debian 10 with Python 3.7