Sitetosite

Most IPsec implementations consist of two parts, one part in kernel for handling connection flow and encryption, and one userspace program for configuration and handling SAs, OpenBSD by default ships with iked and isakmpd handling SAs in IPsec.

Site-to-Site vpn

Consider in the following scenario, servers potato (192.168.1.1) and toybox (192.168.2.1) would like to access each other's network (10.0.1.0/24 and 10.0.2.0/24 respectively). This is called a site-to-site vpn. we may use OpenBSD's iked, to achieve the goal.

In this guide, the server which actively tries to connect is called initiator, while the server which is going to answer the request is called responder.

let's say toybox is the responder, while potato is the initiator.

Responder configuration

First, if firewall policy of responder is to block by default, we need to configure it's fire, otherwise, no action is needed. In /etc/pf.conf:

toybox=192.168.1.1
potato=192.168.2.1
ext_if=vio0

pass in log on $ext_if proto udp from $potato to $toybox port {isakmp, ipsec-nat-t} tag IKED
pass in log on $ext_if proto esp from $potato to $toybox tag IKED

Afterwards, reload pf:

toybox$ doas pfctl -f /etc/pf.conf

Next we need to configure iked:

toybox="192.168.1.1"
net1="10.0.1.0/24"
potato="192.168.2.1"
net2="10.0.2.0/24"

ikev2 'toybox' passive esp \
        from $net1 to $net2 \
        from $net1 to $potato \
        from $toybox to $net1 \
        local $toybox peer $potato \
        srcid "toybox"

In the configuration above, passive esp means iked waits for the initiator to start the connection. we have also defined systems and networks IP addresses, and mention connection from net1 (network of toybox) to net2 (network of potato, net1 to potato and toybox to it's own network should be allowed. we also mention connection is accepted from potato's IP, and messages we sent are tagged "toybox".

finally, set permissions. iked refuses to start if permissions are too open:

toybox$ chmod 0600 /etc/iked.conf

we are done on the responder.

Initiator configuration

In /etc/iked.conf:

toybox="192.168.1.1"
net1="10.0.1.0/24"
potato="192.168.2.1"
net2="10.0.2.0/24"

ikev2 'potato' active esp \
        from $net2 to $net1 \
        from $net2 to $toybox \
        from $potato to $net1 \
        peer $toybox \
        srcid "potato"

Configuration here is pretty similar to what we did back in the other server, only important differences are, now connection is active, meaning this server (potato) will actively try to connect to other server. messages are also tagged "potato".

setting permissions:

potato$ doas chmod 0600 /etc/iked.conf

Keys

IKed can operate using passwords or keys, by default there are public keys generated in /etc/iked/local.pub, keys for peers are read from one of directiories under /etc/iked/pubkeys, depending on how connection is made.

to copy keys from each server to the other one:

toybox$ ssh potato cat /etc/iked/local.pub \
	| doas tee -a /etc/iked/pubkeys/fqdn/potato

and:

potato$ ssh toybox cat /etc/iked/local.pub \
	| doas tee -a etc/iked/pubkeys/fqdn/toybox

and we are done.

Running

Finally, to check if everything is working properly, on the responder:

toybox$ doas iked -dv

and on the initiator:

potato$ doas iked -dv

if everything is working well, you should see something like following message:

...
spi=0x254fdb97ff6a879e: ikev2_childsa_enable: loaded flows: ESP-10.0.2.0/24=10.0.1.0/24(0), ESP-192.168.2.1/32=10.0.1.0/24(0), ESP-10.0.2.0/24=192.168.1.1/32(0)
spi=0x254fdb97ff6a879e: established peer 192.168.1.1:500[FQDN/potato] local 192.168.2.1:500[FQDN/toybox] policy 'toybox' as initiator (enc aes-128-gcm group curve25519 prf hmac-sha2-256)
...

else, if keys aren't set up properly, you will se something like this:

...
spi=0xd5de9f25502d0b7d: ikev2_dispatch_cert: peer certificate is invalid
spi=0xd5de9f25502d0b7d: ikev2_send_auth_failed: authentication failed for FQDN/toybox
...

if everything works ok, you can enable it using openbsd/rcctl on both servers:

toybox$ doas rcctl enable iked
toybox$ doas rcctl start iked
iked(ok)

and:

potato$ doas rcctl enable iked
potato$ rcctl start iked
iked(ok)

Testing

To verify it works, you may use openbsd/ping?, before running iked:

toybox$ ping -c 1 -I 10.0.1.1 10.0.2.1 
PING 10.0.2.1 (10.0.2.1): 56 data bytes

--- 10.0.2.1 ping statistics ---
1 packets transmitted, 0 packets received, 100.0% packet loss

potato$ ping -c 1 -I 10.0.2.1 10.0.1.1 
PING 10.0.1.1 (10.0.1.1): 56 data bytes

--- 10.0.1.1 ping statistics ---
1 packets transmitted, 0 packets received, 100.0% packet loss

After running iked:

toybox$ ping -c 1 -I 10.0.1.1 10.0.2.1 
PING 10.0.2.1 (10.0.2.1): 56 data bytes
64 bytes from 10.0.2.1: icmp_seq=0 ttl=255 time=1.539 ms

--- 10.0.2.1 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 1.539/1.539/1.539/0.000 ms
potato$ ping -c 1 -I 10.0.2.1 10.0.1.1
PING 10.0.1.1 (10.0.1.1): 56 data bytes
64 bytes from 10.0.1.1: icmp_seq=0 ttl=255 time=1.639 ms

--- 10.0.1.1 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 1.639/1.639/1.639/0.000 ms

Note that this setup is lightly tested, be careful while using it.


See also |https://www.openbsd.org/faq/faq17.html?, iked(8), ipsec(4), iked.conf(5)