VPN with FAST_IPSEC and ipsec tools
David DeSimone
fox at verio.net
Fri Jun 23 06:22:29 UTC 2006
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Michael Vince <mv at thebeastie.org> wrote:
>
> > The main reason to use IPSEC tunnel mode and avoid GIF is that such
> > a config is interoperable with other IPSEC implementations, and thus
> > is much more useful in the real world.
>
> OK that said, how do you create a network to network tunnel based VPN
> without using the gif or gre devices?
Ok, here's a typical setup that I've used.
Suppose you have two gateways:
Gateway 1 IP = 1.2.3.4
Networks behind it:
192.168.1.0/24
192.168.2.0/24
Gateway 2 IP = 5.6.7.8
Networks behind it:
192.168.11.0/24
192.168.12.0/24
Most of the examples you'll find will teach you to use IPSEC in
Transport mode. But Transport mode is only used for one endpoint to
talk to another endpoint. What you want here (and what other gateways
like Cisco will implement) is Tunnel mode, where the traffic is
encapsulated rather than merely encrypted.
First you must define your SA's (security associations) in ipsec.conf.
SA's are defined from the perspective of the gateway. What is "inbound"
on one gateway is "outbound" on the other. You can't use the same
ipsec.conf on each endpoint; you have to tailor it to match what it
should expect to see.
Gateway 1's ipsec.conf:
# This is ipsec.conf
# Load it using: setkey -f /etc/ipsec.conf
spdflush; # If you ever reload you will want to start fresh
# Outbound traffic
spdadd 192.168.1.0/24 192.168.11.0/24 any \
-P out ipsec esp/tunnel/1.2.3.4-5.6.7.8/unique;
spdadd 192.168.2.0/24 192.168.11.0/24 any \
-P out ipsec esp/tunnel/1.2.3.4-5.6.7.8/unique;
spdadd 192.168.1.0/24 192.168.12.0/24 any \
-P out ipsec esp/tunnel/1.2.3.4-5.6.7.8/unique;
spdadd 192.168.2.0/24 192.168.12.0/24 any \
-P out ipsec esp/tunnel/1.2.3.4-5.6.7.8/unique;
# Inbound traffic
spdadd 192.168.11.0/24 192.168.1.0/24 any \
-P in ipsec esp/tunnel/5.6.7.8-1.2.3.4/unique;
spdadd 192.168.12.0/24 192.168.1.0/24 any \
-P in ipsec esp/tunnel/5.6.7.8-1.2.3.4/unique;
spdadd 192.168.11.0/24 192.168.2.0/24 any \
-P in ipsec esp/tunnel/5.6.7.8-1.2.3.4/unique;
spdadd 192.168.12.0/24 192.168.2.0/24 any \
-P in ipsec esp/tunnel/5.6.7.8-1.2.3.4/unique;
Things to notice:
There are 8 SA's defined, because each gateway has two subnets,
and each unique subnet needs an SA defined IN EACH DIRECTION.
So, 2 subnets here x 2 subnets there x 2 directions = 8 SA's total.
Half of the SA's will be from the perspective of inbound traffic,
(using "-P in") and the other half will be output ("-P out").
When an SA is inbound ("-P in"), the tunnel descriptor will
have the remote gateway listed first, followed by the local
gateway. Inbound traffic flows FROM the remote gateway (5.6.7.8)
TO the local gateway (1.2.3.4), leading to a descriptor of
"esp/tunnel/5.6.7.8-1.2.3.4/unique;"
When an SA is outbound ("-P out"), the descriptor will be
reversed, showing traffic FROM this gateway TO the remote,
as in "esp/tunnel/1.2.3.4-5.6.7.8/unique;"
When an SA is inbound ("-P in"), the remote gateway's network will
appear first (because it is the source), followed by the local
gateway's network (the destination). That is why the first inbound
specification reads "spdadd 192.168.11.0/24 192.168.1.0/24 any",
specifying traffic coming FROM a remote network TO a local network.
An output SA specifies a local network followed by a remote network.
I hope you can see the pattern.
Gateway 2's ipsec.conf:
# This is ipsec.conf
# Load it using: setkey -f /etc/ipsec.conf
spdflush; # If you ever reload you will want to start fresh
# Inbound traffic
spdadd 192.168.11.0/24 192.168.1.0/24 any \
-P out ipsec esp/tunnel/5.6.7.8-1.2.3.4/unique;
spdadd 192.168.12.0/24 192.168.1.0/24 any \
-P out ipsec esp/tunnel/5.6.7.8-1.2.3.4/unique;
spdadd 192.168.11.0/24 192.168.2.0/24 any \
-P out ipsec esp/tunnel/5.6.7.8-1.2.3.4/unique;
spdadd 192.168.12.0/24 192.168.2.0/24 any \
-P out ipsec esp/tunnel/5.6.7.8-1.2.3.4/unique;
# Outbound traffic
spdadd 192.168.1.0/24 192.168.11.0/24 any \
-P in ipsec esp/tunnel/1.2.3.4-5.6.7.8/unique;
spdadd 192.168.2.0/24 192.168.11.0/24 any \
-P in ipsec esp/tunnel/1.2.3.4-5.6.7.8/unique;
spdadd 192.168.1.0/24 192.168.12.0/24 any \
-P in ipsec esp/tunnel/1.2.3.4-5.6.7.8/unique;
spdadd 192.168.2.0/24 192.168.12.0/24 any \
-P in ipsec esp/tunnel/1.2.3.4-5.6.7.8/unique;
Things to notice:
The pattern is exactly the same, but what was defined as "-P out"
on the other gateway shows up as "-P in" on this gateway, and
vice-versa.
This configuration is sufficient to define the necessary SA prototypes,
but in order to negotiate keys and parameters, you need IKE, and for
that you need the ipsec-tools port, in order to get racoon(8).
Just as each gateway has its own tailored ipsec.conf, each gateway also
has its own racoon.conf. There is of course more than one way to set up
an IKE daemon. These are the settings that I use.
Gateway 1's racoon.conf:
# This is racoon.conf
# Loaded by racoon when it starts, or when receiving a HUP.
log notify; # notify(*), debug, debug2
path pre_shared_key "/etc/ipsec.keys";
path pidfile "/var/run/racoon.pid";
listen
{
isakmp 1.2.3.4;
strict_address; # Needed?
}
remote 5.6.7.8
{
exchange_mode aggressive,main,base;
my_identifier address 1.2.3.4;
peers_identifier address 5.6.7.8;
verify_identifier off;
proposal_check claim; # obey, strict, claim(*), exact(*)
proposal
{
encryption_algorithm aes;
hash_algorithm sha1;
authentication_method pre_shared_key;
dh_group 2;
lifetime time 24 hours;
}
}
sainfo address 192.168.1.0/24 any address 192.168.11.0/24 any
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
sainfo address 192.168.2.0/24 any address 192.168.11.0/24 any
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
sainfo address 192.168.1.0/24 any address 192.168.12.0/24 any
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
sainfo address 192.168.2.0/24 any address 192.168.12.0/24 any
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
sainfo address 192.168.11.0/24 any address 192.168.1.0/24 any
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
sainfo address 192.168.11.0/24 any address 192.168.2.0/24 any
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
sainfo address 192.168.12.0/24 any address 192.168.1.0/24 any
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
sainfo address 192.168.12.0/24 any address 192.168.2.0/24 any
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
Things to notice:
Some people feel aggressive mode is not as secure. If you don't
like it, remove it.
There should be one "remote" section for each gateway that you
converse with.
In my config, I specify IP's as identifiers. I am not sure if this
is actually necessary, which is why I turn verification off. I have
not tested this portion strongly, but the config does work.
The main use of proposal_check is to decide what to do when the two
gateways do not agree on lifetime parameters. It is best for the
gateways to never disagree, of course. :)
The proposal section sets encryption and verification parameters
for Phase 1 of IKE, where the gateways first establish trust. My
config uses pre-shared secrets. I have not (yet) experimented with
certificate-based authentication.
The "sainfo" sections duplicate the information found in ipsec.conf.
For every SA, there needs to be an "sainfo" section describing the
exact same pair of networks. Yes, it is cumbersome. I have wished
that racoon could just read the information out of the kernel, but I
believe the problem is that the kernel only keeps track of networks
that match SA's. The other parameters (lifetime, encryption, etc)
are not stored anywhere else. They come from racoon negotiating
these parameters with the remote system.
If you are really lucky, and all your tunnels use exactly the same
encryption parameters, you could instead use a single "anonymous"
sainfo section like so:
sainfo anonymous
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
This will avoid a lot of repetitive data entry. However, if you
have different tunnels with different peers who want different
parameters, you will have to specify them explicitly.
Yes, you must specify the compression algorithm, even if you are not
going to use compression. Racoon demands it.
Gateway 2's racoon.conf:
# This is racoon.conf
# Loaded by racoon when it starts, or when receiving a HUP.
log notify; # notify(*), debug, debug2
path pre_shared_key "/etc/ipsec.keys";
path pidfile "/var/run/racoon.pid";
listen
{
isakmp 5.6.7.8;
strict_address; # Needed?
}
remote 1.2.3.4
{
exchange_mode aggressive,main,base;
my_identifier address 5.6.7.8;
peers_identifier address 1.2.3.4;
verify_identifier off;
proposal_check claim; # obey, strict, claim(*), exact(*)
proposal
{
encryption_algorithm aes;
hash_algorithm sha1;
authentication_method pre_shared_key;
dh_group 2;
lifetime time 24 hours;
}
}
sainfo address 192.168.1.0/24 any address 192.168.11.0/24 any
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
sainfo address 192.168.2.0/24 any address 192.168.11.0/24 any
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
sainfo address 192.168.1.0/24 any address 192.168.12.0/24 any
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
sainfo address 192.168.2.0/24 any address 192.168.12.0/24 any
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
sainfo address 192.168.11.0/24 any address 192.168.1.0/24 any
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
sainfo address 192.168.11.0/24 any address 192.168.2.0/24 any
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
sainfo address 192.168.12.0/24 any address 192.168.1.0/24 any
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
sainfo address 192.168.12.0/24 any address 192.168.2.0/24 any
{
lifetime time 1 hour;
encryption_algorithm aes;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}
Things to notice:
Yes, this file is almost exactly the same, with the IP's swapped.
What is local here is remote there, and vice-versa. The "sainfo"
sections must be left unchanged. If they were different, the two
racoons would not agree on parameter negotiations, and would fail to
negotiate a tunnel.
Finally, you must specify the keys. Each gateway needs to define the
keys used on the other gateways.
Gateway 1's ipsec.keys:
# Keys for IKE
5.6.7.8 SECRET_KEY
Gateway 2's ipsec.keys:
# Keys for IKE
1.2.3.4 SECRET_KEY
Things to notice:
Each gateway has keys defined for OTHER gateways. The OTHER gateway
has to have the SAME key defined for THIS gateway.
This ipsec.keys file MUST BE PROTECTED. If you do not have it set
to permissions 0600, racoon will silently IGNORE the file, and your
IKE negotiation will fail, and there will be no indication in the
logs as to why. Check your permissions!
With these parameters a pair of gateways should be able to establish
IPSEC sessions with each other, even if the other gateway is some other
standards-compliant IPSEC implementation, such as found on Cisco or
Checkpoint devices. I have tested specifically with those
implementations, and have had no problems.
I suppose I should talk about PF. All my gateways use PF, so I have not
tested with any other firewall methods such as ipfw.
You must certainly allow your gateways to speak IKE and ESP to each
other if you want them to work. I use a table called IPSEC_PEERS which
I load with the IP's of my peer gateways, and then I use these rules to
pass traffic:
EXTIP="(fxp0)"
pass in quick proto udp from <IPSEC_PEERS> to $EXTIP port 500 keep state
pass in quick proto esp from <IPSEC_PEERS> to $EXTIP keep state
pass out quick from self keep state
I am not convinced that "keep state" is needed or even useful here,
since neither UDP nor ESP are stateful protocols, and even if PF did not
keep state the traffic would still be allowed anyway.
An interesting side effect of IPSEC is that PF cannot track the full
state of it ("enc0" patches notwithstanding). Traffic arrives on an
internal interface, and then if it becomes encrypted, the traffic
"mysteriously disappears" as far as PF can tell. The traffic never goes
out another interface. However, reply traffic from the other side of
the tunnel does magically "appear" from nowhere.
A typical gateway will have an "outbound" rule like this:
pass in quick on { $INT } all keep state
where $INT defines the interfaces on the internal side. Since "keep
state" is specified, reply traffic from the external net will have no
trouble coming back in.
However, VPN traffic does not come in through the external network... at
least, not in any way that PF can determine. The traffic comes in as
seemingly-unrelated ESP, is decrypted in the kernel, then magically
appears decrypted on the internal interface for the first time. Your
firewall will not understand this and will block the traffic unless you
add a rule like this:
# VPN traffic appears here...?
pass out quick on { $INT } to $INT:network keep state
So, traffic appearing suddenly on an internal interface, destined for an
internal network, is permitted, on the assumption that it must have come
from an external VPN.
Naturally you can (and probably should) set up much more prohibitive
rules, but keep in mind that the first chance you will have to sense
inbound VPN traffic is when it is headed OUTBOUND on your INTERNAL
interfaces.
- --
David DeSimone == Network Admin == fox at verio.net
"It took me fifteen years to discover that I had no
talent for writing, but I couldn't give it up because
by that time I was too famous. -- Robert Benchley
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)
iD8DBQFEm4idFSrKRjX5eCoRAkFEAJ9QCbodDJUvwG3RG0fuQTXlKRX2dwCbBUhG
Q2QZv3RX582uXHSwBeyQuUk=
=LxYq
-----END PGP SIGNATURE-----
More information about the freebsd-net
mailing list