Solved FreeBSD to FreeBSD (11.2) IPSec / Road Warrior Setup

Hello,

I'd like to setup two FreeBSD decvies (laptop and server) to communicate securely and route the entire traffic from the laptop over the secured tunnel through the server. The setup should look like this:

Code:
   Laptop  ----------- (Internet) ------- Server
   (Dynamic IP)                           (Public IP)

I guess this should be achievable with gif interfaces, StrongSwan and IKEv2 but I weren't successful yet. The FreeBSD documentation has a similar setup using racoon (which I believe, is based on IKEv1). I'd use preshared Keys for now, but it should be done with certificates later (if that basic setup works). Ideally, more than one laptop can connect to the server but for now, this can be one device.

Has anyone running such a scenario and wants to share his configuration or is interested in setting up something similar?

While doing some research, I've found old posts that seem not working or posts that want to achieve other goals. Possibilities and other scenarios include
  1. SSH VPN (tunneling) - which is a bit more expensive due to TCP,
  2. OpenVPN - a lot of people seem to use this instead of IPSec, but I would prefer the encryption done at the network stack inside the kernel. Not quite sure but I believe that strongSwan is a utility that allows X.509 and other authentication schemes, but it's using the FreeBSD kernel facilities to encrypt network traffic.
  3. IKEv1 with racoon.
  4. WireGuard (?)
Thanks for your help.
 
I run this scenario, using keys and StrongSwan. I can connect to with my FreeBSD laptop, android phone and even Cisco ASA.

Server config
Code:
config setup
#       strictcrlpolicy=yes
        uniqueids = yes

conn %default
        keyexchange=ikev2
        authby=pubkey
        left=server_ip
        leftid="C=xxxx, O=xxxxxx, CN=xxxxxxxxx"
        leftcert=ipsec-server-cert.pem
        ike = aes256-sha1-prfsha1-modp2048
        esp = aes256-sha1
        fragmentation=yes
        dpdaction=clear
        rekey=no

conn sphinx
        leftsubnet=0.0.0.0/0
        rightsourceip=192.168.2.0/24
        right=%any
        rightdns=10.0.10.1
        rightid="C=xxx, O=xxxxx, CN=xxxxxxx"
        auto=add

Client
Code:
config setup
        # strictcrlpolicy=yes
        # uniqueids = no

conn server
        keyexchange=ikev2
        authby=pubkey
        left=%any
        leftsourceip=%config
        leftid="C=xxxx, O=xxxxxxx, CN=xxxxxx"
        leftcert=ipsec-sphinx-cert.pem
        right=212.237.34.39
        rightid="C=xxx, O=xxxxx, CN=xxxxxxx"
        rightsubnet=0.0.0.0/0
        ikelifetime = 24h
        rekey=yes
        fragmentation=yes
        lifetime = 60m
        dpdaction=restart
        keyingtries=%forever
        auto=start
 
abishai:
Thanks for sharing your config. Awesome to hear that this works. Do you have any special interfaces for this setup? I've read about ipsec(4) but not sure how it relates to strongswan.

Also: can you show me which commands you're using for certificate creations?
 
No interfaces needed, ipsec is capable mixing everything according rules. Even virtual ip is optional as well.

Sure, here you are:
1. CA: foo.bar
2. Server fqdn: server.foo.bar
3. Client fqdn: client.foo.bar

CA generation:
pki --gen --outform pem --size 2048 > ipsec-ca-key.pem
pki --self --outform pem --lifetime 3650 --digest sha256 --in ipsec-ca-key.pem --ca --dn "C=BAR, O=FOO, CN=foo.bar CA" > ipsec-ca-cert.pem

Server key generation
pki --gen --outform pem --size 2048 > ipsec-server-key.pem
pki --pub --in ipsec-server-key.pem | pki --issue --outform pem --digest sha256 --lifetime 3650 --cacert ipsec-ca-cert.pem --cakey ipsec-ca-key.pem --flag serverAuth --flag ikeIntermediate --san server.foo.bar --dn "C=BAR, O=FOO, CN=server.foo.bar" > ipsec-server-cert.pem

Client key:
pki --gen --outform pem --size 2048 > ipsec-client-key.pem
pki --pub --in ipsec-client-key.pem | pki --issue --outform pem --digest sha256 --cacert ipsec-ca-cert.pem --cakey ipsec-ca-key.pem --san client.foo.bar --dn "C=BAR, O=FOO, CN=client.foo.bar" > ipsec-client-cert.pem

Packaging for distribution:
openssl pkcs12 -export -out ipsec-client.p12 -inkey ipsec-client-key.pem -in ipsec-client-cert.pem -certfile ipsec-ca-cert.pem
openssl enc -base64 -in ipsec-client.p12 -out ipsec-client.b64
 
  • Thanks
