This guide outlines the steps to configure a FreeRADIUS development environment using Docker, enabling PAP authentication against a PostgreSQL database.
Perform these steps in your project directory (e.g., freeradius-pg-docker).
Dockerfile, docker-compose.yml, and init-db.sh into files with those exact names.Run the following command:
chmod +x init-db.sh
Get the PostgreSQL schema file:
curl -o schema.sql https://raw.githubusercontent.com/FreeRADIUS/freeradius-server/v3.2.x/raddb/mods-config/sql/main/postgresql/schema.sql
IMPORTANT: Edit docker-compose.yml and replace BOTH instances of your_secure_password with a strong, unique password.
mkdir ./raddb ./logs
./raddb with Default Config:
Copy the default FreeRADIUS configuration from the image to your host's ./raddb directory. You typically do this once.
# Build a temporary image first (if not already built)
docker build -t temp-freeradius-config .
# Copy config out from the temporary container
docker run --rm --entrypoint /bin/sh temp-freeradius-config -c "tar cf - -C /etc raddb" | tar xf - -C .
# Optionally remove the temporary image
# docker rmi temp-freeradius-config
Ensure the ./raddb directory exists and is populated before proceeding.
./raddb)Edit the configuration files within your host's ./raddb directory. Changes made here will be reflected inside the container due to the volume mount specified in docker-compose.yml.
./raddb/mods-available/sql):
driver = "rlm_sql_postgresql".dialect = "postgresql".postgresql { ... } section, configure the connection using environment variables passed from docker-compose.yml:
server = "%{env:DB_HOST}"
port = "%{env:DB_PORT}"
login = "%{env:DB_USER}"
password = "%{env:DB_PASSWORD}"
radius_db = "%{env:DB_NAME}"
pool {}) if needed for performance. You might also adjust SQL queries later if necessary../raddb/mods-enabled/sql):
./raddb/mods-enabled/sql to ../mods-available/sql. Create it if it doesn't exist (ensure you are in the project root):# Ensure you are in the project root directory (freeradius-pg-docker)
ln -s ../mods-available/sql ./raddb/mods-enabled/sql
./raddb/sites-enabled/default):
This file controls the main request flow. Modify the sections to integrate SQL and PAP.
authorize {} section:
sql (usually near the top) to fetch user details/checks from the database.files as a fallback.pap if you need authorize checks based on Auth-Type PAP.authorize {
# ... other initial checks ...
sql # Check SQL first
# files # Optional: Check files module if not found in SQL
pap # Keep pap here if needed for Auth-Type PAP checks
# ... other modules ...
}
authenticate {} section:
Auth-Type PAP { pap } block exists to handle PAP authentication.pap module itself (configured in mods-available/pap) determines if passwords are checked against the users file (default) or potentially SQL (requires additional configuration like Password-With-Header and SQL query adjustments).sql here too if specific SQL checks are needed during authentication.authenticate {
Auth-Type PAP {
pap # Handle PAP authentication via the pap module
}
# ... other Auth-Types like CHAP ...
# You might add 'sql' here if needed for other checks
}
accounting {} section:
sql to log accounting records to the database.detail, radacct) if you only want SQL accounting.accounting {
# detail # Optional: file logging
sql # Log accounting to SQL
}
session {} and post-auth {} sections:
sql if needed for your logic (e.g., updating tables after successful authentication)../raddb/clients.conf):
127.0.0.1 if testing with radtest from the host/container (e.g., use secret testing123).client localhost {
ipaddr = 127.0.0.1
secret = testing123 # Use the same secret in radtest
}
# Add other clients as needed
# client my_access_point {
# ipaddr = 192.168.1.100
# secret = your_ap_secret
# }
./raddb/users):
Cleartext-Password.papuser Cleartext-Password := "pappassword"
Reply-Message = "Hello from users file, %u"
./raddb)This section lists the primary files within your host's ./raddb directory that you'll typically interact with when configuring PAP and SQL (PostgreSQL) authentication:
./raddb/mods-available/sqlPurpose: Configures the core SQL module (rlm_sql).
Edits:
driver is set to "rlm_sql_postgresql".dialect is set to "postgresql".postgresql {...} subsection with the correct connection details using environment variables (%{env:VAR_NAME}) from docker-compose.yml (e.g., server = "%{env:DB_HOST}", password = "%{env:DB_PASSWORD}")../raddb/mods-enabled/sql (Symlink)Purpose: Enables the SQL module configured in mods-available/sql.
Action: This isn't a file you edit directly, but you must ensure it exists as a symbolic link pointing to ../mods-available/sql. You likely created this in the initial setup steps (ln -s ../mods-available/sql ./raddb/mods-enabled/sql).
./raddb/sites-enabled/default (and potentially inner-tunnel)Purpose: Defines the request processing workflow (virtual server).
Edits: This is where you tell FreeRADIUS when and how to use the PAP and SQL modules within the different processing sections (authorize, authenticate, accounting, post-auth, session) as detailed in Step 3 of the configuration process above. You'll typically uncomment the sql entries or add them in the desired order relative to other modules like files, pap, chap, etc.
authorize {}: Add sql to fetch user details/perform checks from the database.authenticate {}: Ensure Auth-Type PAP { pap } exists. The pap module itself (mods-available/pap) handles the check (vs users file or potentially SQL). You might add sql here too for other checks.accounting {}: Add sql to log records to PostgreSQL.session {}, post-auth {}: Add sql if needed for actions during these phases../raddb/usersPurpose: The default plain-text file for defining users, passwords (for PAP/CHAP if not using SQL for passwords), and attributes.
Edits:
./raddb/clients.confPurpose: Defines which RADIUS clients (NAS devices, switches, APs, VPN concentrators, test tools) are allowed to send requests and the shared secret for communication.
Edits: You absolutely need to edit this file to add the IP address and shared secret for any device sending requests, including localhost (IP 127.0.0.1) for testing with radtest.
docker-compose up -d
Monitor logs for errors or status messages:
docker-compose logs -f postgres freeradius
docker-compose exec postgres psql -U radius -d radius -c "INSERT INTO radcheck (username, attribute, op, value) VALUES ('sqluser', 'Cleartext-Password', ':=', 'sqlpassword');"
./raddb/users file (for PAP file auth testing):
Add the user entry (like the example provided earlier) to ./raddb/users on your host machine.
Remember to restart FreeRADIUS after editing ./raddb/users:
docker-compose restart freeradius
radtest:
radtest sqluser sqlpassword localhost 0 testing123
radtest papuser pappassword localhost 0 testing123
This Docker volume mount setup facilitates rapid development:
./raddb exists on your host and contains the FreeRADIUS configuration files../raddb directory using your preferred text editor./etc/raddb.docker-compose restart freeradius
(Alternatively: docker-compose stop freeradius && docker-compose up -d freeradius)
Remember to restart the freeradius service after saving changes to configuration files on your host for them to take effect. Carefully adapt the configurations to match your specific requirements.