Site-to-site IPSec VPN between strongSwan(AWS) and Cisco Router(On-premise)
Introduction
strongSwan is an open source project, which was launched in 2005 as a fork of the discontinued FreeS/WAN open source project.
The strongSwan VPN suite uses the native IPsec stack in the standard Linux kernel. It supports both the IKEv1 and IKEv2 protocols.
It is a comprehensive implementation of the Internet Key Exchange (IKE) protocols that allows securing IP traffic in policy- and route-based IPsec scenarios from simple to very complex.
In this post, we connect strongSwan on AWS with on-premise Cisco router. I think it’s an interesting scenario, because first, it applies to many companies who have their IT infrastructures on AWS; Second, there are very few tutorials cover this topic.
As well, most existing strongSwan examples online are using the deprecated ipsec.conf method. We will use the recommended swanctl method.
We use IKEv1 in this tutorial, because despite it is “officially deprecated” recently, it’s still the de-facto set up nowadays.
For IKEv2 example, please check the other post https://hello-vpn.com/blog/site-to-site-ipsec-vpn-between-strongswan-and-cisco-router-with-ikev2
Network diagram
The left side(mumbai) is using strongSwan hosted on AWS, and the right side(france) is using on-premise Cisco router. There is also NAT configured, because site-to-site VPN between different companies usually require the encryption domain to use public IP address.
IP Info | Left side(mumbai) | Right side(france) |
VPN device/sw | strongSwan 5.9.8 Debian 12 | Cisco C931-4P |
VPN GW IP | 35.154.207.104 | 31.xxx.xxx.48 |
Encryption Domain (VPN host or subnet) | 3.6.74.40 (NAT to 192.168.0.88) | 31.xxx.xxx.89 (NAT to 192.168.1.2) |
IPSec parameters
Phase I Settings | |
Authentication Method | Pre-Shared |
Diffie-Helman Group | 2 (Mod1024) |
Encryption Algorithm | AES256 |
Hash Algorithm | SHA-1 |
SA Timeout | 28800 |
NAT-T | Enabled |
Phase II Settings | |
Encapsulation | ESP (encrypted) |
Perfect Forward Secrecy (PFS) | NO PFS |
Encryption Algorithm | AES256 |
Hash Algorithm | SHA-1 |
Lifetime (In Seconds) | 3600 (Default) |
Notes for AWS
IP address
We need to keep in mind that an AWS instance does not know the Elastic IP associated with its network interface. It only knows the internal IP inside the subnet that the network interface belongs to.
Therefore, in our example, strongSwan instance is only aware of IP 192.168.0.33.
Disable Src/Dest check
For strongSwan instance, disable src/dest check on it’s main network interface.
The reason? Check below quote from AWS doc:
You can enable or disable source/destination checks, which ensure that the instance is either the source or the destination of any traffic that it receives. Source/destination checks are enabled by default.
You must disable source/destination checks if the instance runs services such as network address translation, routing, or firewalls.
Security group
The security group of strongSwan instance need to have below 2 rules enabled:
- allow incoming from 0.0.0.0 to UDP port 4500
- allow incoming from 0.0.0.0 to UDP port 500
Installation(mumbai site)
apt install strongswan charon-systemd
Set linux kernel parameters(mumbai site)
Edit /etc/sysctl.conf
# /etc/sysctl.conf
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1
# Do not accept ICMP redirects (prevent MITM attacks)
net.ipv4.conf.all.accept_redirects = 0
# Do not send ICMP redirects (we are not a router)
#net.ipv4.conf.all.send_redirects = 0
### also add below two lines, otherwise ping test will not work, replace enX0 with your own interface
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.enX0.send_redirects = 0
Disable the “send_redirect” on the affected network interface is important, because without it, the ping test will not work.
Below is the explanation from strongSwan doc:
If the VPN gateway is not the default gateway of the LAN, ICMP redirects might get returned to hosts if they send traffic destined for the remote hosts/subnets to the VPN gateway, directing them to the default gateway of the LAN (which probably doesn’t work and otherwise might get that traffic out unencrypted). To avoid this, disable sending such ICMP messages by setting
net.ipv4.conf.all.send_redirects=0 net.ipv4.conf.default.send_redirects=0
If the latter option is not set before the network interface comes up, also set the option for the individual interface
net.ipv4.conf.<iface>.send_redirects=0
Load the new setting
root@ip-192-168-0-33:~# sysctl -p
net.ipv4.ip_forward = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.enX0.send_redirects = 0
Configure NAT (Network Address Translation)
First, create the file to define network rules.
iptables-save > /etc/iptables.rules
Then add below rules in /etc/iptables.rules
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -d 3.6.74.40/32 -m comment --comment incoming-from-remote-host -j DNAT --to-destination 192.168.0.88
-A POSTROUTING -s 192.168.0.88/32 -d 31.xxx.xxx.89/32 -m comment --comment outgoing-to-remote-host -j SNAT --to-source 3.6.74.40
Run below command to update iptables
iptables-restore < /etc/iptables.rules
strongSwan VPN configuration(mumbai site)
/etc/swanctl/swanctl.conf
# default settings for all conns (e.g cert, IP pools)
conn-defaults {
version = 1
reauth_time = 28800
proposals = aes256-sha1-modp1024
}
# default settings for all child configs (e.g. traffic selectors)
child-defaults {
mode = tunnel
start_action = trap|start
rekey_time = 3600
}
connections {
mumbai-france : conn-defaults {
local_addrs = 192.168.0.33
remote_addrs = 31.xxx.xxx.48
proposals = aes256-sha1-modp1024
local {
auth = psk
id = 35.154.207.104
}
remote {
auth = psk
id = 31.xxx.xxx.48
}
children {
mumbai-france1 : child-defaults {
local_ts = 3.6.74.40/32
remote_ts = 31.xxx.xxx.89/32
start_action = trap|start
esp_proposals = aes256-sha1
}
}
}
}
secrets {
ike-1 {
# a - local, b - remote
id-1b = 31.xxx.xxx.48
secret = ANsvU5WIwmQ6
}
}
Note:
- local_addrs = 192.168.0.33, remember AWS instance does not know it’s own Elastic IP address, therefore here we put the internal IP
Cisco VPN configuration (france on-premise)
crypto isakmp policy 100
encr aes 256
authentication pre-share
group 2
crypto isakmp key ANsvU5WIwmQ6
!
crypto ipsec transform-set vpn-sha1-aes256 esp-aes 256 esp-sha-hmac
mode tunnel
!
crypto map francemap 2 ipsec-isakmp
set peer 35.154.207.104
set transform-set vpn-sha1-aes256
match address TEST-MUMBAI-SS
!
ip nat inside source static 192.168.1.2 31.xxx.xxx.89
!
ip access-list extended TEST-MUMBAI-SS
permit ip host 31.xxx.xxx.89 host 3.6.74.40
strongSwan start daemon
systemctl start strongswan
# for each modification on the connection, run below two command
swanctl --load-all #load preshared key and conn
swanctl --initiate --child mumbai-france1
The output of –initiate command is something like below if it’s successful:
swanctl --initiate --child mumbai-france1
[ENC] generating QUICK_MODE request 2568099685 [ HASH SA No ID ID ]
[NET] sending packet: from 192.168.0.33[4500] to 31.xxx.xxx.48[4500] (172 bytes)
[NET] received packet: from 31.xxx.xxx.48[4500] to 192.168.0.33[4500] (204 bytes)
[ENC] parsed QUICK_MODE response 2568099685 [ HASH SA No ID ID N((24576)) ]
[CFG] selected proposal: ESP:AES_CBC_256/HMAC_SHA1_96/NO_EXT_SEQ
[IKE] CHILD_SA mumbai-france1{54} established with SPIs c21634ca_i 8dbd1a12_o and TS 3.6.74.40/32 === 31.xxx.xxx.89/32
[ENC] generating QUICK_MODE request 2568099685 [ HASH ]
[NET] sending packet: from 192.168.0.33[4500] to 31.xxx.xxx.48[4500] (60 bytes)
initiate completed successfully
Verify VPN Status
Verify strongSwan config
swanctl --list-conns
mumbai-france: IKEv1, reauthentication every 28800s
local: 192.168.0.33
remote: 31.xxx.xxx.48
local pre-shared key authentication:
id: 35.154.207.104
remote pre-shared key authentication:
id: 31.xxx.xxx.48
mumbai-france1: TUNNEL, rekeying every 3600s
local: 3.6.74.40/32
remote: 31.xxx.xxx.89/32
Verify strongSwan VPN status
swanctl --list-sas
mumbai-france: #53, ESTABLISHED, IKEv1, 99405922d34109cd_i b9f401ec6e3f603c_r*
local '35.154.207.104' @ 192.168.0.33[4500]
remote '31.xxx.xxx.48' @ 31.xxx.xxx.48[4500]
AES_CBC-256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024
established 8915s ago, reauth in 18254s
mumbai-france1: #54, reqid 2, INSTALLED, TUNNEL-in-UDP, ESP:AES_CBC-256/HMAC_SHA1_96
installed 984s ago, rekeying in 2412s, expires in 2976s
in c21634ca, 2940 bytes, 35 packets, 34s ago
out 8dbd1a12, 2940 bytes, 35 packets, 34s ago
local 3.6.74.40/32
remote 31.xxx.xxx.89/32
We can also use below command to request detailed information about the IPsec SAs and policies installed in the kernel.
ip -s xfrm state
ip -s xfrm policy
Verify Cisco VPN status
# show crypto isakmp sa
IPv4 Crypto ISAKMP SA
dst src state conn-id status
35.154.207.104 31.xxx.xxx.48 QM_IDLE 1223 ACTIVE
31.xxx.xxx.48 35.154.207.104 QM_IDLE 1224 ACTIVE
# show crypto session brief
Status: A- Active, U - Up, D - Down, I - Idle, S - Standby, N - Negotiating
K - No IKE
ivrf = (none)
Peer I/F Username Group/Phase1_id Uptime Status
35.154.207.104 Gi4 35.154.207.104 00:22:41 UA
35.154.207.104 Gi4 35.154.207.104 00:22:41 UA
Routing
The hosts behind the VPN GW need to route remote host’s IP via the VPN GW.
On the left side (mumbai), the host “app-L” will add route like this:
ip route add 31.xxx.xxx.89 via 192.168.0.33
And on the right side (france), host “app-R” has route like this:
ip route add 3.6.74.40 via 192.168.1.1
Test
We will ping from app-L (192.168.0.88) to app-R (192.168.1.2)
ping 31.xxx.xxx.89
PING 31.xxx.xxx.89 (31.xxx.xxx.89) 56(84) bytes of data.
64 bytes from 31.xxx.xxx.89: icmp_seq=1 ttl=62 time=152 ms
64 bytes from 31.xxx.xxx.89: icmp_seq=2 ttl=62 time=152 ms
64 bytes from 31.xxx.xxx.89: icmp_seq=3 ttl=62 time=152 ms
64 bytes from 31.xxx.xxx.89: icmp_seq=4 ttl=62 time=152 ms
64 bytes from 31.xxx.xxx.89: icmp_seq=5 ttl=62 time=152 ms
64 bytes from 31.xxx.xxx.89: icmp_seq=6 ttl=62 time=153 ms
64 bytes from 31.xxx.xxx.89: icmp_seq=7 ttl=62 time=152 ms
To verify that those traffic are indeed getting encrypted and decrypted via the VPN tunnel, we can check the counter on both strongSwan and Cisco.
on strongSwan instance, run “swanctl –list-sas”, and observe the number of “in” and “out” packets, it should increase while doing the ping test.
swanctl --list-sas
mumbai-france: #53, ESTABLISHED, IKEv1, 99405922d34109cd_i b9f401ec6e3f603c_r*
local '35.154.207.104' @ 192.168.0.33[4500]
remote '31.xxx.xxx.48' @ 31.xxx.xxx.48[4500]
AES_CBC-256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024
established 8915s ago, reauth in 18254s
mumbai-france1: #54, reqid 2, INSTALLED, TUNNEL-in-UDP, ESP:AES_CBC-256/HMAC_SHA1_96
installed 984s ago, rekeying in 2412s, expires in 2976s
in c21634ca, 2940 bytes, 35 packets, 34s ago
out 8dbd1a12, 2940 bytes, 35 packets, 34s ago
local 3.6.74.40/32
remote 31.xxx.xxx.89/32
On Cisco side, observe as well the “Inbound” and “Outbound” packets increase.
# show crypto session detail
Interface: GigabitEthernet4
Uptime: 00:19:19
Session status: UP-ACTIVE
Peer: 35.154.207.104 port 4500 fvrf: (none) ivrf: (none)
Phase1_id: 35.154.207.104
Desc: (none)
Session ID: 0
IKEv1 SA: local 31.xxx.xxx.48/4500 remote 35.154.207.104/4500 Active
Capabilities:N connid:1223 lifetime:21:28:43
Session ID: 0
IKEv1 SA: local 31.xxx.xxx.48/4500 remote 35.154.207.104/4500 Active
Capabilities:N connid:1224 lifetime:06:17:20
IPSEC FLOW: permit ip host 31.xxx.xxx.89 host 3.6.74.40
Active SAs: 4, origin: crypto map
Inbound: #pkts dec'ed 2121 drop 0 life (KB/Sec) 4344779/2452
Outbound: #pkts enc'ed 2121 drop 0 life (KB/Sec) 4344779/2452
Conclusion
It’s relatively easy to create a standard site-to-site IPSec VPN using strongSwan if you check documentation carefully.
Cost-wise, this is a very interesting option for small companies who only require VPN connection occasionally for some projects.
References
Cisco document: example config between strongSwan and Cisco router (IKEv1 and IKEv2)
strongSwan official doc example of site-to-site IKEv1
Migrate from ipsec.conf to swanctl.conf
https://techtalksecurity.blogspot.com/2022/12/configure-ipsec-site-to-site-vpn-in.html?m=1
https://www.tecmint.com/setup-ipsec-vpn-with-strongswan-on-debian-ubuntu/