Strongswan with Let’s Encrypt on CentOS and RHEL

I have been trying to set up a VPN on my Linode running RHEL 7. Many of the tutorials for this involve creating self-signed certificates, but why? I already have a perfectly valid Let’s Encrypt certificate available–I want to use that to secure my connection!

This is how I did it.

Assumptions

Install Strongswan

As root, yum install strongswan. If the package can’t be found, you probably don’t have EPEL installed and activated. Go back and do that.

Link Let’s Encrypt certificates to Strongswan

Create symlinks from the Let’s Encrypt certificates to Strongswan’s certificate store.

ln -s /etc/letsencrypt/live/mydomain.com/fullchain.pem /etc/strongswan/ipsec.d/certs/fullchain.pem
ln -s /etc/letsencrypt/live/mydomain.com/privkey.pem /etc/strongswan/ipsec.d/private/privkey.pem
ln -s /etc/letsencrypt/live/mydomain.com/chain.pem /etc/strongswan/ipsec.d/cacerts/chain.pem

This way, when they renew every 90 days, Strongswan has access to the new certificates.

Configure Strongswan

In your favourite editor, open /etc/strongswan/ipsec.conf, and add the following. Be sure to update leftid with your server’s domain name.

config setup
    uniqueids=no
    charondebug = ike 3, cfg 3

conn %default
    dpdaction=clear
    dpddelay=35s
    dpdtimeout=2000s

    keyexchange=ikev2
    auto=add
    rekey=no
    reauth=no
    fragmentation=yes
    compress=yes

    ### left - local (server) side
    # filename of certificate chain located in /etc/strongswan/ipsec.d/certs/
    leftcert=fullchain.pem
    leftsendcert=always
    leftsubnet=0.0.0.0/0,::/0

    ### right - remote (client) side
    eap_identity=%identity
    rightsourceip=10.1.1.0/24,2a00:1450:400c:c05::/112
    rightdns=8.8.8.8,2001:4860:4860::8888

conn ikev2-mschapv2
    rightauth=eap-mschapv2

conn ikev2-mschapv2-apple
    rightauth=eap-mschapv2
    leftid=server.mydomain.com

Add VPN username and passwords

In your favourite editor, open /etc/strongswan/ipsec.secrets and add usernames and plain-text passwords for the user you want to use.

# filename of private key located in /etc/strongswan/ipsec.d/private/
: RSA privkey.pem

# syntax is `username : EAP "plaintextpassword"`
rusty : EAP "IAmRustyTheMoodle"

If you need help generating a random, secure password, you can use openssl rand -base64 24 to generate one.

Open firewalld

Red Hat and CentOS use firewalld to configure iptables firewall and routing. Assuming your default and active zone is public, the following will open and forward the correct ports and protocols.

firewall-cmd --zone=public --permanent --add-rich-rule='rule protocol value="esp" accept'
firewall-cmd --zone=public --permanent --add-rich-rule='rule protocol value="ah" accept'
firewall-cmd --zone=public --permanent --add-port=500/udp
firewall-cmd --zone=public --permanent --add-port=4500/udp
firewall-cmd --zone=public --permanent --add-service="ipsec"
firewall-cmd --zone=public --permanent --add-masquerade
firewall-cmd --reload

Confirm the changes with firewall-cmd --list-all.

Configure sysctl to allow packet forwarding

In your favourite editor, open /etc/sysctl.conf and add the following:

net.ipv4.ip_forward = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0

Apply changes with sysctl -p, or with a restart.

Start Strongswan

As the super user, systemctl start strongswan. If you are feeling confident, you can enable the service so it starts automatically at boot with systemctl enable strongswan.

Confirm that certificates are loaded correctly with strongswan listcerts, and ensure your Let’s Encrypt certificate appears, and shows “has private key” in the pubkey section:

# strongswan listcerts
List of X.509 End Entity Certificates

  subject:  "CN=mydomain.com"
  issuer:   "C=US, O=Let's Encrypt, CN=Let's Encrypt Authority X3"
  validity:  not before Nov 13 10:51:00 2016, ok
             not after  Feb 11 10:51:00 2017, ok (expires in 70 days)
  serial:    aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99:aa
  altNames: server.mydomain.com, mydomain.com
  flags:     serverAuth clientAuth 
  OCSP URIs: http://ocsp.int-x3.letsencrypt.org/
  certificatePolicies:
             2.23.140.1.2.1
             1.3.6.1.4.1.44947.1.1.1
             CPS: http://cps.letsencrypt.org
  authkeyId: aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99:aa
  subjkeyId: aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99:aa
  pubkey:    RSA 2048 bits, has private key
  keyid:     aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99:aa
  subjkey:   aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99:aa

Configure clients

Windows is able to auto-detect the type of VPN, and does a fine job of guiding the input of authentication details.

In OS X, be sure to select IKEv2 when adding a VPN, and the Remote ID setting is the leftid setting in ipsec.conf. Don’t forget to add your username and password from ipsec.secret in Authentication Settings.

Troubleshooting

Something not working? tail -f /var/log/messages as the superuser, and try connecting. Debug information will be output, which should guide resolution.

References

Changelog

  • 2016-12-03: Simplified ipsec.conf. Updated references. Fixed newline issue with firewalld.