Существующие варианты реализации 2FA для OpenVPN основываются на модуле google-authenticator-libpam
для OTP-кодов и плагинов аутентификации OpenVPN libpam-radius-auth
, openvpn-plugin-auth-pam
, openvpn-auth-ldap
.
Все эти варианты имеют ряд недостатков:
передача пароля в открытом виде по сети.
невозможно ввести логин, пароль и одноразовый код в отдельных полях. Предлагается добавлять OTP-код после пароля, что ухудшает пользовательский опыт. Либо не использовать пароль, а использовать сертификат + OTP-код. Этот вариант усложняет администрирование.
невозможность использовать несколько серверов для аутентификации.
модуль
google-authenticator-libpam
использует локальные файлы на сервере для хранения секретов. Это усложняет организацию отказоустойчивости сервиса VPN. А так же ограничивает возможность передать техподдержке генерацию нового секрета или его обновление для TOTP при регистрации пользователей, утере или смене телефона с установленным приложением.
Поскольку и OpenVPN, и FreeRADIUS позволяют подключать плагины мы можем, написав собственный плагин, реализовать такую схему, которая будет лишена указанных недостатков, а так же позволит нам:
использовать для аутентификации пользователей логин и пароль из LDAP-каталога.
удобно вводить логин, пароль, OTP в отдельные независимые поля интерфейса, а не после пароля или вместо пароля.
реализовать различные комбинации использования логина, пароля, OTP в зависимости от задач.
обеспечить отказоустойчивость, возможность использования нескольких серверов аутентификации.
использовать LDAP-каталог для централизованного управления пользователями.
хранить seed-значения для генератора OTP независимо от того, какой LDAP-каталог используется (ActiveDirectory, FreeIPA, lldap или другие).
передать функцию создания, обновления seed-значений для генератора OTP техподдержке без необходимости подключаться к серверам OpenVPN.
использовать на смартфонах любое приложение для генерации OTP (Яндекс.Ключ, FreeOTP Authenticator и др.).
не зависеть от работоспособности облачных провайдеров 2FA (при неработоспособности сервиса 2FA или отсутствии связи между вашими серверами и сервисом 2FA вы автоматически теряете удаленный доступ в свою инфраструктуру).
Рассматриваемый вариант предполагает следующие сценарии использования:
доступ пользователей через OpenVPN в инфраструктуру компании.
резервный самодостаточный безопасный удаленный доступ в инфраструктуру для администраторов на случай аварий или сбоев.
В обоих сценариях:
не предполагается использование персональных сертификатов для каждого пользователя. Однако, это не исключает использования сертификатов в качестве дополнительной меры защиты.
для аутентификации используется логин, пароль и OTP.
Исходный код и пример полностью настроенной системы размещены на https://gitverse.ru.
Архитектура
Система состоит из двух частей:
Сервер OpenVPN с плагином аутентификации.
Сервер FreeRADIUS с плагином проверки OTP и отправки логина/пароля LDAP-серверу. А так же сервер PostgreSQL для хранения начальных значений генераторов OTP пользователей.
Хранение пользователей и их аутентификацию выполняет любой LDAP-сервер (контроллер домена Active Directory, FreeIPA, lldap, 389ds и другие).
![Архитектура Архитектура](https://habrastorage.org/getpro/habr/upload_files/e7b/ea3/d19/e7bea3d19930b7296fff2d2032dc142b.png)
Нужный нам плагин для OpenVPN уже существует и называется openvpn-multi-authentication-plugin
. Остается только написать плагин для FreeRADIUS.
Обе части системы можно использовать независимо, например:
OpenVPN с плагином можно использовать в сочетании с любыми другими сервисами 2FA.
Freeradius и плагин к нему вместе с VPN шлюзами, способными аутентифицировать пользователей по протоколу RADIUS.
Схема работы
Пользователь в клиенте OpenVPN вводит свой логин, пароль и в отдельном поле шестизначный код второго фактора.
Учетные данные с помощью плагина
openvpn-multi-authentication-plugin
передаются на сервер FreeRADIUS.Плагин для FreeRADIUS декодирует переданные учетные данные. Сначала проверяет одноразовый код и, в случае успешной проверки, отправляет логин и пароль пользователя на LDAP-сервер .
Если LDAP-сервер успешно аутентифицировал пользователя, FreeRADIUS отправляет положительный ответ.
Проверка OTP перед аутентификацией по логину и паролю позволяет снизить нагрузку на LDAP-сервер при попытках подбора пароля.
Настройка
Покажем настройку системы на одном сервере для сценария резервного самодостаточного безопасного удаленного доступа в инфраструктуру для администраторов на случай аварий или сбоев.
В качестве LDAP-сервера используется lldap. FreeRADIUS, lldap, PosgreSQL работают в Docker-контейнерах. OpenVPN и плагин openvpn-multi-authentication-plugin
- непосредственно в операционной системе. Предполагается, что на сервере установлен Debian 12. Все необходимые файлы будут располагаться в каталоге /opt/ovpn-freeradius-lldap
.
Настройка системы выполняется в порядке, облегчающим диагностику ошибок и позволяющим тестировать работу компонентов по отдельности. Поэтому рекомендуется не нарушать порядок настройки.
Устанавливаем Docker.
apt install docker.io docker-compose
Клонируем репозиторий.
git clone https://gitverse.ru/strongpass/openvpn-2fa-otp-freeradius-ldap.git
cd openvpn-2fa-otp-freeradius-ldap
lldap
Создаем нужные каталоги.
sudo mkdir -p /opt/ovpn-freeradius-lldap/lldap
Создаем файл /opt/ovpn-freeradius-lldap/docker-compose.yaml
следующего содержания:
networks:
ovpn-freeradius-lldap_net:
name: ovpn-freeradius-lldap_net
ipam:
config:
- subnet: 172.21.2.0/24
services:
lldap:
image: mirror.gcr.io/lldap/lldap:stable
container_name: lldap
networks:
ovpn-freeradius-lldap_net:
ipv4_address: 172.21.2.2
ports:
- "389:3890"
# For the web front-end
- "17170:17170"
volumes:
- "./lldap/data:/data"
environment:
- UID=1000
- GID=1000
- TZ=Europe/Moscow
- LLDAP_JWT_SECRET=REPLACE_WITH_RANDOM
- LLDAP_KEY_SEED=REPLACE_WITH_RANDOM
- LLDAP_LDAP_BASE_DN=dc=acme,dc=corp
Запускаем контейнер.
sudo docker-compose -f /opt/ovpn-freeradius-lldap/docker-compose.yaml up
Создание пользователей
Подключаемся к веб-интерфейсу lldap по адресу http://127.0.0.1:17170/login
. Реквизиты по умолчанию для подключения: admin/password
.
Создаем пользователей:
user-test1
для тестирования аутентификации без OTP.user-test2
для тестирования аутентификации с OTP.freeradius-ldap-user
- для подключения плагина FreeRADIUS к lldap.
Создаем группу otp-vpn-users
. Пользователям только этой группы будет разрешено подключаться по VPN. Добавьте в эту группу пользователей user-test1
, user-test2
.
Важно! Добавьте пользователя freeradius-ldap-user
в группу lldap_strict_readonly
. В противном случае поиск по LDAP-каталогу не будет разрешен.
Останавливаем контейнер.
sudo docker-compose -f /opt/ovpn-freeradius-lldap/docker-compose.yaml down
PostgreSQL
Копируем файл инициализации БД из репозитория.
sudo cp -R src/postgresql /opt/ovpn-freeradius-lldap
В БД у нас будет 2 пользователя:
для плагина FreeRADIUS. Пользователь может только читать seed-коды.
для технической поддержки. Пользователь может только создавать, обновлять, удалять seed-коды генератора OTP, но не может их читать.
В файле /opt/ovpn-freeradius-lldap/postgresql/init_db/init_db.sql
замените логины и пароли пользователей на ваши значения.
Добавляем в файл /opt/ovpn-freeradius-lldap/docker-compose.yaml
раздел касающийся PosgreSQL. Содержание файла /opt/ovpn-freeradius-lldap/docker-compose.yaml
на этом этапе выглядит так:
networks:
ovpn-freeradius-lldap_net:
name: ovpn-freeradius-lldap_net
ipam:
config:
- subnet: 172.21.2.0/24
services:
lldap:
image: mirror.gcr.io/lldap/lldap:stable
container_name: lldap
networks:
ovpn-freeradius-lldap_net:
ipv4_address: 172.21.2.2
ports:
- "389:3890"
# For the web front-end
- "17170:17170"
volumes:
- "./lldap/data:/data"
environment:
- UID=1000
- GID=1000
- TZ=Europe/Moscow
- LLDAP_JWT_SECRET=REPLACE_WITH_RANDOM
- LLDAP_KEY_SEED=REPLACE_WITH_RANDOM
- LLDAP_LDAP_BASE_DN=dc=acme,dc=corp
postgres:
image: mirror.gcr.io/postgres:16.3-bookworm
container_name: postgres
restart: unless-stopped
environment:
POSTGRES_DB: "otpdb"
POSTGRES_USER: "db_admin"
POSTGRES_PASSWORD: "IrcfRqB0cQ2G"
TZ: "Europe/Moscow"
networks:
ovpn-freeradius-lldap_net:
ipv4_address: 172.21.2.3
ports:
- "5432:5432"
volumes:
- "./postgresql/init_db:/docker-entrypoint-initdb.d"
- "./postgresql/data:/var/lib/postgresql/data"
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U db_admin -d otpdb" ]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
Запускаем контейнеры и убеждаемся, что нет сообщений об ошибках.
sudo docker-compose -f /opt/ovpn-freeradius-lldap/docker-compose.yaml up
После первого запуска и успешной инициализации базы нужно удалить файл /opt/ovpn-freeradius-lldap/postgresql/init_db/init_db.sql
и закомментировать строку
./postgresql/init_db:/docker-entrypoint-initdb.d
в файле /opt/ovpn-freeradius-lldap/docker-compose.yaml
Управление секретами генератора OTP
Для создания, обновления и удаления секретов написан скрипт на python, который можно отдать техподдержке. Скрипт расположен в каталоге репозитория openvpn-2fa-otp-freeradius-ldap/src/manage_otp
.
Для подключения к базе данных создайте файл config.yaml
. Укажите параметры по аналогии с примером ниже.
host: 172.21.2.3
port: 5432
db_name: otpdb
user: helpdesk_user
В параметре user
указывается логин пользователя технической поддержки, созданный в postgres. В нашем примере - это helpdesk_user
.
Находясь в каталоге openvpn-2fa-otp-freeradius-ldap
установите зависимости и приложение в виртуальное окружение.
sudo apt install pipx
pipx ensurepath
pipx install --include-deps ./src/manage_otp
После установки будет доступна команда manage-otp
.
Создайте секрет генератора OTP для пользователя user-test2
.
manage-otp -c config.yaml create user-test2
По окончании работы приложение выведет строку для настройки генератора OTP, а так же создаст файл с QR-кодом. Добавьте на смартфоне в приложение для генерации OTP учетную запись с полученным секретом.
Останавливаем контейнеры.
sudo docker-compose -f /opt/ovpn-freeradius-lldap/docker-compose.yaml down
Плагин для FreeRADIUS
Находясь в каталоге openvpn-2fa-otp-freeradius-ldap
копируем файлы плагина из репозитория.
mkdir -p /opt/ovpn-freeradius-lldap/freeradius
cp -r src/freeradius/freeradius-config /opt/ovpn-freeradius-lldap/freeradius/
cp -r src/freeradius/freeradius-plugin /opt/ovpn-freeradius-lldap/freeradius/
Создаем файл /opt/ovpn-freeradius-lldap/freeradius/freeradius-plugin/strongpass-otp/config.yml
. Пояснения к параметрам можно найти в файле openvpn-2fa-otp-freeradius-ldap/src/freeradius/freeradius-plugin/config.yml.example
.
otp_option: 2
auth_test_user: "user-test1"
db:
host: 172.21.2.3
port: 5432
db_name: otpdb
user: freeradius_user
# замените на свой пароль.
password: "7xFWnt8BN6Ww"
ldap:
host: 172.21.2.2
port: 3890
use_ssl: false
# для LLDAP
search_base: "ou=people,dc=acme,dc=corp"
search_filter: "(&(uid=%s)(memberof=cn=otp-vpn-users,ou=groups,dc=acme,dc=corp))"
bind_dn: "uid=freeradius-ldap-user,ou=people,dc=acme,dc=corp"
# замените на свой пароль
password: "587MVkETPhRf"
Важно! На этапе настройки и тестирования для облегчения ввода пароля и OTP устанавливаем для параметра otp_option
значение 2. В этом варианте OTP вводится пользователем сразу после пароля (6 цифр). Пример: password349307
. После окончания настройки, тестирования и при использовании с OpenVPN нужно будет установить значение opt_option: 1
.
FreeRADIUS
Для работы плагина FreeRADIUS потребуются зависимости, которых нет в исходном образе, поэтому необходимо собрать собственный образ.
Находясь в каталоге openvpn-2fa-otp-freeradius-ldap
выполняем команду:
sudo docker build -f src/freeradius/docker/Dockerfile -t freeradius:otp .
Добавляем в файл /opt/ovpn-freeradius-lldap/docker-compose.yaml
раздел касающийся FreeRADIUS. Содержимое файла на этом этапе выглядит так:
networks:
ovpn-freeradius-lldap_net:
name: ovpn-freeradius-lldap_net
ipam:
config:
- subnet: 172.21.2.0/24
services:
lldap:
image: mirror.gcr.io/lldap/lldap:stable
container_name: lldap
networks:
ovpn-freeradius-lldap_net:
ipv4_address: 172.21.2.2
ports:
- "389:3890"
# web frontend
- "17170:17170"
volumes:
- "./lldap/data:/data"
environment:
- UID=1000
- GID=1000
- TZ=Europe/Moscow
- LLDAP_JWT_SECRET=REPLACE_WITH_RANDOM
- LLDAP_KEY_SEED=REPLACE_WITH_RANDOM
- LLDAP_LDAP_BASE_DN=dc=acme,dc=corp
postgres:
image: mirror.gcr.io/postgres:16.3-bookworm
container_name: postgres
restart: unless-stopped
environment:
POSTGRES_DB: "otpdb"
POSTGRES_USER: "db_admin"
POSTGRES_PASSWORD: "IrcfRqB0cQ2G"
TZ: "Europe/Moscow"
networks:
ovpn-freeradius-lldap_net:
ipv4_address: 172.21.2.3
ports:
- "5432:5432"
volumes:
- "./postgresql/init_db:/docker-entrypoint-initdb.d"
- "./postgresql/data:/var/lib/postgresql/data"
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U db_admin -d otpdb" ]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
freeradius:
image: "freeradius:otp"
container_name: freeradius
# Раскомментируйте строчку ниже для отладки freeradius
# command: "freeradius -X"
environment:
- TZ="Europe/Moscow"
networks:
ovpn-freeradius-lldap_net:
ipv4_address: 172.21.2.4
ports:
- "1812:1812"
- "1813:1813"
volumes:
- "./freeradius/freeradius-config/sites-enabled:/etc/freeradius/sites-enabled"
- "./freeradius/freeradius-config/mods-enabled/python3:/etc/freeradius/mods-enabled/python3"
- "./freeradius/freeradius-config/clients.conf:/etc/freeradius/clients.conf"
- "./freeradius/freeradius-plugin/strongpass-otp:/opt/strongpass-otp"
- "./freeradius/logs/:/var/log/freeradius"
Указываем в файле /opt/ovpn-freeradius-lldap/freeradius/freeradius-config/clients.conf
настройки для подключения клиентов.
client docker-net {
ipv4addr=172.21.2.0/24
secret=MOhqCOukFGp02lRC
proto=udp
nas_type=other
}
Установим разрешения для файлов.
sudo chmod -R 600 /opt/ovpn-freeradius-lldap/freeradius/freeradius-config/mods-enabled
sudo chmod -R 600 /opt/ovpn-freeradius-lldap/freeradius/freeradius-config/sites-enabled
sudo chmod 600 /opt/ovpn-freeradius-lldap/freeradius/freeradius-config/clients.conf
Запускаем контейнеры и убеждаемся, что нет сообщений об ошибках.
sudo docker-compose -f /opt/ovpn-freeradius-lldap/docker-compose.yaml up
Журнал FreeRADIUS пишется в /opt/ovpn-freeradius-lldap/freeradius/logs/radius.log
.
Проверяем возможность подключиться тестовым пользователем, который будет использоваться плагином openvpn-multi-authentication-plugin
для мониторинга работоспособности аутентификации с выбранными серверами.
Напомним, что пользователей и группу мы создали на шаге "Создание пользователей". Перед тестированием убедитесь, что:
в файле
/opt/ovpn-freeradius-lldap/freeradius/freeradius-plugin/strongpass-otp/config.yml
значение параметраauth_test_user
совпадает с логином выбранного нами пользователя (в нашем случаеuser-test1
). Для указанного в этом параметре пользователя проверка OTP не производится.пользователи
user-test1
,user-test2
входят в группуotp-vpn-users
.в файле
/opt/ovpn-freeradius-lldap/freeradius/freeradius-plugin/strongpass-otp/config.yml
в значении параметраldap.search_filter
указана группаotp-vpn-users
.
Скачиваем последнюю версию плагина из раздела "Releases" репозитория openvpn-multi-authentication-plugin. В архиве находится radius-client
, который позволит протестировать нам правильность взаимодействия FreeRADIUS, плагина FreeRADIUS и LDAP сервера.
Выполняем команду (вместо <пароль>
укажите свое значение). Значение параметра -s
должно совпадать со значением параметра secret
в /opt/ovpn-freeradius-lldap/freeradius-config/clients.conf
./radius-client --addr 172.21.2.4:1812 --proto pap -u user-test1 -p <пароль> -s MOhqCOukFGp02lRC
Если мы получили код ответа Access-Reject
, то необходимо проверить журнал FreeRADIUS (/opt/ovpn-freeradius-lldap/freeradius/logs/radius.log
) на предмет ошибок.
В случае успеха ответ будет следующий:
Settings from command line:
Server: 172.21.2.4:1812
Secret: MOhqCOukFGp02lRC
Username: user-test
Password: 5bc5ce448a71
Protocol: pap
NAS ID:
NAS Port: 443
Response contents
Code: 2, Access-Accept
Service Type: ServiceType(0)
Framed-Protocol: FramedProtocol(0)
Framed-IPAddress: <nil>
Framed-Netmask: <nil>
Framed-Routing: None
MS-Primary-DNS-Server: <nil>
MS-Secondary-DNS-Server: <nil>
Теперь протестируем аутентификацию пользователя с OTP. OTP указывается сразу после пароля (6 цифр). Пример: password349307
.
./radius-client --addr 172.21.2.4:1812 --proto pap -u user-test2 -p <пароль + OTP код> -s MOhqCOukFGp02lRC
При успешной проверке OTP и логина/пароля мы получим ответ Access-Accept
:
Settings from command line:
Server: 172.21.2.4:1812
Secret: MOhqCOukFGp02lRC
Username: user-test2
Password: 5bc5ce448abad489327
Protocol: pap
NAS ID:
NAS Port: 443
Response contents
Code: 2, Access-Accept
Service Type: ServiceType(0)
Framed-Protocol: FramedProtocol(0)
Framed-IPAddress: <nil>
Framed-Netmask: <nil>
Framed-Routing: None
MS-Primary-DNS-Server: <nil>
MS-Secondary-DNS-Server: <nil>
При отсутствии ошибок можно переходить к настройке OpenVPN.
Если FreeRADIUS и плагин будут использоваться с любым другим VPN шлюзом, способным аутентифицировать пользователей по протоколу RADIUS, то на этом настройка закончена, и система готова к работе.
Плагин для OpenVPN
Плагин состоит из двух частей: непосредственно плагин для OpenVPN и сервис аутентификации. Сервис аутентификации нужен для того, чтобы в случае использования RADIUS не передавать пароль в открытом виде по сети.
Скачиваем последнюю версию плагина из раздела "Releases" репозитория
openvpn-multi-authentication-plugin. Т.к. используется Debian 12, нам нужен файл openvpn-multi-authentication-plugin-linux-libssl3-amd64.tar.gz
. Копируем из скачанного архива каталоги auth-service
и openvpn-plugin
в /opt/ovpn-freeradius-lldap/openvpn
. Указываем в файле /opt/ovpn-freeradius-lldap/openvpn/auth-service/config.yml
нужные значения параметров. Комментарии к каждому параметру можно найти в самом файле config.yml
. Содержание файла:
web_server:
listen_address: 127.0.0.1
port: 11245
auth_api_key: 7a8lkmq73z15x06guhuh
https:
enable: false
private_key: ""
certificate: ""
status:
enable: false
path: ""
api_key: ""
log:
file: /var/log/auth-service.log
level: error
auth_provider:
type: radius
auth_check:
enable: false
radius:
nas_id: "openVPN"
nas_ipv4_address: ""
nas_port: 443
servers:
# параметры подключения к FreeRADIUS
- name: server1
address: 172.21.2.4
port: 1812
protocol: pap
secret: MOhqCOukFGp02lRC
response_timeout_sec: 15
Создаем файл /etc/systemd/system/auth-service.service
следующего содержания:
[Unit]
Description=OpenVPN plugin. Auth Service
After=network.target
Wants=network.target
[Service]
Type=simple
ExecStart=/opt/ovpn-freeradius-lldap/openvpn/auth-service/auth-service -config /opt/ovpn-freeradius-lldap/openvpn/auth-service/config.yml
[Install]
WantedBy=multi-user.target
Запускаем сервис и проверяем журнал на наличие ошибок:
systemctl enable --now auth-service
journalctl -xeu auth-service.service
systemctl status auth-service
В случае отсутствия ошибок в журналах systemd
и auth-service
проверяем, что можем аутентифицироваться с помощью тестового пользователя user-test1
. Значение заголовка X-Api-Key
берем из параметра web_server.auth_api_key
файла /opt/ovpn-freeradius-lldap/openvpn/auth-service/config.yml
. Вместо <user_password>
укажите свое значение.
curl -H "X-Api-Key: 7a8lkmq73z15x06guhuh" -X POST --data '{"u": "user-test1", "p": "<user_password>", "client_ip": "127.0.0.1"}' -i http://127.0.0.1:11245/auth
При успешной аутентификации получим ответ с кодом 200.
Важно! После окончания проверки в файле /opt/ovpn-freeradius-lldap/freeradius/freeradius-plugin/strongpass-otp/config.yml
установите otp_option: 1
и перезапустите контейнеры. OpenVPN передает пароль и OTP в закодированном формате. В случае несоответствия настроек плагина FreeRADIUS аутентификация клиентов OpenVPN не будет успешной.
Далее настраиваем непосредственно плагин OpenVPN. Указываем в файле /opt/ovpn-freeradius-lldap/openvpn/openvpn-plugin/config.yml
нужные значения параметров. Комментарии к каждому параметру можно найти в самом файле config.yml
.
Важно! Значение параметра:
auth_service.url
должно соответствовать значениямweb_server.listen_address
,web_server.port
,https.enable
конфигурационного файлаauth-service
.auth_service.api_key
должно совпадать со значениемweb_server.auth_api_key
конфигурационного файлаauth-service
.
Содержание /opt/ovpn-freeradius-lldap/openvpn/openvpn-plugin/config.yml
:
https_verify_cert: false
auth_service:
- name: Service 1
url: http://127.0.0.1:11245
api_key: 7a8lkmq73z15x06guhuh
monitoring:
# т.к. мониторинг в нашем примере не используется, то оставляем значения по умолчанию.
path: /monitor/12345
api_key: 123456789
log:
file: /var/log/openvpn-plugin.log
level: error
auth:
connect_timeout_sec: 5
monitoring:
enable: false
check_interval_sec: 5
Сервер OpenVPN
Настройка сервера OpenVPN с нуля не будет подробно описываться, т.к. в интернете есть много статей на эту тему. Остановимся только на основных моментах и особенностях настройки. Предполагается, что на сервере установлен OpenVPN версии не ниже: 2.6.3.
OpenVPN и плагин к нему работает непосредственно в операционной системе, а не в Docker-контейнере. Пользователям не требуются индивидуальные сертификаты для подлючения к серверу. Для аутентификации пользователей используется логин, пароль и OTP.
Пример конфигурационного файла сервера.
dev tun
port 443
proto tcp4
persist-tun
persist-key
data-ciphers CHACHA20-POLY1305:AES-256-GCM:AES-256-CBC
data-ciphers-fallback AES-256-CBC
auth SHA512
tls-server
resolv-retry infinite
auth-nocache
reneg-sec 0
keepalive 10 120
tls-version-min 1.2
verify-client-cert none
topology subnet
server 192.168.200.0 255.255.255.0
#push "redirect-gateway def1"
push "route 192.168.200.0 255.255.255.0"
push "dhcp-option DNS 192.168.200.2"
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DOMAIN acme.corp"
push "dhcp-option DOMAIN-SEARCH acme.corp"
ca /etc/openvpn/server/ca.crt
cert /etc/openvpn/server/openvpn-server.crt
key /etc/openvpn/server/openvpn-server.key
dh /etc/openvpn/server/dh.pem
tls-crypt /etc/openvpn/server/ta.key
plugin /opt/ovpn-freeradius-lldap/openvpn/openvpn-plugin/libopenvpn_auth_plugin.so --config /opt/ovpn-freeradius-lldap/openvpn/openvpn-plugin/config.yml
status /var/log/openvpn-status.log
log /var/log/openvpn.log
verb 4
Ключевые параметры, определяющие логику аутентификации:
verify-client-cert none
plugin /opt/ovpn-freeradius-lldap/openvpn/openvpn-plugin/libopenvpn_auth_plugin.so --config /opt/ovpn-freeradius-lldap/openvpn/openvpn-plugin/config.yml
Запускаем сервер OpenVPN и проверяем журналы сервера и плагина на наличие ошибок.
Клиент OpenVPN
В конфигурационном файле клиента нужно добавить параметр static-challenge "Введите одноразовый пароль" 1
. После этого в графическом интерфейсе клиента OpenVPN для Windows и в TunnelBlick для MacOS будет показываться отдельное поле для ввода OTP. В Linux при запуске openvpn из командой строки будет дополнительно запрошен OTP.
Пример конфигурационного файла клиента:
dev tun
persist-tun
persist-key
data-ciphers CHACHA20-POLY1305:AES-256-GCM:AES-256-CBC
data-ciphers-fallback AES-256-CBC
auth SHA512
tls-client
client
resolv-retry infinite
remote vpn1.acme.corp 443 tcp4
remote vpn2.acme.corp 443 tcp4
remote vpn3.acme.corp 443 tcp4
server-poll-timeout 10
lport 0
auth-user-pass
auth-nocache
verify-x509-name "openvpn.acme.corp" name
remote-cert-tls server
reneg-sec 0
allow-pull-fqdn
verb 4
setenv CLIENT_CERT 0
static-challenge "Введите одноразовый код" 1
<ca>
-----BEGIN CERTIFICATE-----
MIIB9TCCAXygAwIBAgIUNArxOIYVEI6U9C6GC8hK5yIfk98wCgYIKoZIzj0EAwQw
................................................................
I0QfT71JPXFUAnIbgVDh4DZfZ6k4uUECMA9C2ypGO2ezDjO5rF+odCW1F1DeiIWD
PvoUN4aHG4Y7/cxGIP9fK6MWq8TYxRCqbg==
-----END CERTIFICATE-----
</ca>
<tls-crypt>
#
# 2048 bit OpenVPN static key
#
-----BEGIN OpenVPN Static key V1-----
035d7bb282df6c5b981c2b733d6051a8
................................
08ab402ee7605146e38ef097979f1ebc
-----END OpenVPN Static key V1-----
</tls-crypt>
Ключевые параметры конфигурации клиента касающиеся аутентификации:
auth-user-pass
setenv CLIENT_CERT 0
static-challenge "Введите одноразовый код" 1
Пробуем подключиться к серверу OpenVPN под учетной записью user-test2
с указанием одноразового пароля (настройка генератора OTP производилась на шаге "Управление секретами генератора OTP").
На этом настройка закончена, система готова к эксплуатации.
CodARM
Одно и то же... Похоже пора писать статью "Настройка 2FA openvpn без использования FreeRADIUS и LDAP". Там жеж проще простого, но почему-то нигде этого нет.