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
Post a Comment