FreeRADIUS Installation and Configuration on Ubuntu Server 24.04 (OpenLDAP)¶
Based on IAM by LANKA (Lanka Education and Research Network) (learn@learn.ac.lk)
1. Prerequisites¶
- 1.1 Minimum System Requirements:
- 4GB or more for small to medium deployments.
- Quad-core or higher with a minimum clock speed of 2.0 GHz.
- At least 50GB of free disk space.
- Ports allowed (tcp/80, tcp/443, udp/1812, udp/1813)
2. Update your server and install curl¶
sudo apt update
sudo apt upgrade
sudo apt install curl
3. Install Repo from NetworkRADIUS¶
To install FreeRADIUS 3.2 on Ubuntu noble 24.04, Add the NetworkRADIUS PGP public key:
install -d -o root -g root -m 0755 /etc/apt/keyrings
curl -s 'https://packages.networkradius.com/pgp/packages%40networkradius.com' | \
sudo tee /etc/apt/keyrings/packages.networkradius.com.asc > /dev/null
Add an APT preferences file to ensure all freeradius packages are installed from the Network RADIUS repository:
printf 'Package: /freeradius/\nPin: origin "packages.networkradius.com"\nPin-Priority: 999\n' | \
sudo tee /etc/apt/preferences.d/networkradius > /dev/null
Add the APT sources list:
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/packages.networkradius.com.asc] http://packages.networkradius.com/freeradius-3.2/ubuntu/noble noble main" | \
sudo tee /etc/apt/sources.list.d/networkradius.list > /dev/null
Finally, update the APT database and install the packages:
sudo apt update
4. Install Packages¶
You need to become root by sudo su
and proceed.
sudo apt install freeradius
sudo apt install git libssl-dev devscripts pkg-config libnl-3-dev libnl-genl-3-dev
5. Modify Users for testing¶
Next, sudo vim /etc/freeradius/users
and modify to enable bob and test realm user
#
#bob Cleartext-Password := "hello"
# Reply-Message := "Hello, %{User-Name}"
#
eduroamtest Cleartext-Password := "EduTestP@33"
####
After the user modification following radtests should succeed.
sudo systemctl restart freeradius.service
radtest -t mschap -x eduroamtest EduTestP@33 127.0.0.1:1812 10000 testing123
6. Build eapol tool for testing¶
git clone --depth 1 --single-branch https://github.com/FreeRADIUS/freeradius-server.git
cd freeradius-server/scripts/ci/
./eapol_test-build.sh
sudo cp ./eapol_test/eapol_test /usr/local/bin/
You can now test the above radius local user authentication with eapol_test as below. For eapol_test command you need to create a configuration file which describes the network connection properties. Let's create a configuration file.
cd /etc/freeradius
sudo vim peap-mschapv2-local.conf
Add the below code,
network={
ssid="eduroam"
key_mgmt=WPA-EAP
eap=PEAP
identity="eduroamtest"
# anonymous_identity="@eduroam.gh"
password="EduTestP@33"
phase2="auth=MSCHAPV2"
# Uncomment the following to perform server certificate validation.
# ca_cert="/etc/raddb/certs/ca.der"
}
And execute the eapol_test as below,
eapol_test -c peap-mschapv2-local.conf -p 1812 -s testing123
If the authentication is successful you should recieve at the end,
MPPE keys OK: 1 mismatch: 0
SUCCESS
7. Freeradius Settings¶
Go to install location and do the changes.
cd /etc/freeradius/
sudo mv mods-config/attr_filter/pre-proxy mods-config/attr_filter/pre-proxy.orig
sudo mv mods-config/attr_filter/post-proxy mods-config/attr_filter/post-proxy.orig
Edit the file pre-proxy
with following content:
sudo vim mods-config/attr_filter/pre-proxy
DEFAULT
User-Name =* ANY,
EAP-Message =* ANY,
Message-Authenticator =* ANY,
NAS-IP-Address =* ANY,
NAS-Identifier =* ANY,
State =* ANY,
Proxy-State =* ANY,
Calling-Station-Id =* ANY,
Called-Station-Id =* ANY,
Operator-Name =* ANY,
Class =* ANY,
Chargeable-User-Identity =* ANY
Edit the file post-proxy
with following content:
sudo vim mods-config/attr_filter/post-proxy
DEFAULT
Framed-IP-Address == 255.255.255.254,
Framed-IP-Netmask == 255.255.255.255,
Framed-MTU >= 576,
Framed-Filter-ID =* ANY,
Reply-Message =* ANY,
Proxy-State =* ANY,
EAP-Message =* ANY,
Message-Authenticator =* ANY,
MS-MPPE-Recv-Key =* ANY,
MS-MPPE-Send-Key =* ANY,
MS-CHAP-MPPE-Keys =* ANY,
State =* ANY,
Session-Timeout <= 28800,
Idle-Timeout <= 600,
Calling-Station-Id =* ANY,
Operator-Name =* ANY,
Port-Limit <= 2,
User-Name =* ANY,
Class =* ANY,
Chargeable-User-Identity =* ANY
Backup the eap module configuration file as follows,
sudo mv mods-available/eap mods-available/eap.orig
sudo vim mods-available/eap
Now modify the configuration file to make the below changes. Don't delete any additional configurations not show below. Also some of the below configurations also might be the same as them in your configuration file, hence need to change the selected parts only.
eap {
default_eap_type = peap # change to your organisation's preferred eap type (tls, ttls, peap, mschapv2)
timer_expire = 60
ignore_unknown_eap_types = no
cisco_accounting_username_bug = no
tls-config tls-eduroam {
#private_key_password = whatever
private_key_file = ${certdir}/server.pem
certificate_file = ${certdir}/server.pem
ca_file = ${cadir}/ca.pem
#dh_file = ${certdir}/dh
random_file = /dev/urandom
fragment_size = 1024
include_length = yes
check_crl = no
cipher_list = "DEFAULT"
}
tls {
tls = tls-eduroam
}
ttls {
tls = tls-eduroam
default_eap_type = mschapv2
copy_request_to_tunnel = yes
use_tunneled_reply = yes
virtual_server = "eduroam-inner-tunnel"
}
peap {
tls = tls-eduroam
default_eap_type = mschapv2
copy_request_to_tunnel = yes
use_tunneled_reply = yes
virtual_server = "eduroam-inner-tunnel"
}
mschapv2 {
# send_error = yes
}
}
You need to modify the linelog module as follows too,
sudo vim mods-enabled/linelog
Modify the following lines containing Access-Accept
and Access-Reject
Access-Accept = "%T eduroam-auth#ORG=%{request:Realm}#USER=%{User-Name}#CSI=%{%{Calling-Station-Id}:-Unknown Caller Id}#NAS=%{%{Called-Station-Id}:-Unknown Access Point}#NAS-IP=%{%{NAS-IP-Address}:-Unknown}#OPERATOR=%{%{Operator-Name}:-Unknown}#CUI=%{%{reply:Chargeable-User-Identity}:-Unknown}#RESULT=OK#"
Access-Reject = "%T eduroam-auth#ORG=%{request:Realm}#USER=%{User-Name}#CSI=%{%{Calling-Station-Id}:-Unknown Caller Id}#NAS=%{%{Called-Station-Id}:-Unknown Access Point}#NAS-IP=%{%{NAS-IP-Address}:-Unknown}#OPERATOR=%{%{Operator-Name}:-Unknown}#CUI=%{%{reply:Chargeable-User-Identity}:-Unknown}#MSG=%{%{reply:Reply-Message}:-No Failure Reason}#RESULT=FAIL#"
Chargeable-User-Identity (CUI) is a non-human readable (“opaque”) cryptographic hash that is targeted to the service provider. Each service provider therefore receives a different opaque value for the same user. This allows service providers to recognize a user as one that they have seen before, without knowing who the user is; while preventing service providers from colluding to track users. This enables legitimate purposes, such as blocking malfunctioning devices and generating accurate usage statistics. The CUI value is computed as a SHA1 hash of concatenated (inner) User-Name, optional Operator-Name and a local salt value. This salt is random string and we have to set this salt in the cui_hash_key attribute.
Run the command below to generate a 16-byte (128-bit) salt in base64
openssl rand -base64 16
Modify the cui policy as follows,
sudo vim policy.d/cui
cui_hash_key = "SOMELONGCHARACTERstring"
cui_require_operator_name = "yes"
8. Creating Certificates¶
Certificates can be obtained using a service like LetsEncrypt or Commercial provider. We can also create certificates using a private CA.You need to only follow a one method.
Method 1: Create certificates using LetsEncrypt¶
Install the certbot
utility from LetsEncrypt. On Debian it can be installed from the default repositories:
apt-get install certbot
Add a group for the certificate and key files, and then add the FreeRADIUS user to this group so that FreeRADIUS can read the certificate files:
addgroup certs
adduser freerad certs
Configure certbot
We will use a script to restart FreeRADIUS whenever certbot
renews the certificate. This script will also ensure that the permission are always set correctly on the certificate files, so that FreeRADIUS is able to read them.
Create a file /usr/local/sbin/certbot-post-hook
with the following contents:
#!/bin/sh
# Ensure certificates are in the correct group
chgrp -R certs /etc/letsencrypt/live /etc/letsencrypt/archive
chmod 750 /etc/letsencrypt/live /etc/letsencrypt/archive
# Restart FreeRADIUS
service freeradius restart
chmod +x /usr/local/sbin/certbot-post-hook
Generate the Certificate
The system is now ready to request a certificate from LetsEncrypt. We will be using the example FQDN of radius.example.com
here; replace this name with whatever name you have in your DNS, and which points to the public IP address of the RADIUS server.
nano mods-available/eap
private_key_file = /etc/letsencrypt/live/SERVER_FQDN/privkey.pem
certificate_file = /etc/letsencrypt/live/SERVER_FQDN/fullchain.pem
certbot certonly \
--standalone \
--cert-name radius.example.com \
-d radius.example.com
bash /usr/local/sbin/certbot-post-hook
Method 2: Create Certificates Using Private CA¶
By default, the FreeRADIUS installation generates certificates that are only valid for 60 days. To generate new certificates, follow these steps:
find /etc/freeradius/certs -type f ! -name "Makefile" ! -name "bootstrap" ! -name "ca.cnf" ! -name "client.cnf" ! -name "inner-server.cnf" ! -name "server.cnf" ! -name "xpextensions" ! -name "index.txt" -delete
The above command deletes everything in the cert folder except the following files:
- Makefile
- bootstrap
- ca.cnf
- client.cnf
- inner-server.cnf
- server.cnf
- xpextensions
cd /etc/freeradius/certs/
Populate the ca.cnf
with the following updates:
[CA_default]
# ...
default_days = 3650
default_crl_days = 3650
# ...
[req]
# ...
input_password = private-key-password-set-in-step-7-in-eap-configuration
output_password = private-key-password-set-in-step-7-in-eap-configuration
x509_extensions = v3_ca
# ...
[certificate_authority]
countryName = GH
stateOrProvinceName = Central
localityName = Somewhere
organizationName = Univerity of ABC
emailAddress = admin@YOUR_DOMAIN
commonName = "Univerity of ABC Certificate Authority"
[v3_ca]
#....
crlDistributionPoints = URI:http://server-fqdn/domain_ca.crl
Populate the client.cnf
with the following updates:
[CA_default]
# ...
default_days = 3650
default_crl_days = 3650
# ...
[req]
# ...
input_password = private-key-password-set-in-step-7-in-eap-configuration
output_password = private-key-password-set-in-step-7-in-eap-configuration
# ...
[client]
countryName = GH
stateOrProvinceName = Central
localityName = Somewhere
organizationName = University of ABC
emailAddress = wifiuser@abc.edu.gh
commonName = "Wifi User Client Certificate"
Populate the server.cnf
with the following updates:
[CA_default]
# ...
default_days = 3650
default_crl_days = 3650
# ...
[req]
# ...
input_password = private-key-password-set-in-step-7-in-eap-configuration
output_password = private-key-password-set-in-step-7-in-eap-configuration
# ...
[server]
countryName = GH
stateOrProvinceName = Central
localityName = Somewhere
organizationName = University of ABC
emailAddress = radius@abc.edu.gh
commonName = "radius.abc.edu.gh"
[alt_names]
DNS.1 = server-fqdn
otherName.0 = 1.3.6.1.5.5.7.8.8;FORMAT:UTF8,UTF8:*.YOUR-DOMAIN.edu.gh
Remove exisiting certificate generation entry in index.txt
to allow the generation of new certificates
Generate certificates by running the make command
make
chown freerad:freerad *
9. Sites Configurations¶
Create virtual server for eduroam as
cd /etc/freeradius/
sudo vim sites-available/eduroam
######################################################################
#
# Virtual Server Eduroam
#
######################################################################
server eduroam {
listen {
type = auth
ipaddr = *
port = 0
limit {
max_connections = 16
lifetime = 0
idle_timeout = 30
}
}
listen {
ipaddr = *
port = 0
type = acct
limit {
}
}
listen {
type = auth
ipv6addr = ::
port = 0
limit {
max_connections = 16
lifetime = 0
idle_timeout = 30
}
}
listen {
ipv6addr = ::
port = 0
type = acct
limit {
}
}
authorize {
preprocess
filter_username
if (("%{client:shortname}" != "FLR1")||("%{client:shortname}" != "FLR2")) {
update request {
Operator-Name := "1YOUR_DOMAIN"
# the literal number "1" above is an important prefix! Do not change it!
}
}
operator-name
cui
auth_log
suffix
eap {
ok = return
}
files
-ldap
}
authenticate {
eap
}
preacct {
suffix
}
accounting {
}
session {
}
post-auth {
update {
&reply: += &session-state:
}
reply_log
linelog
remove_reply_message_if_eap
Post-Auth-Type REJECT {
reply_log
linelog
}
}
pre-proxy {
# if you want detailed logging
cui
pre_proxy_log # logs the packet to the file system again. Attributes that have been added on during inspection are now visible
if("%{Packet-Type}" != "Accounting-Request") {
attr_filter.pre-proxy # removes unnecessary attributes off of the request before sending the request upstream
}
}
post-proxy {
# if you want detailed logging
post_proxy_log # logs the rply packet to the file system - as received by upstream
attr_filter.post-proxy # strips unwanted attributes off of the reply, prior to sending it back to the Access Points (VLAN attributes in particular)
}
}
Create virtual server for eduroam-inner-tunnel.
sudo vim sites-available/eduroam-inner-tunnel
######################################################################
#
# Virtual Server Eduroam-Inner-Tunnel
#
######################################################################
server eduroam-inner-tunnel {
listen {
ipaddr = 127.0.0.1
port = 18120
type = auth
}
authorize {
auth_log
suffix
update control {
&Proxy-To-Realm := LOCAL
}
eap {
ok = return
}
files
-ldap
mschap
pap
}
authenticate {
Auth-Type PAP {
pap
}
Auth-Type MS-CHAP {
mschap
}
eap
}
session {
radutmp
}
post-auth {
cui-inner
reply_log
Post-Auth-Type REJECT {
reply_log
attr_filter.access_reject
update outer.session-state {
&Module-Failure-Message := &request:Module-Failure-Message
}
}
}
pre-proxy {
}
post-proxy {
eap
}
}
Create vim sites-available/blackhole
for blackholing
server blackhole {
authorize {
reject
}
}
Next you need to enable the created virtual-server sites above and also remove the unwanted,
cd sites-enabled
rm default
rm inner-tunnel
ln -s ../sites-available/eduroam-inner-tunnel eduroam-inner-tunnel
ln -s ../sites-available/eduroam eduroam
ln -s ../sites-available/blackhole blackhole
Then modify proxy.conf
cd /etc/freeradius
sudo mv proxy.conf proxy.conf.orig
sudo vim proxy.conf
proxy server {
default_fallback = no
}
# Add your country's FLR details for the home_server {} attribute as shown below. port and status_check will not change.
# Add as many definitions as there are FLRs
home_server FLR2 {
ipaddr = 169.239.249.51
port = 1812
secret = secretthatmustbesharedwithGARNET
status_check = status-server
}
home_server FLR1 {
ipaddr = 197.255.124.73
port = 1812
secret = secretthatmustbesharedwithGARNET
status_check = status-server
}
realm LOCAL {
# If we do not specify a server pool, the realm is LOCAL, and
# requests are not proxied to it.
}
# eduroam home_server_pool attribute links from the home_server attribute. ensure home_server in home_server_pool matches home_server above
home_server_pool EDUROAM {
type = fail-over
home_server = FLR2
home_server = FLR1
}
# Your IdP realm
realm YOUR-DOMAIN.edu.gh {
nostrip #uncomment to remove striping of realm from username
}
# Catchall for unhandled realms
# redirect them to a blackhole server
#
home_server blackhole {
virtual_server = blackhole
}
home_server_pool blackhole_pool {
home_server = blackhole
name = blackhole
}
realm wlan.mnc000.mcc413.3gppnetwork.org{
auth_pool = blackhole_pool
}
realm wlan.mnc001.mcc413.3gppnetwork.org{
auth_pool = blackhole_pool
}
realm wlan.mnc002.mcc413.3gppnetwork.org{
auth_pool = blackhole_pool
}
realm wlan.mnc003.mcc413.3gppnetwork.org{
auth_pool = blackhole_pool
}
realm wlan.mnc004.mcc413.3gppnetwork.org{
auth_pool = blackhole_pool
}
realm wlan.mnc005.mcc413.3gppnetwork.org{
auth_pool = blackhole_pool
}
realm wlan.mnc006.mcc413.3gppnetwork.org{
auth_pool = blackhole_pool
}
realm wlan.mnc007.mcc413.3gppnetwork.org{
auth_pool = blackhole_pool
}
realm wlan.mnc008.mcc413.3gppnetwork.org{
auth_pool = blackhole_pool
}
realm wlan.mnc009.mcc413.3gppnetwork.org{
auth_pool = blackhole_pool
}
###########################################
# Proxy the rest
realm "~.+$" {
pool = EDUROAM
nostrip
}
Modify Clients
vim clients.conf
Add following to the tail
client Private-Network-1 {
ipaddr = 10.0.0.0/8
secret = verypowerfullsecret
nastype = other
}
client Private-Network-2 {
ipaddr = 172.16.0.0/12
secret = verypowerfullsecret
nastype = other
}
client Private-Network-3 {
ipaddr = 192.168.0.0/16
secret = verypowerfullsecret
nastype = other
}
client FLR2 {
ipaddr = 169.239.249.51
secret = secretthatmustbesharedwithGARNET
nas_type = other
Operator-Name = 1YOUR_DOMAIN
add_cui = yes
virtual_server = eduroam
}
client FLR1 {
ipaddr = 197.255.124.73
secret = secretthatmustbesharedwithGARNET
nas_type = other
Operator-Name = 1YOUR_DOMAIN
add_cui = yes
virtual_server = eduroam
}
Now restart the radius server.
sudo systemctl restart freeradius.service
After the restart, following tests should succeed.
eapol_test -c peap-mschapv2-local.conf -p 1812 -s testing123
You may also test some of the test roaming accounts provided by your National Upstream Radius Partner.
10. Enabling LDAP users¶
Install Freeradius LDAP module
sudo apt-get install freeradius-ldap
Configure LDAP parameters
sudo vim /etc/freeradius/mods-available/ldap
Copy ca_certs.pem from /etc/ldap/ located on the OpenLDAP server and upload to Freeradius Server. Configure LDAP parameters in ldap located in /etc/freeradius/mods-available/ and modify the appropriate lines:
server = 'LDAP_SERVER_FQDN'
identity = 'cn=admin,dc=abc,dc=edu,dc=gh' #bind User
password = 'YOUR_LDAP_PASSWORD'
base_dn = 'ou=people,dc=abc,dc=edu,dc=gh'
edir_autz = yes
#Under the tls section, Update the following
start_tls = yes
ca_file = "/etc/freeradius/ca_certs.pem"
require_cert = "demand"
Enable LDAP Module & Restart Freeradius
ln -s /etc/freeradius/mods-available/ldap /etc/freeradius/mods-enabled/ldap
service freeradius restart
Network configuration file for the ldap connectivity may look like below.
network={
ssid="eduroam"
key_mgmt=WPA-EAP
eap=PEAP
identity="user@YOUR_DOMAIN"
# anonymous_identity="@eduroam.gh"
password="USER-PASSWORD"
phase2="auth=MSCHAPV2"
# Uncomment the following to perform server certificate validation.
# ca_cert="/etc/raddb/certs/ca.der"
}
Test ldap user authentication:
sudo eapol_test -c peap-mschapv2-ldap.conf -p 1812 -s testing123
11. Troubleshoot¶
Log Path: /var/logs/freeradius/
Debug mode:
* In a new console, stop freeradius service service freeradius stop
* Start in debug mode freeradius -X
* To stop debug mode, use CTRL+c