Двухфакторная аутентификация для VPN и Wi-Fi через FreeRADIUS + OTP (TOTP/HOTP)
FreeRADIUS — самый популярный RADIUS-сервер. На его базе можно сделать двухфакторную аутентификацию (пароль + OTP) для любого RADIUS-клиента: Mikrotik VPN (L2TP/IPsec, PPTP), гостевой Wi-Fi / Hotspot, RD Gateway. В статье — Ubuntu FreeRADIUS + RADIUS-клиент на Mikrotik и проверка OTP через модуль rlm_otp (или через скрипт TOTP).
Архитектура
[Пользователь] --[VPN/Wi-Fi/RDG]--> [Mikrotik / RD Gateway : радиус-клиент]
|
(UDP 1812/1813)
v
[FreeRADIUS @ Ubuntu :1812]
|
[OTP-модуль: TOTP/HOTP]
- RADIUS-клиент (NAS) — Mikrotik (L2TP/IPsec, hotspot), Windows NPS, RD Gateway
- RADIUS-сервер — FreeRADIUS на Ubuntu
- OTP — TOTP (Google Authenticator/FreeOTP) или HOTP
Шаг 1. Установка FreeRADIUS
sudo apt update && sudo apt install -y freeradius
Проверка:
sudo freeradius -X
Ошибки конфига видны прямо в выводе.
Шаг 2. Базовые пароли пользователей
Первичная проверка (пароль из users):
/etc/freeradius/3.0/users:
# формат: User-Name Cleartext-Password := "пароль"
vpnuser01 Cleartext-Password := "Passw0rd!"
Список и проверка:
# из Ubuntu
echo "User-Name=vpnuser01, User-Password=Passw0rd!" | radclient localhost auth testing123
Ответ Access-Accept означает успех.
Пароли лучше хранить в
hash:vpnuser01 Cleartext-Password := "..."НЕ рашлите в открытом виде — используйте NTHash/MD5/SSHA.
Шаг 3. Включаем модуль rlm_otp (TOTP)
В FreeRADIUS нет встроенного TOTP, но есть rlm_otp (HOTP) либо подключаем python/exec процедуру для TOTP. Простой рабочий путь — через exec и скрипт oathtool.
3.1. Установка oathtool
sudo apt install -y oathtool
3.2. Генерация секретов для пользователей
# Генерация случайного секрета (base32 для Google Authenticator)
SECRET=$(head -c 20 /dev/urandom | base32 | tr -d '=')
echo "Секрет пользователя: $SECRET"
# В Google Authenticator вводите этот секрет
3.3. Скрипт проверки OTP
Создайте /usr/local/bin/check_totp.sh:
#!/bin/bash
# $1 - логин, $2 - введённый OTP
USER="$1"
TOKEN="$2"
BASE32_SECRET=$(grep "^$USER:" /etc/freeradius/totp_secrets | awk -F: '{print $2}')
if [ -z "$BASE32_SECRET" ]; then
echo "Auth-Type reject"
exit 1
fi
# Допускаем окно -1,0,+1 (держит небольшой рассинхрон)
for ((off=-1; off<=1; off++)); do
EXPECTED=$(oathtool --totp --base32 --time-step-size=30 --window=$off "$BASE32_SECRET" 2>/dev/null)
if [ "$EXPECTED" = "$TOKEN" ]; then
echo "Auth-Type accept"
exit 0
fi
done
echo "Auth-Type reject"
exit 1
Файл секретов /etc/freeradius/totp_secrets:
vpnuser01:BASE32SECRET123456
vpnuser02:ANOTHERBASE32SECRET
Засекречьте файл:
sudo chmod 600 /etc/freeradius/totp_secrets
3.4. Подключение к FreeRADIUS
/etc/freeradius/3.0/sites-enabled/otp:
authorize {
if (User-Password =~ /^[0-9]{6}$/) {
update {
control:Packet-Type := Access-Accept
}
}
else {
update {
control:Auth-Type := Reject
}
}
}
Или полнее через exec в authenticate:
В /etc/freeradius/3.0/modules/exec добавляем:
exec totp_check {
wait = yes
input = "dummy"
program = "/usr/local/bin/check_totp.sh %{User-Name} %{User-Password}"
output = none
}
В sites-enabled/otp:
authenticate {
Auth-Type OTP {
exec totp_check
}
}
Шаг 4. RADIUS-клиент на Mikrotik (L2TP/IPsec)
Настроим Mikrotik как RADIUS-клиент — тогда при L2TP/IPsec VPN сервер спрашивает Username + Password у FreeRADIUS, где «Password» — OTP.
4.1. Добавляем RADIUS-сервер
/radius add service=pppoe,l2tp address=192.168.10.55
secret=radsecret ports=1812 timeout=3s comment="FreeRADIUS"
4.2. Включаем RADIUS для L2TP (VPN)
/ppp l2tp-server set enabled=yes authentication=mschap2
use-ipsec=yes ips-pool=vpn-pool
/ppp profile add name=vpn-radius change-address=none
bridge-mode=none use-radius=yes
4.3. Проверка из WinBox
Пользователь вводит в VPN-клиенте: логин vpnuser01, пароль <его OTP>. Если всё настроено — подключение проходит только при верном OTP.
Шаг 5. RD Gateway / Windows NPS через RADIUS
Связка со статьёй про RD Gateway:
- Установите роль Network Policy and Access Services (NPS).
- В NPS: RADIUS Clients → добавить FreeRADIUS.
- Для RD Gateway: настройте CAP обращение к RADIUS.
- Пользователь вводит доменную учётку, а NPS передаёт пароль как «password + OTP» (пароль8021x…). Стандартная практика:
фиксированный-парольв поле User-Password, но с FreeRADIUS гибче OTP-модуль.
Упрощённо: RD Gateway → NPS (Windows) → FreeRADIUS (OTP). В RNPS connection request policy укажите forwarded to FreeRADIUS.
Шаг 6. Hotspot/Wi-Fi через RADIUS (связка со статьёй про captive portal)
На Mikrotik-роутере для гостевого Wi-Fi:
/radius set service=hotspot address=192.168.10.55 secret=radsecret
timeout=3s
/ip hotspot profile set guest use-radius=yes
/ip hotspot user profile set default radius-accounting=yes
Теперь при входе на wiki-портал гость вводит логин + OTP — проверку делает FreeRADIUS.
Проверка всей цепочки
# 1. FreeRADIUS результаты
sudo tail -f /var/log/freeradius/radius.log
# 2. Конкретный e2e через radclient (без NAS):
# - если OTP верный:
echo "User-Name=vpnuser01, User-Password=123456" |
radclient -x 127.0.0.1:1812 auth testing123
# вывод: Access-Accept
# 3. От Mikrotik в логах FreeRADIUS появится NAS-адрес и User-Name
Тонкости и подводные камни
- OTP бывает рассинхронизирован — окно ±1 шаг (30c) решает; если клиент вводит код после long-тики — настройте
--window=2. - Не путайте пароль и OTP — в RADIUS
User-Passwordодин. Варианты: «пароль+OTP» через%{User-Password}склеивание, либо TOTP-only (как здесь). Для домашнего использования TOTP-only — норма. - Безопасность секретов — файл
totp_secretsэто root-only. Не делайте readable для freeradius-пользователя. - FreeRADIUS порт 1812/1813 — откройте в firewall:
bash
sudo ufw allow 1812/udp && sudo ufw allow 1813/udp - Mikrotik mschap2 подсекает OTP — с L2TP/IPsec используйте
mschap-v2с расширением: FreeRADIUS должен вернутьMS-CHAP2-Success. Для TOTP-only прощеchap/mschapобычный — проверьте. - NAS-ключ (secret) — одинаковый в
/radius addи вclients.conf:secret = radsecret. Иначе Access-Reject.
Шпаргалка
sudo apt install freeradius oathtool
# секрет для пользователя
SECRET=$(head -c 20 /dev/urandom | base32 | tr -d '=')
echo "user:$SECRET" >> /etc/freeradius/totp_secrets
# клиенты (NAS) в /etc/freeradius/3.0/clients.conf
# client mikrotik { ipaddr = 192.168.10.1 secret = radsecret }
# Mikrotik:
# /radius add service=l2tp address=192.168.10.55 secret=radsecret
# /ppp profile set default use-radius=yes
Проверено на: Ubuntu 22.04 + FreeRADIUS 3.x + RouterOS 7.
Дата: Сентябрь 2026.