Host to Host IPsec Tunnel With Libreswan On CentOS 7.2

This is a guide on setting up a Host to Host IPsec tunnel between two CentOS 7.2 hosts. We will be using Libreswan as the implementation of IPsec. Libreswan is available in CentOS 7.2 in the default package repositories.

Before you get started you are going to need two CentOS 7.2 servers, I am using KVM virtual servers in this example, you can use either real metal or a KVM virtual server. I have not tried this on other hypervisors, but I would be interested to hear if you have success using anything other than KVM.

One of my virtual servers will be hosted on Digital Ocean and the other is running on a HP Microserver in my office. The IPsec tunnel will be initiated from the virtual server running on the HP Microserver as this is behind a NAT. Essentially the local virtual server will be a road warrior in this instance.

IPsec Topology

Installing and Configuring libreswan

Login to each of your virtual machines and install Libreswan, you can do this by running the following.

yum install -y libreswan

You should now have the config file /etc/ipsec.conf and the directory /etc/ipsec.d now run the following command

ipsec status

As the IPsec service has not yet been started you should get a message like the following.

whack: Pluto is not running (no "/var/run/pluto/pluto.ctl")

Ok good, now Libreswan is installed

Next up you need to configure your RSA keys, we will be using RSA keys for authentication as it provides a higher level of security than a private shared key.

You need to initialize the NSS database and then generate the hostkey, this step must be done on both virtual servers.

# ipsec initnss
Initializing NSS database
See 'man pluto' if you want to protect the NSS database with a password

# ipsec newhostkey
/usr/libexec/ipsec/newhostkey: WARNING: file "/etc/ipsec.secrets" exists, appending to it
Generated RSA key pair using the NSS database

It may take some time to generate the key depending on how much entropy /dev/random provides. Once the key generation process completes you will get the following message.

/usr/libexec/ipsec/newhostkey: WARNING: file "/etc/ipsec.secrets" exists, appending to it
Generated RSA key pair using the NSS database

Now the key generation is complete we can start by creating our config files, we will do this first on our Digital Ocean virtual server.

Using your favourite text editor, create the file /etc/ipsec.d/host-to-host.conf and fill it with the following contents.

conn host-to-host
 left=%defaultroute
 leftsubnet=178.50.30.10/32
 leftrsasigkey=
 leftid=@digitalocean
 right=%any
 rightsubnet=192.168.2.100/32
 rightrsasigkey=
 rightid=@home
 dpddelay=5
 dpdtimeout=30
 dpdaction=restart
 auto=add

You should replace leftsubnet= with the public IP address of your Digital Ocean virtual server followed by /32 to indicate the subnet is a single host.

Also you need to replace leftrsasigkey= with the leftrsasigkey for that host, run the following command on your Digital Ocean virtual server. And copy from and including leftrsasigkey= right up until and including the last character. Use this value to replace the blank leftrsasigkey= value.

# ipsec showhostkey --left
ipsec showhostkey loading secrets from "/etc/ipsec.secrets"
ipsec showhostkey no secrets filename matched "/etc/ipsec.d/*.secrets"
ipsec showhostkey loaded private key for keyid: PPK_RSA:AQPJRZtjt
 # rsakey AQPJRZtjt
 leftrsasigkey=0sAQPJRZtjtcRrGWKk3fOau+1M1HjY0KDGWtDSF/I4s1uQLBx8tI0inoH7dypvowq/pI/AksjEh+s+gyJxWiWUtO7oyKm/I3jPxCbED90RTe8mloAEinjPVBQqpUMQOdBC315xPxxp1Ay8EMmbMrPXRTKqWuscoEfDtfUFuD/hE+3fXub9VGWhbjimAAp5aeYCSW+vGymRDFeRejoBbqIBc1FRiNWinrSgV6+lfmzq305cv9hK1+1fEvAr6R1gu4jxrxjaQpWwI37Qz5dSKjZ26eqApUnGgyEZS4pD8pJ1fk/TcDrScD0o42KiDjHOVltvHmb9b5hzGYlwnkZAewjYNoGAIWlB1uMzv7GNOGIQjxpqiNlKVO3+EepONTRlR1bQya5FoMgSZ1v9OZkxjn5q0LjHAS2jg2iEVdXTVV/ng69PT+J7Cp4YXmO5pAzvdcQwg6rLawLAfck6k9+GpfElgGTV31g6E/hV4sE7U75SOvMglFfstGBoftKnT/jziAztVPEcpLLruOPKCPlQHzHDdGT+0QLTozi7GK9iT1YlOedkMKcPCLp+SSAkYHzofe2JVr0+pev+760XvFkPMRPGw1W1

Now replace rightsubnet= with your other virtual servers private IP address followed by /32 in our example we use 192.168.2.100/32

You should also replace rightrsasigkey= you must get this value from your other virtual server, in our case we login to 192.168.2.100 and run the following command.

