
Вступление
Всем привет! Хотелось бы поделиться результатом своих наработок по небольшому личному проекту. Некоторое время назад пришлось покопаться в FreeRADIUS, и я подумал, почему бы не попробовать реализовать схему со вторым фактором для давно используемого Ocserv.
Дисклеймер
Хочу обратить ваше внимание, что содержание этой статьи — это работающий концепт, а не готовый продукт, который можно использовать в production-окружениях. Поэтому у нас будут множественные допущения, цель которых — упростить реализацию для лучшего понимания. В частности, мы не будем затрагивать темы безопасности, маршрутизации трафика и разделения привилегий.
С чего начнем
Синхронизация времени
TOTP генерируется на основе текущего времени. Если время на сервере и на устройстве клиента рассинхронизировано, сервер вычислит другое значение и не сможет подтвердить корректный одноразовый пароль, что приведёт к ложному отклонению доступа. Поэтому убедитесь, что на устройстве для генерации кода и на вашем сервере одинаковое время.
Окружение
В моем случае я использовал довольно стандартный стек:
Docker 29
Ubuntu 24.04
GIT
Google Authenticator (или любой подобный продукт)
Клонируем репозиторий
git clone https://github.com/scorsair/ocserv-freeradius-freeipa-totp.git cd ocserv-freeradius-freeipa-totp
Сертификаты
Для работы Ocserv нам понадобятся сертификаты. Можете использовать certbot с вашим доменом или сделать проще и быстрее для теста:
cd ocserv openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 -subj "/CN=ocserv.ipa.local" cd -
Запуск и настройка сервисов
Поднимаем контейнеры
docker compose up -d # Первый запуск может занять продолжительное время из-за инициализации FreeIPA docker compose logs -f freeipa # Дожидаемся вывода "FreeIPA server started" # Убеждаемся в том, что все три контейнера запущены и не имеют периодических рестартов docker compose ps --status running
Ручные шаги
docker compose exec freeipa bash # Добавляем FreeRADIUS аттрибуты в схему LDAP нашей FreeIPA ipa-ldap-updater -S /usr/share/dirsrv/data/60radius.ldif ipactl restart # Auth kinit admin # Вводим пароль: 9g5xTFf29b0C92Rz # Добавляем новый ObjectClass для будущих пользователей по умолчанию ipa config-mod --addattr=ipaUserObjectClasses=radiusprofile # Для пользователя admin добавляем принудительно ipa user-mod --addattr=objectClass=radiusprofile admin # Добавляем RADIUS аттрибуты для пользователя admin, эти значения будут перехватываться FreeRADIUS и перенаправляться в Ocserv ipa user-mod admin --setattr="radiusFramedIPAddress=10.255.255.170" ipa user-mod admin --setattr="radiusFramedIPNetmask=255.255.255.255" ipa user-mod admin --setattr="radiusFramedRoute=10.255.255.0/24" ipa user-show admin --all | grep radius
OTP
Теперь нам нужно создать OTP-секрет для пользователя admin. Результатом выполнения команды будет QR-код, который надо отсканировать приложением Google Authenticator
ipa otptoken-add --type=totp --owner=admin
Привилегии
Так как мы используем того же пользователя admin для интеграции FreeRADIUS с FreeIPA, создадим необходимые привилегии и роли, которые назначим ему:
# Permissions ipa permission-add --attrs=userpassword --right='read' 'Read UserPassword' --type=user ipa permission-add --attrs={radiusframedipaddress,radiusframedipnetmask,radiusframedroute} --right='read' 'Read RadiusAttr' --type=user ipa permission-add --attrs={ipatokenOTPkey,ipatokenOwner,ipatokenUniqueID} --right={read,search} 'Read OTP' # Privilege ipa privilege-add 'Radius Server' ipa privilege-add-permission 'Radius Server' --permissions={'Read UserPassword','Read RadiusAttr','Read OTP'} # Role ipa role-add 'Radius' ipa role-add-privilege 'Radius' --privileges='Radius Server' # Назначаем роль ipa role-add-member --users=admin 'Radius'
Вот и все, можно подключаться)
Подключение
Для подключения можно использовать OpenConnect VPN for Windows или Cisco AnyConnect. Так как у нас всё развернуто локально, используем URL: https://127.0.0.1. Вводим логин и OTP-код, подключаемся.