Reactions: bch
So, once again, thanks to abishai for the help! With that help, I was able to set up a FreeBSD/FreeBSD Roadwarrior VPN Setup. I'd like to add a few notes here what I did and how to set up the firewall. I hope it is helpful for others too:

I am using the following hosts:

Code:
   192.168.36.131             192.168.36.132
   [fbsd.foo.bar] ----------- [fbsd2.foo.bar]
     |                         (Route: 10/8 -> 192.168.36.131 ESP)
     |
   10.0.0.1
   10.0.0.2
   ....

I am using FreeBSD 12 on both systems (otherwise, you have to make sure that the kernel supports IPSEC and NAT).
  1. Preshared Key (I used this one to get started and debugging is a bit simpler than starting with cert-based strongswan).
    1. Server Config: 2 files need to be changed, plus pf.conf (if used)
      1. /usr/local/etc/ipsec.conf:
        Code:
        config setup         uniqueids = no
        # Add connections:
        conn %default
                keyexchange=ikev2
                ikelifetime=60m
                keylife=20m
                rekeymargin=3m
                keyingtries=1
                keyexchange=ikev2
                authby=secret
        conn rw
                left=192.168.36.131
                leftsubnet=10.0.0.0/16   # Jails, VMs or whatever
                right=%any
                auto=add
      2. /usr/local/etc/ipsec.secrets:
        Code:
        192.168.36.131 : PSK "SuperSecret"
      3. /etc/pf.conf:
        Code:
        ext_if=em0set skip on lo0
        block in log all
        ...
        pass in log on $ext_if proto tcp from any to any port 22
        pass in log on $ext_if proto udp from any to any port { 500, 4500 }
        pass in log on $ext_if proto esp from any to any
        pass out log all keep state
    2. Server Startup: now, you can start strongswan on the server:
      Code:
      kldload pf && pfctl -f /etc/pf.conf && pfctl -e
      service strongswarn onestart  # or to debug the program:
      ipsec start --nofork --debug-all
    3. Client Config: same config files must be changed:
      1. /usr/local/etc/ipsec.conf
        Code:
        config setup
        conn %default
                ikelifetime=60m
                keylife=20m
                rekeymargin=3m
                keyingtries=1
                keyexchange=ikev2
                authby=secret              # psk or secret
        conn home                          # name used in ipsec(1) commands
                leftfirewall=yes
                right=192.168.36.131       # target server
                rightsubnet=10.0.0.0/16    # network from the server
                auto=add                   # Add routing entries?
      2. /usr/local/etc/ipsec.secrets:
        Code:
        192.168.36.131 : PSK "SuperSecret"
    4. After that, the client can try connecting to the server:
      Code:
      service strongswan onestart   # or the debug version (seen above)
      ipsec up home
      To query the status: ipsec status or ipsec statusall
  2. The 2 config files and password files have to be changed as this:
    1. Create the certificates as described by abishai
    2. server:
      1. /usr/local/etc/ipsec.conf

      2. Code:
        config setup
                # strictcrlpolicy=yes
                 uniqueids = no
        
        # Add connections here:
        conn %default
                keyexchange=ikev2
                ikelifetime=60m
                keylife=20m
                rekeymargin=3m
                keyingtries=1
                keyexchange=ikev2
        conn rw
                left=fbsd.foo.bar
                leftsubnet=10.0.0.0/16
                leftid="C=BAR, O=FOO, CN=fbsd.foo.bar"
                leftcert=/root/ipsec-server-cert.pem
                leftfirewall=yes
                right=%any
                auto=add
      3. /usr/local/etc/ipsec.secrets
        Code:
        : RSA /path/to/ipsec-server-key.pem
    3. client:
      1. /usr/local/etc/ipsec.conf

      2. Code:
        config setup
        conn %default
                ikelifetime=60m
                keylife=20m
                rekeymargin=3m
                keyingtries=1
                keyexchange=ikev2
        
        conn home
                leftcert=/home/bch/ipsec-client-cert.pem
                leftid="C=BAR, O=FOO, CN=fbsd2.foo.bar"
                left=%any
                leftfirewall=yes
        
                right=fbsd.foo.bar
                rightid="C=BAR, O=FOO, CN=fbsd.foo.bar"
                rightsubnet=10.0.0.0/16
                auto=add
      3. /usr/local/etc/ipsec.secrets
        Code:
        : RSA /path/to/ipsec-client-key.pem
    4. Commands to bring up the tunnel are the same.
The result can be verified with tcpdump -i em0. Any improvements are welcome.
 
Back
Top