XFRM interfaces with VRF-based multitenant IPsec
This example configures a multitenant IPsec setup:
- use strongSwan for IPsec setup
- use VLAN subinterfaces for inside VRF access
- XFRM interfaces to connect IPsec tunnels with the VRFs (requires Linux kernel 4.19+)
interfaces:
# external interface for IPsec termination
outside:
addresses:
- 198.51.100.2/31
link:
state: up
kind: physical
identify:
perm_address: 00:50:56:ad:db:ac
# inside base interface
trunk:
link:
kind: physical
state: up
identify:
perm_address: 8c:16:45:dc:b1:ad
# first tenant VRF
vrf-tenant1:
link:
state: up
kind: vrf
vrf_table: 101
ipsec-tenant1:
link:
state: up
kind: xfrm
xfrm_link: outside
xfrm_if_id: 1
master: vrf-tenant1
inside-tenant1:
addresses:
- 192.0.2.1/24
link:
state: up
kind: vlan
link: trunk
vlan_id: 41
master: vrf-tenant1
# second tenant VRF
vrf-tenant2:
link:
state: up
kind: vrf
vrf_table: 102
ipsec-tenant2:
link:
state: up
kind: xfrm
xfrm_link: outside
xfrm_if_id: 2
master: vrf-tenant2
inside-tenant2:
addresses:
- 192.0.2.1/24
link:
state: up
kind: vlan
link: trunk
vlan_id: 42
master: vrf-tenant2
routing:
routes:
# outside default route
- to: 0.0.0.0/0
via: 198.51.100.1
# first tenant VRF: add default route into vpn
- to: 0.0.0.0/0
dev: ipsec-tenant1
table: 101
# second tenant VRF: add default route into vpn
- to: 0.0.0.0/0
dev: ipsec-tenant2
table: 102
{
networking.ifstate = {
enable = true;
settings = {
interfaces = {
# external interface for IPsec termination
outside = {
addresses = [ "198.51.100.2/31" ];
link = {
state = "up";
kind = "physical";
};
identify.perm_address = "00:50:56:ad:db:ac";
};
# inside base interface
trunk = {
link = {
kind = "physical";
state = "up";
};
identify.perm_address = "8c:16:45:dc:b1:ad";
};
# first tenant VRF
vrf-tenant1 = {
link = {
state = "up";
kind = "vrf";
vrf_table = 101;
};
};
ipsec-tenant1 = {
link = {
state = "up";
kind = "xfrm";
xfrm_link = "outside";
xfrm_if_id = 1;
master = "vrf-tenant1";
};
};
inside-tenant1 = {
addresses = [ "192.0.2.1/24" ];
link = {
state = "up";
kind = "vlan";
link = "trunk";
vlan_id = 41;
master = "vrf-tenant1";
};
# second tenant VRF
vrf-tenant2 = {
link = {
state = "up";
kind = "vrf";
vrf_table = 102;
};
};
ipsec-tenant2 = {
link = {
state = "up";
kind = "xfrm";
xfrm_link = "outside";
xfrm_if_id = 2;
master = "vrf-tenant2";
};
};
inside-tenant2 = {
addresses = [ "192.0.2.1/24" ];
link = {
state = "up";
kind = "vlan";
link = "trunk";
vlan_id = 42;
master = "vrf-tenant2";
};
};
};
};
routing = {
routes = [
# outside default route
{
to = "0.0.0.0/0";
via = "198.51.100.1";
}
# first tenant VRF: add default route into vpn
{
to = "0.0.0.0/0";
dev = "ipsec-tenant1";
table = 101;
}
# second tenant VRF: add default route into vpn
{
to = "0.0.0.0/0";
dev = "ipsec-tenant2";
table = 102;
}
];
};
};
};
}
strongSwan
To make strongSwan VRF aware you must use swanctl. It is not possible to use the classic ipsec.conf with XFRM interfaces. A swanctl configuration might look like:
#
# IPsec tunnel for tenant1
#
connections {
# Section for an IKE connection named <conn>.
tentant1 {
# IKE major version to use for connection.
version = 2
# Local address(es) to use for IKE communication, comma separated.
local_addrs = 198.51.100.2
# Remote address(es) to use for IKE communication, comma separated.
remote_addrs = 203.0.113.1
# Default inbound XFRM interface ID for children.
if_id_in = 1
# Default outbound XFRM interface ID for children.
if_id_out = 1
# Section for a local authentication round.
local {
auth = psk
}
# Section for a remote authentication round.
remote {
auth = psk
}
children {
# CHILD_SA configuration sub-section.
tenant1 {
# Local traffic selectors to include in CHILD_SA.
local_ts = 192.0.2.0/24
# Remote selectors to include in CHILD_SA.
remote_ts = 0.0.0.0/0
}
}
}
}
#
# IPsec tunnel for tenant2
#
connections {
# Section for an IKE connection named <conn>.
tentant2 {
# IKE major version to use for connection.
version = 2
# Local address(es) to use for IKE communication, comma separated.
local_addrs = 198.51.100.2
# Remote address(es) to use for IKE communication, comma separated.
remote_addrs = 203.0.113.1
# Default inbound XFRM interface ID for children.
if_id_in = 2
# Default outbound XFRM interface ID for children.
if_id_out = 2
# Section for a local authentication round.
local {
auth = psk
}
# Section for a remote authentication round.
remote {
auth = psk
}
children {
# CHILD_SA configuration sub-section.
tenant1 {
# Local traffic selectors to include in CHILD_SA.
local_ts = 192.0.2.0/24
# Remote selectors to include in CHILD_SA.
remote_ts = 0.0.0.0/0
}
}
}
}