# ipsec showhostkey --right
ipsec showhostkey loading secrets from "/etc/ipsec.secrets"
ipsec showhostkey no secrets filename matched "/etc/ipsec.d/*.secrets"
ipsec showhostkey loaded private key for keyid: PPK_RSA:AQPAcILGW
 # rsakey AQPAcILGW
 rightrsasigkey=0sAQPAcILGW8l0YmIfPkNCEbN1N5Lna3qb/Yjj4bD2u0wNvKUSO2j62xhdCavPLoBFtNfJnMnaMNtAr8odNMTCig2Tu8ZXQVajszQwmCVGRAATK82L+nO0LBD4bJRlA86un352bzAMPBcLZgwmEA//bYznzQ036sch5ooQ3YMailgRR9IKkPezx1Nz9ny5uaZLGN7uxzWMOxllfMyCRBj52bf1JMDwShPFS72NuBIi2ZxzasHeO1OyPl5KHprDJH3j8fO2qmYKAivr4vQt54MsjHd89/ePr6gg/nfEpVAFhw2Pxv+vERQhXgvX/CSVQXMtiVrWyJH4s803XDoYRMfsW8Q1XsAeDFTOq18Wf1jh0GhP70OrfOFDvURITwIZNnVXTxJ+u8cOYnKxgahQ5+H7gyP9JWunufb+F0IVPx8tc0jFgCpidlVBozEOZLmG7fRi5ReU5UmdMZhv4fI4yW7ewZhYQt/hEKdLddUyZtTkZbyKHoFlPWBhiuaX0CBDXWj8dy0+kNPv

Replace rightrsasigkey with the rightrsasigkey value returned from the previous command.

This configuration file is now complete, you may run the following to start the IPsec service.

# systemctl start ipsec

Now run the following to confirm that the config file has been loaded. You will see in the output the host-to-host connection information. This means IPsec is ready to receive connections, we must first configure the other side of the tunnel.

# ipsec status
...
000 Connection list:
000
000 "host-to-host": 178.50.30.10/32===178.50.30.10[@digitalocean]---178.50.30.1...%any[@home]===192.168.2.100/32; unrouted; eroute owner: #0
000 "host-to-host": oriented; my_ip=unset; their_ip=unset
000 "host-to-host": xauth info: us:none, them:none, my_xauthuser=[any]; their_xauthuser=[any]
000 "host-to-host": modecfg info: us:none, them:none, modecfg policy:push, dns1:unset, dns2:unset, domain:unset, banner:unset;
000 "host-to-host": labeled_ipsec:no;
000 "host-to-host": policy_label:unset;
000 "host-to-host": ike_life: 3600s; ipsec_life: 28800s; rekey_margin: 540s; rekey_fuzz: 100%; keyingtries: 0;
000 "host-to-host": retransmit-interval: 500ms; retransmit-timeout: 60s;
000 "host-to-host": sha2_truncbug:no; initial_contact:no; cisco_unity:no; send_vendorid:no;
000 "host-to-host": policy: RSASIG+ENCRYPT+TUNNEL+PFS+IKEV1_ALLOW+IKEV2_ALLOW+SAREF_TRACK+IKE_FRAG_ALLOW;
000 "host-to-host": conn_prio: 32,32; interface: eth0; metric: 0; mtu: unset; sa_prio:auto; nflog-group: unset;
000 "host-to-host": dpd: action:restart; delay:5; timeout:30; nat-t: force_encaps:no; nat_keepalive:yes; ikev1_natt:both
000 "host-to-host": newest ISAKMP SA: #0; newest IPsec SA: #0;
000 "v6neighbor-hole-in": ::/0===::1<::1>:58/34560...%any:58/34816===::/0; prospective erouted; eroute owner: #0

On your local virtual server (192.168.2.100 in this example) create the following configuration file using your favourite text editor /etc/ipsec.d/host-to-host.conf again you will need to replace some values.

conn host-to-host
 left=%defaultroute
 leftsubnet=192.168.2.41/32
 leftrsasigkey=
 leftid=@home
 right=178.50.30.10
 rightsubnet=178.50.30.10/32
 rightrsasigkey=
 rightid=@digitalocean
 dpddelay=5
 dpdtimeout=30
 dpdaction=restart
 auto=start

rightsubnet= should be replaced with the private IP address of your local virtual server followed by /32 to indicate a single host.

leftrsasigkey= should be replaced with the value returned from running the following command on the local virtual server.

