Project: Containerized FreeRADIUS Server with Mikrotik Router
Summary of Identified Errors
This report outlines the debugging process and resolution of issues encountered while setting up a FreeRADIUS server within Docker containers, using a MySQL database as the backend.
The primary challenges we faced during the setup were:
- FreeRADIUS Container Instability: Initially, the
radius
Docker container kept crashing immediately after starting, showing an “Exited (1)” status. This meant the FreeRADIUS software couldn’t even begin to run inside the container. - Persistent Authentication Failures: Even after getting the container to stay “Up,” we hit another wall. Our
radtest
commands, used to verify authentication, consistently returned anAccess-Reject
. This issue evolved:
Root Cause Analysis
A methodical approach to debugging, primarily focusing on Docker container logs and FreeRADIUS configuration files, helped uncover the following root causes:
1.) File System Permissions on Mounted Volume (Initial Exited (1)):
- Analysis: The freeradius/freeradius-server Docker image runs the FreeRADIUS daemon as a specific user (freerad) inside the container. The docker-compose.yml mounts a local directory (./raddb) into the container’s configuration path (/etc/raddb). If the permissions on the host’s raddb directory were too restrictive, the freerad user could not read the necessary configuration files, causing the server to fail startup.
- Impact: Prevented the FreeRADIUS container from ever running successfully.
2.) Incorrect SQL Driver Configuration (First Access-Reject when container was Up):
- Analysis: During an intermediate troubleshooting step, the sql module in raddb/mods-available/sql was explicitly configured with driver = “rlm_sql_null”. This “null” driver essentially disables actual database interaction for authentication purposes. While this allowed the container to stay “Up” (as it wasn’t failing to connect to a non-existent database), it meant FreeRADIUS couldn’t authenticate users against MySQL, leading to an Access-Reject for all requests.
- Impact: FreeRADIUS was operational but not performing authentication against the intended MySQL backend.
3.) Mandatory TLS/SSL Connection Without Configuration (Subsequent Restarting (1)):
- Analysis: After enabling the correct MySQL driver (rlm_sql_mysql), the radius container began restarting again. Investigation revealed a tls block within the mysql section of raddb/mods-available/sql that had tls_required = yes. This mandated an encrypted connection to the MySQL database. However, neither the FreeRADIUS container had the specified certificate files volume-mounted, nor was the mysql:5.7 container configured for TLS/SSL by default. The failed attempt to establish a mandatory secure connection caused FreeRADIUS to crash.
- Impact: Reverted the radius container to a non-operational, constantly restarting state.
Fixes or Resolutions
The following steps were implemented to successfully resolve the issues, leading to a fully functional FreeRADIUS server authenticating against MySQL:
1.) Correcting File System Permissions:
- Action: The permissions on the host’s raddb directory were updated recursively to allow the FreeRADIUS user within the container to read its configuration.
- Command:
# chmod -R 755 raddb
- Outcome: This resolved the initial “Exited (1)” status, allowing the FreeRADIUS container to start up without immediate termination.
2.) Enabling and Configuring the MySQL SQL Driver:
- Action: The raddb/mods-available/sql configuration file was updated to correctly specify MySQL as the database dialect and enable its corresponding driver.
- Configuration Snippet (raddb/mods-available/sql):
sql {
# ...
dialect = "mysql" # Changed from "sqlite" to "mysql"
# ...
# driver = "rlm_sql_null" # This line was commented out
driver = "rlm_sql_${dialect}" # This line was uncommented and correctly set
# ...
# Ensure connection details match docker-compose.yml db service
server = "db"
port = 3306
login = "radius"
password = "radiuspass"
radius_db = "radius"
# ...
}
- Outcome: This correctly instructed FreeRADIUS to attempt a connection to the MySQL database for authentication.
3.) Disabling Mandatory TLS for MySQL Connection:
- Action: The tls configuration block within the mysql section of raddb/mods-available/sql was commented out. This removed the requirement for an encrypted connection that was not supported by the current MySQL setup.
- Configuration Snippet (raddb/mods-available/sql):
mysql {
# If any of the files below are set, TLS encryption is enabled
# tls { # <--- This entire block was commented out
# ca_file = "/etc/ssl/certs/my_ca.crt"
# # ... other TLS settings ...
# tls_required = yes
# # ...
# }
warnings = auto
}
- Outcome: This allowed the FreeRADIUS process to connect to the MySQL database without crashing due to TLS handshake failures, making the radius container stable and Up.
4.) Confirming Database Access and User Authentication:
- Action: After the radius container was stable, radtest was used to confirm successful authentication against the MySQL database.
- Command and Output:
docker exec -it radius_wicl_radius_1 radtest testuser2 testpassword2 127.0.0.1 0 testing123
Sent Access-Request Id 178 from 0.0.0.0:52743 to 127.0.0.1:1812 length 79
User-Name = "testuser2"
User-Password = "testpassword2"
NAS-IP-Address = 172.18.0.3
NAS-Port = 0
Message-Authenticator = 0x00
Cleartext-Password = "testpassword2"
Received Access-Accept Id 178 from 127.0.0.1:1812 to 127.0.0.1:52743 length 38
Message-Authenticator = 0xff590bed550e2a181108092e5ab84f8c
(0) -: Expected Access-Accept got Access-Reject