ctx->guides->ipsec
Securing services with IPsec tunnels
This short document will get you started on how to configure simple IPsec tunnels between your remote hosts. All peers need to run the key management daemon and have IPsec enabled and allowed through PF.
/etc/rc.conf.local:
isakmpd_flags="-K"
ipsec=YES
/etc/pf.conf:
# Allow incoming IPsec traffic
pass quick on egress proto {esp, ah}
pass in quick on egress proto udp to port {isakmp, ipsec-nat-t}
The next part shows how we run mail message submission and POP version 3 services through IPsec tunnels.
Server configuration
/etc/ipsec.conf:
peers="{hosta.example.org, hostb.example.org, hostc.example.org}"
ike passive esp proto tcp from egress to $peers \
port submission \
psk "hackme"
ike passive esp proto tcp from egress to $peers \
port pop3 \
psk "hackmemore"
Client configuration
/etc/ipsec.conf:
peer=ipsec.example.org
ike esp proto tcp from egress to $peer \
port submission \
psk "hackme"
ike esp proto tcp from egress to $peer \
port pop3 \
psk "hackmemore"
The isakmpd server uses UDP port 500 for key management; UDP port 4500 is used for IPsec NAT features. You should forward those ports on your router if needed. The ports can be found with:
$ grep ipsec /etc/services
ipsec-nat-t 4500/tcp ipsec-msft # IPsec NAT-Traversal
ipsec-nat-t 4500/udp ipsec-msft # IPsec NAT-Traversal
$ grep isakmp /etc/services
isakmp 500/udp # ISAKMP key management
Furthermore, here is a little trick to bypass some nasty firewalls that block low ports. This makes port 500 to effectively appear as port 5000 to other peers.
/etc/pf.conf:
# Rewrite outgoing src port isakmp to src port 5000 and back
pass out on egress proto udp from any port isakmp to any port isakmp \
nat-to (egress) port 5000
Testing the setup
If all went OK, from a client you should see something like the following, when the server's IP address is 1.2.3.4 while the client's IP address is 5.6.7.8.
$ ipsecctl -s flow
FLOWS:
flow esp in proto tcp from 1.2.3.4 port pop3 to 5.6.7.8 peer 1.2.3.4 srcid 5.6.7.8/32 dstid 1.2.3.4/32 type use
flow esp out proto tcp from 5.6.7.8 to 1.2.3.4 port pop3 peer 1.2.3.4 srcid 5.6.7.8/32 dstid 1.2.3.4/32 type require
flow esp in proto tcp from 1.2.3.4 port submission to 5.6.7.8 peer 1.2.3.4 srcid 5.6.7.8/32 dstid 1.2.3.4/32 type use
flow esp out proto tcp from 5.6.7.8 to 1.2.3.4 port submission peer 1.2.3.4 srcid 5.6.7.8/32 dstid 1.2.3.4/32 type require
$ route -n show -encap
Routing tables
Encap:
Source Port Destination Port Proto SA(Address/Proto/Type/Direction)
1.2.3.4/32 110 5.6.7.8/32 0 6 1.2.3.4/esp/use/in
5.6.7.8/32 0 1.2.3.4/32 110 6 1.2.3.4/esp/require/out
1.2.3.4/32 587 5.6.7.8/32 0 6 1.2.3.4/esp/use/in
5.6.7.8/32 0 1.2.3.4/32 587 6 1.2.3.4/esp/require/out
$ nc -v server.example.org 587
Connection to server.example.org 587 port [tcp/submission] succeeded!
$ nc -v server.example.org 110
Connection to server.example.org 110 port [tcp/pop3] succeeded!
+OK
Notes
There is no actual server and client in the protocol, however in this
setup the server knows all other hosts, and they only know the server.
The server is configured as passive while others start negotiation
immediately. The server needs to know all peers in order to correctly
setup the Encap routes. A config with peers=any
will create a default
route pointing to the peer negotiated last. Such a setup is broken!
That is certainly not all folks!
Cheers!
lostd@