Freeradius, Dynamic VLANs, and Google LDAP
This tutorial is based on Ubuntu 18.04. Here, we will install FreeRadius and connect it to Google Workspace Secure LDAP. Then, we will assign VLANs to users based on their groupings in Google Workspace.
Google Workspace Secure LDAP Setup
In the Google Admin Console, go to Apps > LDAP. Click on ADD LDAP CLIENT.
Give the client a name and description.
Set the following access permissions:
Verify user credentials: Entire domain
Read user information: Entire domain
Read group information: On
Click on the ADD LDAP CLIENT button.
At this point, you can download the certificate if desired, otherwise leave it for later and click CONTINUE TO CLIENT DETAILS.
The next screen shows the settings for you new LDAP client. Click on the Authentication section.
If you haven't already, download the certificate zip file. Extract the .crt and .key file and save them for later.
Click on GENERATE NEW CREDENTIALS. Make note of the username and password. Be sure to copy the password now because it will no longer be available after closing the credential popup. Create new credentials if necessary.
Keep the .crt and .key files, as well as the access credentials, for the Freeradius setup.
Installing Freeradius
On an existing Ubuntu 18.04 installation, install Freeradius: sudo apt install freeradius freeradius-ldap
Copy the .crt and .key files into the /etc/freeradius/3.0/certs folder. In this example, we'll rename the .crt and .key files to google.crt and google.key for simplicity:
sudo cp /path/to/.crt /etc/freeradius/3.0/certs/google.crt
sudo cp /path/to/.key /etc/freeradius/3.0/certs/google.key
These are the freeradius files that need to be modified:
/etc/freeradius/3.0/mods-available/ldap
/etc/freeradius/3.0/mods-available/eap
/etc/freeradius/3.0/sites-available/default
/etc/freeradius/3.0/sites-available/inner-tunnel
/etc/freeradius/3.0/clients.conf
Optional: /etc/freeradius/3.0/proxy.conf
/etc/freeradius/3.0/mods-config/files/authorize
Modifying Freeradius
Editing /etc/freeradius/3.0/mods-available/ldap
In the ldap section, modify the following lines:
server 'ldaps://ldap.google.com:636'
identity = username from access credentials
password = password from access credentials
base_dn = 'dc=domain,dc=com'
comment out the line description := "Authenticated as %S" in the section 'ldap -> post-auth -> update' so it appears as follows:
post-auth {
update {
#description := "Authenticated at %S"
}
}
In the tls section, modify the following lines:
start_tls = no
certificate_file = /etc/freeradius/3.0/certs/google.crt
private_key_file = /etc/freeradius/3.0/certs/google.key
require_cert = 'allow'
Save and exit the file. Next, symlink the file to mods-enabled:
sudo ln -s /etc/freeradius/3.0/mods-available/ldap /etc/freeradius/3.0/mods-enabled/ldap
Editing /etc/freeradius/3.0/mods-available/eap
First, create a certificate authority, then generate the server.key and server.crt files, as well as the ca.pem. The easiest way to get these files is to have freeradius generate the files. To do this, modify the .cnf files in /etc/freeradius/3.0/certs. Change the info for:
default_days
input_password
output_password
all the stuff in the [server] and [certificate_authority] sections of server.cnf, client.cnf and ca.cnf, respectively
Then issue the make command inside /etc/freeradius/3.0/certs/
Download ca.der (certificate authority) for installation on client devices.
Change ownership of new files to freerad
sudo chown freerad:freerad /etc/freeradius/3.0/certs/*
In the eap section, modify the following lines:
default_eap_type = ttls
Enter the .key, .crt, and .pem in the tls-config tls-common section.
private_key_password = [whatever password you created]
private_key_file = /path/to/server.key
certificate_file = /path/to/server.crt
ca_file = /path/to/ca.pem
Comment out the disable_tls lines:
#disable_tlsv1_2 = no
#disable_tlsv1_1 = yes
#disable_tlsv1 = yes
Set tls_min_version and tls_max_version to your preferred version numbers.
Editing /etc/freeradius/3.0/sites-available/default
In the authorize section, enable LDAP by removing the "-" sign before it so it looks like:
#
# The ldap module reads passwords from the LDAP database.
ldap
In the authorize section, before the password authentication protocol (PAP) statement, add an if statement so it looks like:
# This module should be listed last, so that the other modules
# get a chance to set Auth-Type for themselves.
#
if (User-Password ) {
update control {
Auth-Type := ldap
}
}
pap
**This section is no longer necessary.** In the authenticate section, modify the Auth-Type PAP block as follows:
Auth-Type PAP {
# pap
ldap
}
**End unnecessary section**
In the authenticate section, modify the Auth-Type LDAP block as follows:
# Auth-Type LDAP {
ldap
# }
Editing /etc/freeradius/3.0/sites-available/inner-tunnel
Perform the same steps as in /etc/freeradius/3.0/sites-available/default
In the authorize section, uncomment filter_inner_identity. This will provide the ability to match outer/inner User-Name so that users can't offer anonymous names.
In the post-auth section, uncomment the following lines to prevent Windows clients showing up as anonymous:
update outer.session-state {
User-Name := &User-Name
}
In the post-auth section, find the block that starts with if (0) and change it to if (1) as shown below:
# Instead of "use_tunneled_reply", change this "if (0)" to an
# "if (1)".
#
if (1) {
#
# These attributes are for the inner-tunnel only,
# and MUST NOT be copied to the outer reply.
#
update reply {
User-Name !* ANY
Message-Authenticator !* ANY
EAP-Message !* ANY
Proxy-State !* ANY
MS-MPPE-Encryption-Types !* ANY
MS-MPPE-Encryption-Policy !* ANY
MS-MPPE-Send-Key !* ANY
MS-MPPE-Recv-Key !* ANY
}
#
# Copy the inner reply attributes to the outer
# session-state list. The post-auth policy will take
# care of copying the outer session-state list to the
# outer reply.
#
update {
&outer.session-state: += &reply:
}
}
Editing /etc/freeradius/3.0/clients.conf
Add the following block to have the freeradius server accept requests from your lan. Modify the client name, IP block, and secret.
client mylan {
ipaddr = 192.168.0.0/24
secret = [your radius secret]
}
Editing /etc/freeradius/3.0/proxy.conf
Optional: This is a useful setting if you want your RADIUS server to serve multiple domains or subdomains. Create a realm, then point it at the specific Auth-Type which controls that realm. Alternatively, this can use used to require users to type in their full email address as their username. An example is shown below.
realm domain.com {
Auth-Type := domain
}
realm subdomain.domain.com {
Auth-Type := subdomain
}
At this point, we have made the necessary modifications to use Freeradius with Google Workspace Secure LDAP. Restart Freeradius:
sudo systemctl restart freeradius
Test a user:
radtest [username]@[domain.com] [userpassword] localhost 0 testing 123
If everything is set up correctly, you should receive the following response from freeradius:
Received Access-Accept Id 68 from 127.0.0.1:1812 to 0.0.0.0:0 length 20
Editing /etc/freeradius/3.0/mods-config/files/authorize
This file is used to attach VLAN information to the user account based on certain criteria. This first example will assign a specific VLAN ID to all users who have an organizational account. This is useful if you don't need to separate users from each other based on user type:
DEFAULT Ldap-UserDN := "uid=%{User-Name},ou=Users,dc=domain,dc=com"
Tunnel-Type = VLAN,
Tunnel-Medium-Type = IEEE-802,
Tunnel-Private-Group-Id = "100"
The following set of modifications makes the assumption that you have groups created in Google Workspace and the users are in the group individually, not using shortcut entries such as "All users in the organization". In the following example, there are 3 groups with their respective group email addresses: group1@domain.com (VLAN 10), group2@domain.com (VLAN 30), and group3@domain.com (VLAN 50). A catch-all entry is shown at the end to place users that are not otherwise assigned to a group. Place this block of code at the top of /etc/freeradius/3.0/mods-config/files/authorize.
DEFAULT Ldap-Group == "cn=group1,ou=Groups,dc=domain,dc=com"
Tunnel-Type = VLAN,
Tunnel-Medium-Type = IEEE-802,
Tunnel-Private-Group-Id = "10"
DEFAULT realm == "domain.com", Ldap-Group == "cn=group2,ou=Groups,dc=domain,dc=com"
Tunnel-Type = VLAN,
Tunnel-Medium-Type = IEEE-802,
Tunnel-Private-Group-Id = "30"
DEFAULT realm == "domain.com", Ldap-Group == "cn=group3,ou=Groups,dc=domain,dc=com"
Tunnel-Type = VLAN,
Tunnel-Medium-Type = IEEE-802,
Tunnel-Private-Group-Id = "50"
DEFAULT Ldap-UserDN := "uid=%{User-Name},ou=Users,dc=domain,dc=com"
Tunnel-Type = VLAN,
Tunnel-Medium-Type = IEEE-802,
Tunnel-Private-Group-Id = "50"
The realm == "domain.com" portion above is optional and is useful for multiple domains or for requiring users to type their entire email address as their username. If you modified proxy.conf, you should consider matching the realms here.
Save the file, then restart freeradius:
sudo systemctl restart freeradius
Let's assume we have an account of testuser@domain.com with a password of "sh3k6cy" who is part of group1. Perform a radtest:
radtest testuser@domain.com sh3k6cy localhost 0 testing123
The radtest should produce the following result showing Access-Accept and the Tunnel-Private-Group-ID, which is the VLAN assignment for the user:
Sent Access-Request Id 214 from 0.0.0.0:40001 to 127.0.0.1:1812 length 115
User-Name = "testuser@domain.com"
User-Password = "sh3k6cy"
NAS-IP-Address = 127.0.1.1
NAS-Port = 0
Message-Authenticator = 0x00
Cleartext-Password = "sh3k6cy"
Received Access-Accept Id 214 from 127.0.0.1:1812 to 0.0.0.0:0 length 36
Tunnel-Type:0 = VLAN
Tunnel-Medium-Type:0 = IEEE-802
Tunnel-Private-Group-Id:0 = "10"