StrongSwan can use RADIUS as an authentication backend. In case the RADIUS service also returns group membership information it becomes possible for the IKE server to also choose the VPN configuration based on the membership information.
StrongSwan
EAP-RADIUS,
as documented in the projects WIKI, describes how to use a RADIUS backend in the
StrongSwan VPN server. I find enabling RADIUS quite simple. All it takes is
adding the RADIUS server and its secret to the eap-radius
configuration
section of the IKE service charon
.
A little further down at the section
Group
Selection the documentation says that charon
will honor the Class
attribute in a
RADIUS reply, provided the class_group
option is set to yes
. So my complete
config eap-radius.conf
looks like:
eap-radius {
class_group = yes
load = yes
secret = testing123
server = 192.2.0.12
}
The RADIUS Configuration
I use FreeRADIUS as server. For a first test, I just add two users to the
users
file:
user1 Cleartext-Password := "password1"
Class = "sales"
user2 Cleartext-Password := "password2"
Class = "admins"
Since StrongSwan will authenticate with EAP also the TLS stuff, i.e. CA, server certificate and key has to be set up. Please refer to the FreeRADIUS documentation how to configure that part. Also the StrongSwan server has to be added to the clients that are allowed to use the RADIUS service.
After starting the freeradius
daemon, the RADIUS service is ready to
authenticate incoming requests.
StrongSwan Configuration
The StrongSwan project offers example configurations for nearly every setup you can think of. The scenario I use is described in IKEv2-EAP-TTLS-RADIUS. Thus the configuration of my VPN gateway looks like this:
conn admins
left=192.2.0.1
leftsubnet=192.2.0.0/24
leftcert=server-cert.pem
leftauth=pubkey
leftfirewall=yes
leftsendcert=always
#
right=%any
rightsourceip=198.51.100.0/25
rightid=%any
rightsendcert=never
rightauth=eap-radius
rightgroups="admins"
#
fragmentation=yes
auto=add
conn sales
left=192.2.0.1
leftsubnet=192.2.0.0/24
leftcert=server-cert.pem
leftauth=pubkey
leftfirewall=yes
leftsendcert=always
#
right=%any
rightsourceip=198.51.100.128/25
rightid=%any
rightsendcert=never
rightauth=eap-radius
rightgroups="sales"
#
fragmentation=yes
auto=add
The configuration checks the Class
attribute from the reply of the RADIUS
server. The VPN server assigns IP addresses to the clients depending on their
group (better Class
) membership. With firewall rules in place separate
policies could be applied for the both groups.
The important part of the VPN log of a connection of the user1
of the sales
team looks like:
charon: 06[IKE] authentication of 'user1' with EAP successful
charon: 06[CFG] constraint check failed: group membership to 'admins' required
charon: 06[CFG] selected peer config 'admins' inacceptable: non-matching authentication done
charon: 06[CFG] switching to peer config 'sales'
charon: 06[IKE] authentication of <server id> (myself) with EAP
charon: 06[IKE] IKE_SA sales[4] established between 192.2.0.1[<server id>]...93.104.100.218[user1]
charon: 06[IKE] peer requested virtual IP %any
charon: 06[IKE] assigning virtual IP 198.51.100.129 to peer 'user1'
charon: 06[IKE] CHILD_SA sales{3} established with SPIs c63a699b_i 362e33a9_o and TS 192.2.0.0/24 === 198.51.100.129/32
The user was authenticated successfully from the RADIUS server, but the Class
does not match. So charon looks for the next connection where the sales
definition matches. So the user gets an IP address from that pool.
Group attributes from LDAP
The LDAP module of FreeRADIUS also provides a section for group lookup.
Depending on the organization of your LDAP you have to adjust the options in the
configuration of the group section, especially the membership_filter
or
membership_attribute
.
Since the LDAP-Group
is no ordinary RADIUS attribute, you have to enable
caching. While FreeRADIUS searches for the user it also looks for the group
memberships and adds it to the LDAP-Group
attribute array. In my case I want
to have the group name, so I set cacheable_name = 'yes'
in the user section of
the ldap module.
After authorization the LDAP-Group
attribute array contains the list of groups
the user is included. In the post-auth
section of a server I can set the
Class
attribut.
switch &control:LDAP-Group[*] {
case "admins" {
update reply {
Class = "admins"
}
}
case "sales" {
update reply {
Class = "sales"
}
}
}
I have to use the switch / case structure since a user can be member of multiple
groups. So the LDAP-Group
might be an array, not a single value. If the VPN
groups are of a specific form, like "vpn-*", you also could have such a
construction:
if ( &control:LDAP-Group[*] =~ /^vpn-.*/ ) { update reply { Class = "%{0}" } }
The =~
operator checks for a regular expression. Only the entries that fit
remain in the list and the first element in that list is assigned to the Class
attribute.
For the sake of clarity of the server configuration you could move this mapping
in the post-auth
section into a policy.
Please mail me if you have questions or improvements to ms@sys4.de.