From 824f0554e43f838d415604ceee023d01446acf4c Mon Sep 17 00:00:00 2001 From: Tygozwolle Date: Fri, 24 Jul 2026 12:51:51 +0200 Subject: [PATCH 01/11] feat: consolidate FreeRADIUS and web controller into a single Docker image with unified entrypoint orchestration --- README.md | 55 ++++++++++++++-------------------- docker-compose.yml | 23 +++++--------- radiuscontroller/Dockerfile | 32 +++++++++++++++++--- radiuscontroller/entrypoint.sh | 38 +++++++++++++++++++++++ 4 files changed, 95 insertions(+), 53 deletions(-) create mode 100644 radiuscontroller/entrypoint.sh diff --git a/README.md b/README.md index 6d21861..5f666ee 100644 --- a/README.md +++ b/README.md @@ -7,24 +7,21 @@ This project provides a complete **RADIUS Authentication & Accounting Controller ## πŸ—οΈ System Architecture ``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” UDP 1812/1813 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ UniFi AP / β”‚ ◄───────────────────────► β”‚ FreeRADIUS β”‚ -β”‚ Dream Machine β”‚ β”‚ (Port 1812/13) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ β”‚ - β”‚ Wi-Fi 802.1X / β”‚ SQL Queries - β”‚ Guest Auth β–Ό - β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ β”‚ PostgreSQL β”‚ - β”‚ β”‚ (Radius DB) β”‚ - β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β–²β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ β”‚ - β”‚ HTTP/8080 β”‚ EF Core - β–Ό β”‚ -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ Guests / Admins β”‚ β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -β”‚ (Web Portal) β”‚ RadiusController Web App -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” UDP 1812/1813 (RADIUS) +β”‚ UniFi AP / β”‚ ◄────────────────────────────────┐ +β”‚ Dream Machine β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” HTTP 8080 (Web UI) β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Guests / Admins β”‚ ◄────────────────────────► β”‚ Combined Application Container β”‚ +β”‚ (Browser) β”‚ β”‚ (FreeRADIUS + Web Controller) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ PostgreSQL + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ PostgreSQL β”‚ + β”‚ (Database) β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- @@ -51,21 +48,6 @@ services: - /mnt/user/appdata/radiuscontroller/pgdata:/var/lib/postgresql/data - /mnt/user/appdata/radiuscontroller/sql/init.sql:/docker-entrypoint-initdb.d/init.sql:ro - freeradius: - image: freeradius/freeradius-server:latest - container_name: radius_freeradius - restart: always - depends_on: - - postgres - ports: - - "1812:1812/udp" - - "1813:1813/udp" - environment: - - DB_NAME=radius - - DB_HOST=postgres - - DB_USER=radius - - DB_PASS=radpass - radiuscontroller: image: cablon.vanolst.tech/tygozwolle/radius:latest container_name: radius_web_controller @@ -74,7 +56,14 @@ services: - postgres ports: - "8080:8080" + - "1812:1812/udp" + - "1813:1813/udp" environment: + - DB_HOST=postgres + - DB_PORT=5432 + - DB_USER=radius + - DB_PASS=radpass + - DB_NAME=radius - ConnectionStrings__DefaultConnection=Host=postgres;Port=5432;Database=radius;Username=radius;Password=radpass; - ASPNETCORE_ENVIRONMENT=Production ``` diff --git a/docker-compose.yml b/docker-compose.yml index 8224d5c..88e6d9b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,21 +15,6 @@ services: - /mnt/user/appdata/radiuscontroller/pgdata:/var/lib/postgresql/data - /mnt/user/appdata/radiuscontroller/sql/init.sql:/docker-entrypoint-initdb.d/init.sql:ro - freeradius: - image: freeradius/freeradius-server:latest - container_name: radius_freeradius - restart: always - depends_on: - - postgres - ports: - - "1812:1812/udp" - - "1813:1813/udp" - environment: - - DB_NAME=radius - - DB_HOST=postgres - - DB_USER=radius - - DB_PASS=radpass - radiuscontroller: image: cablon.vanolst.tech/tygozwolle/radius:latest container_name: radius_web_controller @@ -38,7 +23,13 @@ services: - postgres ports: - "8080:8080" + - "1812:1812/udp" + - "1813:1813/udp" environment: + - DB_HOST=postgres + - DB_PORT=5432 + - DB_USER=radius + - DB_PASS=radpass + - DB_NAME=radius - ConnectionStrings__DefaultConnection=Host=postgres;Port=5432;Database=radius;Username=radius;Password=radpass; - ASPNETCORE_ENVIRONMENT=Production - diff --git a/radiuscontroller/Dockerfile b/radiuscontroller/Dockerfile index 178ef90..56579d1 100644 --- a/radiuscontroller/Dockerfile +++ b/radiuscontroller/Dockerfile @@ -1,8 +1,21 @@ -ο»ΏFROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base -USER $APP_UID +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base +USER root + +# Install FreeRADIUS, PostgreSQL module, and utility packages +RUN apt-get update && apt-get install -y --no-install-recommends \ + freeradius \ + freeradius-postgresql \ + freeradius-utils \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Create symlink so both /etc/raddb and /etc/freeradius/3.0 work +RUN ln -sf /etc/freeradius/3.0 /etc/raddb + WORKDIR /app EXPOSE 8080 -EXPOSE 8081 +EXPOSE 1812/udp +EXPOSE 1813/udp FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build ARG BUILD_CONFIGURATION=Release @@ -19,5 +32,16 @@ RUN dotnet publish "./radiuscontroller.csproj" -c $BUILD_CONFIGURATION -o /app/p FROM base AS final WORKDIR /app + +# Copy pre-configured FreeRADIUS PostgreSQL rules & EAP authentication config +COPY raddb/clients.conf /etc/freeradius/3.0/clients.conf +COPY raddb/mods-enabled/sql /etc/freeradius/3.0/mods-enabled/sql +COPY raddb/sites-enabled/default /etc/freeradius/3.0/sites-enabled/default +COPY raddb/sites-enabled/inner-tunnel /etc/freeradius/3.0/sites-enabled/inner-tunnel + +# Copy published application and entrypoint script COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "radiuscontroller.dll"] +COPY radiuscontroller/entrypoint.sh /app/entrypoint.sh +RUN chmod +x /app/entrypoint.sh + +ENTRYPOINT ["/app/entrypoint.sh"] diff --git a/radiuscontroller/entrypoint.sh b/radiuscontroller/entrypoint.sh new file mode 100644 index 0000000..4d6bc78 --- /dev/null +++ b/radiuscontroller/entrypoint.sh @@ -0,0 +1,38 @@ +#!/bin/sh +set -e + +# Default environment variables +DB_HOST="${DB_HOST:-postgres}" +DB_PORT="${DB_PORT:-5432}" +DB_USER="${DB_USER:-radius}" +DB_PASS="${DB_PASS:-radpass}" +DB_NAME="${DB_NAME:-radius}" + +echo "=================================================" +echo " Starting RADIUS Controller & FreeRADIUS Stack" +echo " DB Host: $DB_HOST:$DB_PORT | Database: $DB_NAME" +echo "=================================================" + +# Dynamically update FreeRADIUS SQL configuration with DB settings +SQL_CONF="/etc/freeradius/3.0/mods-enabled/sql" +if [ -f "$SQL_CONF" ]; then + sed -i "s/server = .*/server = \"$DB_HOST\"/" "$SQL_CONF" + sed -i "s/port = .*/port = $DB_PORT/" "$SQL_CONF" + sed -i "s/login = .*/login = \"$DB_USER\"/" "$SQL_CONF" + sed -i "s/password = .*/password = \"$DB_PASS\"/" "$SQL_CONF" + sed -i "s/radius_db = .*/radius_db = \"$DB_NAME\"/" "$SQL_CONF" +fi + +# Ensure correct permissions for FreeRADIUS config directory +chown -R freerad:freerad /etc/freeradius/3.0/ || true + +# Start FreeRADIUS daemon in background +echo "Starting FreeRADIUS service..." +freeradius -x & + +# Wait briefly for FreeRADIUS to initialize +sleep 2 + +# Start ASP.NET Core Application +echo "Starting ASP.NET Core Web Controller..." +exec dotnet radiuscontroller.dll From fd133bf9f3c71037c149bf210b975dad54e5c6d2 Mon Sep 17 00:00:00 2001 From: Tygozwolle Date: Fri, 24 Jul 2026 12:58:07 +0200 Subject: [PATCH 02/11] feat: add FreeRADIUS configuration and containerization support with PostgreSQL integration --- radiuscontroller/Dockerfile | 8 +- radiuscontroller/raddb/clients.conf | 11 +++ radiuscontroller/raddb/mods-enabled/sql | 30 +++++++ radiuscontroller/raddb/sites-enabled/default | 78 +++++++++++++++++++ .../raddb/sites-enabled/inner-tunnel | 36 +++++++++ 5 files changed, 159 insertions(+), 4 deletions(-) create mode 100644 radiuscontroller/raddb/clients.conf create mode 100644 radiuscontroller/raddb/mods-enabled/sql create mode 100644 radiuscontroller/raddb/sites-enabled/default create mode 100644 radiuscontroller/raddb/sites-enabled/inner-tunnel diff --git a/radiuscontroller/Dockerfile b/radiuscontroller/Dockerfile index 56579d1..b684d1b 100644 --- a/radiuscontroller/Dockerfile +++ b/radiuscontroller/Dockerfile @@ -34,10 +34,10 @@ FROM base AS final WORKDIR /app # Copy pre-configured FreeRADIUS PostgreSQL rules & EAP authentication config -COPY raddb/clients.conf /etc/freeradius/3.0/clients.conf -COPY raddb/mods-enabled/sql /etc/freeradius/3.0/mods-enabled/sql -COPY raddb/sites-enabled/default /etc/freeradius/3.0/sites-enabled/default -COPY raddb/sites-enabled/inner-tunnel /etc/freeradius/3.0/sites-enabled/inner-tunnel +COPY radiuscontroller/raddb/clients.conf /etc/freeradius/3.0/clients.conf +COPY radiuscontroller/raddb/mods-enabled/sql /etc/freeradius/3.0/mods-enabled/sql +COPY radiuscontroller/raddb/sites-enabled/default /etc/freeradius/3.0/sites-enabled/default +COPY radiuscontroller/raddb/sites-enabled/inner-tunnel /etc/freeradius/3.0/sites-enabled/inner-tunnel # Copy published application and entrypoint script COPY --from=publish /app/publish . diff --git a/radiuscontroller/raddb/clients.conf b/radiuscontroller/raddb/clients.conf new file mode 100644 index 0000000..f1bd4f7 --- /dev/null +++ b/radiuscontroller/raddb/clients.conf @@ -0,0 +1,11 @@ +client localhost { + ipaddr = 127.0.0.1 + secret = testing123 + shortname = localhost +} + +client local_net { + ipaddr = 0.0.0.0/0 + secret = radpass + shortname = all_clients +} diff --git a/radiuscontroller/raddb/mods-enabled/sql b/radiuscontroller/raddb/mods-enabled/sql new file mode 100644 index 0000000..04bc130 --- /dev/null +++ b/radiuscontroller/raddb/mods-enabled/sql @@ -0,0 +1,30 @@ +sql { + driver = "rlm_sql_postgresql" + dialect = "postgresql" + + server = "postgres" + port = 5432 + login = "radius" + password = "radpass" + radius_db = "radius" + + read_clients = yes + client_table = "nas" + + group_attribute = "User-Group" + + pool { + start = 2 + min = 1 + max = 10 + spare = 3 + uses = 0 + retry_delay = 30 + lifetime = 0 + idle_timeout = 60 + } + + read_groups = yes + + $INCLUDE ${modconfdir}/${.:name}/main/${dialect}/queries.conf +} diff --git a/radiuscontroller/raddb/sites-enabled/default b/radiuscontroller/raddb/sites-enabled/default new file mode 100644 index 0000000..a7ae66d --- /dev/null +++ b/radiuscontroller/raddb/sites-enabled/default @@ -0,0 +1,78 @@ +server default { +listen { + type = auth + ipaddr = * + port = 1812 + limit { + max_connections = 16 + lifetime = 0 + idle_timeout = 30 + } +} + +listen { + type = acct + ipaddr = * + port = 1813 + limit { + max_connections = 16 + lifetime = 0 + idle_timeout = 30 + } +} + +authorize { + filter_username + preprocess + chap + mschap + digest + pap + eap { + ok = return + } + sql + expiration + logintime +} + +authenticate { + Auth-Type PAP { + pap + } + Auth-Type CHAP { + chap + } + Auth-Type MS-CHAP { + mschap + } + mschap + eap +} + +pre-proxy { +} + +post-proxy { + eap +} + +accounting { + detail + sql + exec +} + +session { + sql +} + +post-auth { + sql + exec + Post-Auth-Type REJECT { + sql + attr_filter.access_reject + } +} +} diff --git a/radiuscontroller/raddb/sites-enabled/inner-tunnel b/radiuscontroller/raddb/sites-enabled/inner-tunnel new file mode 100644 index 0000000..02a8e14 --- /dev/null +++ b/radiuscontroller/raddb/sites-enabled/inner-tunnel @@ -0,0 +1,36 @@ +server inner-tunnel { +authorize { + filter_username + chap + mschap + pap + eap { + ok = return + } + sql + expiration + logintime +} + +authenticate { + Auth-Type PAP { + pap + } + Auth-Type CHAP { + chap + } + Auth-Type MS-CHAP { + mschap + } + mschap + eap +} + +post-auth { + sql + Post-Auth-Type REJECT { + sql + attr_filter.access_reject + } +} +} From f7663a284ef9378b0829a9248e8335fcd66b0bf4 Mon Sep 17 00:00:00 2001 From: Tygozwolle Date: Fri, 24 Jul 2026 14:10:25 +0200 Subject: [PATCH 03/11] feat: add PostgreSQL schema initialization and FreeRADIUS SQL module configuration --- radiuscontroller/raddb/mods-enabled/sql | 17 ++++++++++++++++- sql/init.sql | 9 +++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/radiuscontroller/raddb/mods-enabled/sql b/radiuscontroller/raddb/mods-enabled/sql index 04bc130..4f2bc32 100644 --- a/radiuscontroller/raddb/mods-enabled/sql +++ b/radiuscontroller/raddb/mods-enabled/sql @@ -8,8 +8,23 @@ sql { password = "radpass" radius_db = "radius" - read_clients = yes + # Standard FreeRADIUS SQL Table Mappings + authcheck_table = "radcheck" + authreply_table = "radreply" + groupcheck_table = "radgroupcheck" + groupreply_table = "radgroupreply" + usergroup_table = "radusergroup" + + # Accounting Table Mappings + acct_table1 = "radacct" + acct_table2 = "radacct" + + # Post-auth Table Mapping + postauth_table = "radpostauth" + + # NAS Client Table Mapping client_table = "nas" + read_clients = yes group_attribute = "User-Group" diff --git a/sql/init.sql b/sql/init.sql index f67c8bf..077db02 100644 --- a/sql/init.sql +++ b/sql/init.sql @@ -86,6 +86,15 @@ CREATE TABLE IF NOT EXISTS nas ( description VARCHAR(200) DEFAULT 'RADIUS Client' ); +CREATE TABLE IF NOT EXISTS radpostauth ( + id BIGSERIAL PRIMARY KEY, + username VARCHAR(64) NOT NULL DEFAULT '', + pass VARCHAR(64) NOT NULL DEFAULT '', + reply VARCHAR(32) NOT NULL DEFAULT '', + authdate TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); +CREATE INDEX IF NOT EXISTS radpostauth_username ON radpostauth (username); + -- Application Management Tables CREATE TABLE IF NOT EXISTS guest_profiles ( id SERIAL PRIMARY KEY, From 0bb36ea50282e65f3974c1ec6da3247f09d5251f Mon Sep 17 00:00:00 2001 From: Tygozwolle Date: Fri, 24 Jul 2026 14:22:38 +0200 Subject: [PATCH 04/11] feat: add FreeRADIUS PostgreSQL configuration module to mods-enabled --- radiuscontroller/raddb/mods-enabled/sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radiuscontroller/raddb/mods-enabled/sql b/radiuscontroller/raddb/mods-enabled/sql index 4f2bc32..a1e72b9 100644 --- a/radiuscontroller/raddb/mods-enabled/sql +++ b/radiuscontroller/raddb/mods-enabled/sql @@ -26,7 +26,7 @@ sql { client_table = "nas" read_clients = yes - group_attribute = "User-Group" + group_attribute = "SQL-Group" pool { start = 2 From 574bcbe69a4483cd94948bf035a585132a0791e6 Mon Sep 17 00:00:00 2001 From: Tygozwolle Date: Fri, 24 Jul 2026 14:53:01 +0200 Subject: [PATCH 05/11] feat: add FreeRADIUS client configuration, environment-based secret management, and custom entrypoint script --- docker-compose.yml | 1 + radiuscontroller/entrypoint.sh | 8 ++++++++ radiuscontroller/raddb/clients.conf | 8 +++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 88e6d9b..17acccc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,5 +31,6 @@ services: - DB_USER=radius - DB_PASS=radpass - DB_NAME=radius + - RADIUS_SECRET=radpass - ConnectionStrings__DefaultConnection=Host=postgres;Port=5432;Database=radius;Username=radius;Password=radpass; - ASPNETCORE_ENVIRONMENT=Production diff --git a/radiuscontroller/entrypoint.sh b/radiuscontroller/entrypoint.sh index 4d6bc78..021c2ea 100644 --- a/radiuscontroller/entrypoint.sh +++ b/radiuscontroller/entrypoint.sh @@ -7,10 +7,12 @@ DB_PORT="${DB_PORT:-5432}" DB_USER="${DB_USER:-radius}" DB_PASS="${DB_PASS:-radpass}" DB_NAME="${DB_NAME:-radius}" +RADIUS_SECRET="${RADIUS_SECRET:-radpass}" echo "=================================================" echo " Starting RADIUS Controller & FreeRADIUS Stack" echo " DB Host: $DB_HOST:$DB_PORT | Database: $DB_NAME" +echo " RADIUS Secret: $RADIUS_SECRET (Allows all IP addresses)" echo "=================================================" # Dynamically update FreeRADIUS SQL configuration with DB settings @@ -23,6 +25,12 @@ if [ -f "$SQL_CONF" ]; then sed -i "s/radius_db = .*/radius_db = \"$DB_NAME\"/" "$SQL_CONF" fi +# Dynamically update RADIUS shared secret for all client networks from env +CLIENTS_CONF="/etc/freeradius/3.0/clients.conf" +if [ -f "$CLIENTS_CONF" ]; then + sed -i "s/secret = .*/secret = $RADIUS_SECRET/" "$CLIENTS_CONF" +fi + # Ensure correct permissions for FreeRADIUS config directory chown -R freerad:freerad /etc/freeradius/3.0/ || true diff --git a/radiuscontroller/raddb/clients.conf b/radiuscontroller/raddb/clients.conf index f1bd4f7..e0a0a18 100644 --- a/radiuscontroller/raddb/clients.conf +++ b/radiuscontroller/raddb/clients.conf @@ -1,6 +1,6 @@ client localhost { ipaddr = 127.0.0.1 - secret = testing123 + secret = radpass shortname = localhost } @@ -9,3 +9,9 @@ client local_net { secret = radpass shortname = all_clients } + +client local_net_v6 { + ipv6addr = ::/0 + secret = radpass + shortname = all_clients_v6 +} From c7e18c76acd8713c01148508a4cfd843402a9791 Mon Sep 17 00:00:00 2001 From: Tygozwolle Date: Fri, 24 Jul 2026 15:04:46 +0200 Subject: [PATCH 06/11] feat: initialize default and inner-tunnel RADIUS server configurations --- radiuscontroller/raddb/sites-enabled/default | 2 +- radiuscontroller/raddb/sites-enabled/inner-tunnel | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/radiuscontroller/raddb/sites-enabled/default b/radiuscontroller/raddb/sites-enabled/default index a7ae66d..893b71a 100644 --- a/radiuscontroller/raddb/sites-enabled/default +++ b/radiuscontroller/raddb/sites-enabled/default @@ -24,6 +24,7 @@ listen { authorize { filter_username preprocess + sql chap mschap digest @@ -31,7 +32,6 @@ authorize { eap { ok = return } - sql expiration logintime } diff --git a/radiuscontroller/raddb/sites-enabled/inner-tunnel b/radiuscontroller/raddb/sites-enabled/inner-tunnel index 02a8e14..eef3b96 100644 --- a/radiuscontroller/raddb/sites-enabled/inner-tunnel +++ b/radiuscontroller/raddb/sites-enabled/inner-tunnel @@ -1,13 +1,13 @@ server inner-tunnel { authorize { filter_username + sql chap mschap pap eap { ok = return } - sql expiration logintime } From 9a6b1131b18a91098edff31c59f9bdcf8c8bdcf5 Mon Sep 17 00:00:00 2001 From: Tygozwolle Date: Fri, 24 Jul 2026 15:09:42 +0200 Subject: [PATCH 07/11] feat: add Dockerfile, entrypoint script, and EAP configuration for FreeRADIUS containerization --- radiuscontroller/Dockerfile | 1 + radiuscontroller/entrypoint.sh | 8 +++++ radiuscontroller/raddb/mods-enabled/eap | 40 +++++++++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 radiuscontroller/raddb/mods-enabled/eap diff --git a/radiuscontroller/Dockerfile b/radiuscontroller/Dockerfile index b684d1b..1c800bc 100644 --- a/radiuscontroller/Dockerfile +++ b/radiuscontroller/Dockerfile @@ -36,6 +36,7 @@ WORKDIR /app # Copy pre-configured FreeRADIUS PostgreSQL rules & EAP authentication config COPY radiuscontroller/raddb/clients.conf /etc/freeradius/3.0/clients.conf COPY radiuscontroller/raddb/mods-enabled/sql /etc/freeradius/3.0/mods-enabled/sql +COPY radiuscontroller/raddb/mods-enabled/eap /etc/freeradius/3.0/mods-enabled/eap COPY radiuscontroller/raddb/sites-enabled/default /etc/freeradius/3.0/sites-enabled/default COPY radiuscontroller/raddb/sites-enabled/inner-tunnel /etc/freeradius/3.0/sites-enabled/inner-tunnel diff --git a/radiuscontroller/entrypoint.sh b/radiuscontroller/entrypoint.sh index 021c2ea..ad68e66 100644 --- a/radiuscontroller/entrypoint.sh +++ b/radiuscontroller/entrypoint.sh @@ -31,6 +31,14 @@ if [ -f "$CLIENTS_CONF" ]; then sed -i "s/secret = .*/secret = $RADIUS_SECRET/" "$CLIENTS_CONF" fi +# Generate FreeRADIUS EAP certificates if missing +if [ ! -f /etc/freeradius/3.0/certs/server.pem ]; then + echo "Generating FreeRADIUS EAP certificates..." + if [ -f /etc/freeradius/3.0/certs/bootstrap ]; then + /etc/freeradius/3.0/certs/bootstrap || true + fi +fi + # Ensure correct permissions for FreeRADIUS config directory chown -R freerad:freerad /etc/freeradius/3.0/ || true diff --git a/radiuscontroller/raddb/mods-enabled/eap b/radiuscontroller/raddb/mods-enabled/eap new file mode 100644 index 0000000..4b40382 --- /dev/null +++ b/radiuscontroller/raddb/mods-enabled/eap @@ -0,0 +1,40 @@ +eap { + default_eap_type = peap + timer_expire = 60 + ignore_unknown_eap_types = no + cisco_accounting_username_bug = no + max_sessions = ${max_requests} + + # PEAP Configuration + peap { + default_eap_type = mschapv2 + copy_request_to_tunnel = yes + use_tunneled_reply = yes + virtual_server = "inner-tunnel" + } + + # TTLS Configuration + ttls { + default_eap_type = mschapv2 + copy_request_to_tunnel = yes + use_tunneled_reply = yes + virtual_server = "inner-tunnel" + } + + # MSCHAPv2 Configuration + mschapv2 { + } + + # TLS Configuration for PEAP / TTLS + tls-config certs { + private_key_password = whatever + private_key_file = ${certdir}/server.pem + certificate_file = ${certdir}/server.pem + ca_file = ${cadir}/ca.pem + dh_file = ${certdir}/dh + cipher_list = "DEFAULT@SECLEVEL=1" + cipher_server_preference = no + tls_min_version = "1.0" + tls_max_version = "1.2" + } +} From 1054dfb61ae4f4ba632701c77caaab0e5f39f8c7 Mon Sep 17 00:00:00 2001 From: Tygozwolle Date: Fri, 24 Jul 2026 15:18:22 +0200 Subject: [PATCH 08/11] feat: add FreeRADIUS EAP module configuration and container entrypoint script for dynamic service orchestration --- radiuscontroller/entrypoint.sh | 6 ++-- radiuscontroller/raddb/mods-enabled/eap | 44 +++++++++++++------------ 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/radiuscontroller/entrypoint.sh b/radiuscontroller/entrypoint.sh index ad68e66..9b8e0e7 100644 --- a/radiuscontroller/entrypoint.sh +++ b/radiuscontroller/entrypoint.sh @@ -34,9 +34,11 @@ fi # Generate FreeRADIUS EAP certificates if missing if [ ! -f /etc/freeradius/3.0/certs/server.pem ]; then echo "Generating FreeRADIUS EAP certificates..." - if [ -f /etc/freeradius/3.0/certs/bootstrap ]; then - /etc/freeradius/3.0/certs/bootstrap || true + cd /etc/freeradius/3.0/certs + if [ -f ./bootstrap ]; then + ./bootstrap || true fi + cd /app fi # Ensure correct permissions for FreeRADIUS config directory diff --git a/radiuscontroller/raddb/mods-enabled/eap b/radiuscontroller/raddb/mods-enabled/eap index 4b40382..273e5d2 100644 --- a/radiuscontroller/raddb/mods-enabled/eap +++ b/radiuscontroller/raddb/mods-enabled/eap @@ -5,27 +5,7 @@ eap { cisco_accounting_username_bug = no max_sessions = ${max_requests} - # PEAP Configuration - peap { - default_eap_type = mschapv2 - copy_request_to_tunnel = yes - use_tunneled_reply = yes - virtual_server = "inner-tunnel" - } - - # TTLS Configuration - ttls { - default_eap_type = mschapv2 - copy_request_to_tunnel = yes - use_tunneled_reply = yes - virtual_server = "inner-tunnel" - } - - # MSCHAPv2 Configuration - mschapv2 { - } - - # TLS Configuration for PEAP / TTLS + # TLS configuration section named "certs" tls-config certs { private_key_password = whatever private_key_file = ${certdir}/server.pem @@ -37,4 +17,26 @@ eap { tls_min_version = "1.0" tls_max_version = "1.2" } + + # PEAP configuration referencing tls-config certs + peap { + tls = certs + default_eap_type = mschapv2 + copy_request_to_tunnel = yes + use_tunneled_reply = yes + virtual_server = "inner-tunnel" + } + + # TTLS configuration referencing tls-config certs + ttls { + tls = certs + default_eap_type = mschapv2 + copy_request_to_tunnel = yes + use_tunneled_reply = yes + virtual_server = "inner-tunnel" + } + + # MSCHAPv2 configuration + mschapv2 { + } } From 9dc029e32f7696d0c17b5dcb8822a33e109a7c70 Mon Sep 17 00:00:00 2001 From: Tygozwolle Date: Fri, 24 Jul 2026 15:29:07 +0200 Subject: [PATCH 09/11] feat: add Dockerfile and entrypoint script to containerize RADIUS controller and FreeRADIUS stack --- radiuscontroller/Dockerfile | 1 + radiuscontroller/entrypoint.sh | 33 +++++++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/radiuscontroller/Dockerfile b/radiuscontroller/Dockerfile index 1c800bc..4882c49 100644 --- a/radiuscontroller/Dockerfile +++ b/radiuscontroller/Dockerfile @@ -7,6 +7,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ freeradius-postgresql \ freeradius-utils \ ca-certificates \ + openssl \ && rm -rf /var/lib/apt/lists/* # Create symlink so both /etc/raddb and /etc/freeradius/3.0 work diff --git a/radiuscontroller/entrypoint.sh b/radiuscontroller/entrypoint.sh index 9b8e0e7..51e8a51 100644 --- a/radiuscontroller/entrypoint.sh +++ b/radiuscontroller/entrypoint.sh @@ -32,13 +32,34 @@ if [ -f "$CLIENTS_CONF" ]; then fi # Generate FreeRADIUS EAP certificates if missing -if [ ! -f /etc/freeradius/3.0/certs/server.pem ]; then +CERT_DIR="/etc/freeradius/3.0/certs" +if [ ! -f "$CERT_DIR/server.pem" ]; then echo "Generating FreeRADIUS EAP certificates..." - cd /etc/freeradius/3.0/certs - if [ -f ./bootstrap ]; then - ./bootstrap || true - fi - cd /app + mkdir -p "$CERT_DIR" + + # Generate CA key and certificate + openssl req -new -x509 -keyout "$CERT_DIR/ca.key" -out "$CERT_DIR/ca.pem" \ + -days 3650 -nodes -subj "/CN=RADIUS CA" 2>/dev/null + + # Generate server key and CSR + openssl req -new -keyout "$CERT_DIR/server.key" -out "$CERT_DIR/server.csr" \ + -nodes -subj "/CN=RADIUS Server" 2>/dev/null + + # Sign the server certificate with the CA + openssl x509 -req -in "$CERT_DIR/server.csr" -CA "$CERT_DIR/ca.pem" \ + -CAkey "$CERT_DIR/ca.key" -CAcreateserial -out "$CERT_DIR/server.crt" \ + -days 3650 2>/dev/null + + # Combine server key + cert into server.pem + cat "$CERT_DIR/server.key" "$CERT_DIR/server.crt" > "$CERT_DIR/server.pem" + + # Generate DH parameters (small size for speed, adequate for internal use) + openssl dhparam -out "$CERT_DIR/dh" 1024 2>/dev/null + + # Clean up intermediate files + rm -f "$CERT_DIR/server.csr" "$CERT_DIR/server.key" "$CERT_DIR/server.crt" "$CERT_DIR/ca.key" "$CERT_DIR/ca.srl" + + echo "EAP certificates generated successfully." fi # Ensure correct permissions for FreeRADIUS config directory From 44290fa89c58492929dd9f421e28adb5511ee8b8 Mon Sep 17 00:00:00 2001 From: Tygozwolle Date: Fri, 24 Jul 2026 15:37:19 +0200 Subject: [PATCH 10/11] chore: add RADIUS_SECRET environment variable and certs volume mount to docker-compose configuration --- README.md | 3 +++ docker-compose.yml | 2 ++ 2 files changed, 5 insertions(+) diff --git a/README.md b/README.md index 5f666ee..f8e294c 100644 --- a/README.md +++ b/README.md @@ -64,8 +64,11 @@ services: - DB_USER=radius - DB_PASS=radpass - DB_NAME=radius + - RADIUS_SECRET=radpass - ConnectionStrings__DefaultConnection=Host=postgres;Port=5432;Database=radius;Username=radius;Password=radpass; - ASPNETCORE_ENVIRONMENT=Production + volumes: + - /mnt/user/appdata/radiuscontroller/certs:/etc/freeradius/3.0/certs ``` 2. Start the stack: diff --git a/docker-compose.yml b/docker-compose.yml index 17acccc..5a6fd08 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,3 +34,5 @@ services: - RADIUS_SECRET=radpass - ConnectionStrings__DefaultConnection=Host=postgres;Port=5432;Database=radius;Username=radius;Password=radpass; - ASPNETCORE_ENVIRONMENT=Production + volumes: + - /mnt/user/appdata/radiuscontroller/certs:/etc/freeradius/3.0/certs From c4ed400ac6a378b99a230c04e7e214308cce20c6 Mon Sep 17 00:00:00 2001 From: Tygozwolle Date: Fri, 24 Jul 2026 15:40:26 +0200 Subject: [PATCH 11/11] c --- radiuscontroller/Dockerfile | 4 ++++ radiuscontroller/raddb/dictionary.custom | 3 +++ 2 files changed, 7 insertions(+) create mode 100644 radiuscontroller/raddb/dictionary.custom diff --git a/radiuscontroller/Dockerfile b/radiuscontroller/Dockerfile index 4882c49..8ab2910 100644 --- a/radiuscontroller/Dockerfile +++ b/radiuscontroller/Dockerfile @@ -41,6 +41,10 @@ COPY radiuscontroller/raddb/mods-enabled/eap /etc/freeradius/3.0/mods-enabled/ea COPY radiuscontroller/raddb/sites-enabled/default /etc/freeradius/3.0/sites-enabled/default COPY radiuscontroller/raddb/sites-enabled/inner-tunnel /etc/freeradius/3.0/sites-enabled/inner-tunnel +# Add custom dictionary for Max-Octets attribute +COPY radiuscontroller/raddb/dictionary.custom /etc/freeradius/3.0/dictionary.custom +RUN echo '$INCLUDE /etc/freeradius/3.0/dictionary.custom' >> /etc/freeradius/3.0/dictionary + # Copy published application and entrypoint script COPY --from=publish /app/publish . COPY radiuscontroller/entrypoint.sh /app/entrypoint.sh diff --git a/radiuscontroller/raddb/dictionary.custom b/radiuscontroller/raddb/dictionary.custom new file mode 100644 index 0000000..edfa6bb --- /dev/null +++ b/radiuscontroller/raddb/dictionary.custom @@ -0,0 +1,3 @@ +# Custom RADIUS attributes for Radius Controller +# Max-Octets: Limits total bytes (upload + download) per session +ATTRIBUTE Max-Octets 227 integer