# ipsec showhostkey --left
ipsec showhostkey loading secrets from "/etc/ipsec.secrets"
ipsec showhostkey no secrets filename matched "/etc/ipsec.d/*.secrets"
ipsec showhostkey loaded private key for keyid: PPK_RSA:AQPAcILGW
 # rsakey AQPAcILGW
 leftrsasigkey=0sAQPAcILGW8l0YmIfPkNCEbN1N5Lna3qb/Yjj4bD2u0wNvKUSO2j62xhdCavPLoBFtNfJnMnaMNtAr8odNMTCig2Tu8ZXQVajszQwmCVGRAATK82L+nO0LBD4bJRlA86un352bzAMPBcLZgwmEA//bYznzQ036sch5ooQ3YMailgRR9IKkPezx1Nz9ny5uaZLGN7uxzWMOxllfMyCRBj52bf1JMDwShPFS72NuBIi2ZxzasHeO1OyPl5KHprDJH3j8fO2qmYKAivr4vQt54MsjHd89/ePr6gg/nfEpVAFhw2Pxv+vERQhXgvX/CSVQXMtiVrWyJH4s803XDoYRMfsW8Q1XsAeDFTOq18Wf1jh0GhP70OrfOFDvURITwIZNnVXTxJ+u8cOYnKxgahQ5+H7gyP9JWunufb+F0IVPx8tc0jFgCpidlVBozEOZLmG7fRi5ReU5UmdMZhv4fI4yW7ewZhYQt/hEKdLddUyZtTkZbyKHoFlPWBhiuaX0CBDXWj8dy0+kNPv

right= should be replaced with the public IP address of your Digital Ocean virtual server.

rightsubnet= should be replaced with the public IP address of your Digital Ocean virtual server followed by /32 to indicate a single host.

rightrsasigkey= should be replaced with the value returned from running the following command on the Digital Ocean virtual server.

# ipsec showhostkey --right
ipsec showhostkey loading secrets from "/etc/ipsec.secrets"
ipsec showhostkey no secrets filename matched "/etc/ipsec.d/*.secrets"
ipsec showhostkey loaded private key for keyid: PPK_RSA:AQPJRZtjt
 # rsakey AQPJRZtjt
 rightrsasigkey=0sAQPJRZtjtcRrGWKk3fOau+1M1HjY0KDGWtDSF/I4s1uQLBx8tI0inoH7dypvowq/pI/AksjEh+s+gyJxWiWUtO7oyKm/I3jPxCbED90RTe8mloAEinjPVBQqpUMQOdBC315xPxxp1Ay8EMmbMrPXRTKqWuscoEfDtfUFuD/hE+3fXub9VGWhbjimAAp5aeYCSW+vGymRDFeRejoBbqIBc1FRiNWinrSgV6+lfmzq305cv9hK1+1fEvAr6R1gu4jxrxjaQpWwI37Qz5dSKjZ26eqApUnGgyEZS4pD8pJ1fk/TcDrScD0o42KiDjHOVltvHmb9b5hzGYlwnkZAewjYNoGAIWlB1uMzv7GNOGIQjxpqiNlKVO3+EepONTRlR1bQya5FoMgSZ1v9OZkxjn5q0LjHAS2jg2iEVdXTVV/ng69PT+J7Cp4YXmO5pAzvdcQwg6rLawLAfck6k9+GpfElgGTV31g6E/hV4sE7U75SOvMglFfstGBoftKnT/jziAztVPEcpLLruOPKCPlQHzHDdGT+0QLTozi7GK9iT1YlOedkMKcPCLp+SSAkYHzofe2JVr0+pev+760XvFkPMRPGw1W1

Now save the configuration file and start the IPsec service on your local virtual server.

# systemctl start ipsec

Check the ipsec status, all being well the tunnel should be established and you should be able to send traffic to private IP address of your local virtual server from your Digital Ocean virtual server.

# ipsec status
000 #4: "host-to-host":4500 STATE_QUICK_I2 (sent QI2, IPsec SA established); EVENT_SA_REPLACE in 26838s; newest IPSEC; eroute owner; isakmp#3; idle; import:admin initiate
000 #4: "host-to-host" esp.498fa27b@178.50.30.10 esp.af78dce2@192.168.2.100 tun.0@178.50.30.10 tun.0@192.168.2.100 ref=0 refhim=4294901761 Traffic: ESPout=0B ESPin=0B! ESPmax=4194303B
000 #3: "host-to-host":4500 STATE_MAIN_I4 (ISAKMP SA established); EVENT_SA_REPLACE in 1647s; newest ISAKMP; lastdpd=0s(seq in:25944 out:0); idle; import:admin initiate

From your Digital Ocean virtual server try and SSH to your local virtual server on it’s private IP address.

# ssh root@192.168.2.100
The authenticity of host '192.168.2.100 (192.168.2.100)' can't be established.
ECDSA key fingerprint is 3c:6f:2b:a9:1d:d2:f6:22:e8:b2:2f:54:e2:f5:92:05.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.2.41' (ECDSA) to the list of known hosts.
root@192.168.2.100's password:
Last login: Sun Aug 14 12:31:50 2016 from 127.0.0.1
#

Congratulations, you have now configured an IPsec tunnel between two hosts. If you have any problems or feedback please leave a comment!