Еще в пандемийные годы стало понятно, что жить без двухфакторки на удаленке, как минимум, рискованно. И хоть большинство приложений и обеспечивают 2FA, все-таки существуют сервисы, для которых защищенный доступ из коробки недоступен. Я Саша Зеленов, архитектор Cloud.ru, и сегодня я поделюсь с вами опытом, как мы настроили у себя двухфакторную аутентификацию для веб-приложений, которые сопротивляются прогрессу.
В продуктовом каталоге Cloud.ru есть несколько вендорских сервисов, в которые не заложили возможность подключения двухфакторной аутентификации, или предлагаемая функциональность нас по ряду причин не устраивала.
В частности, можно отметить сервисы VMware — (Cloud Director Availability и Horizon), Veeam (Cloud Connect, Service Provider Console) и ряд других.
Например, в рамках услуги VDI (Виртуальные рабочие места) нам требовалось сделать доступной для пользователей за пределами локальной сети Horizon Admin Console, чтобы администраторы наших клиентов могли управлять своей инфраструктурой виртуальных рабочих мест.
Вендором предусмотрен только один способ 2FA для доступа к консоли администратора — смарт-карта, которая потребует от нас физической передачи специальных карт и считывателей для них клиенту. Еще возможна настройка доступа по сертификату, что также потребует от клиента настройки своего ПК для возможности работы с консолью.
Из-за сложности организации подобных работ — закупка, передача, обслуживание оборудования, нам такой способ не подходит. А в случае с сертификатом еще и потенциальный взлом/утеря ПК приводит к тому, что у злоумышленника есть доступ к «второму фактору».
Еще один пример: приложение Veeam Cloud Connect, которое используется в другой нашей услуге — Резервное копирование в облако. Веб-консоль предоставляет администраторам услуги возможность управлять заданиями резервного копирования и следить за их статусом. И всё это в тесной связке с VMware Cloud Director (vCD).
Но и тут мы столкнулись с тем, что вендор еще не реализовал подходящий нам сценарий — тот, в котором есть возможность подключить Veeam Cloud Connect к SAML/OpenID провайдеру в связке с VMware Cloud Director. Вот что ответила техническая поддержка Veeam:
Я проверил нашу внутреннюю документацию и провёл несколько тестов: к сожалению, BEM Self-Service портал для vCD не поддерживает SAML-аутентификацию. Как обходное решение, я могу предложить настроить SAML-аутентификацию в самом vCD, но работать это будет только при использовании Self-Service портала из консоли vCD: https://helpcenter.veeam.com/docs/backup/em/vcd_portal_access.html?ver=120#accessing-veeam-self-service-backup-portal-from-vmware-cloud-director
Также в нашей системе открыт Feature Request для добавления данного функционала. К сожалению, на данный момент, сроки внедрения данного функционала неизвестны.
С уважением,
Техническая поддержка Veeam
На выходе мы имеем ситуацию, где у нас нет возможности внести изменения в код вендорского ПО, чтобы обеспечить должный уровень безопасности. В таком случае мы должны попробовать защитить хотя бы канал, по которому пользователи получают доступ к приложению.
Обычно подобные задачи решаются с помощью VPN: многие VPN-клиенты поддерживают интеграцию с системами, реализующими проверку второго фактора перед подключением. Но это требует установки и настройки клиентского ПО, что в удаленном формате работы не очень дружелюбно для пользователей. К тому же такой вариант не предусматривает возможности разграничить уровни доступа для сотрудников компании, что требуется и у многих заказчиков, и у нас самих. Поэтому мы в Cloud.ru придумали свой, альтернативный способ.
Что придумали мы
Основные компоненты
Для реализации альтернативы мы взяли следующее:
Reverse Proxy с функционалом OpenID Client. Мы использовали свободно распространяемый OAuth2 Proxy, который разместили в DMZ.
IAM (Identity Access Management) в качестве провайдера OpenID для предварительной верификации первого и второго факторов. Мы использовали IAM собственной разработки. В качестве альтернативы можно выбрать ADFS, Keycloak и другие популярные провайдеры, которые поддерживает OAuth2Proxy (полный список есть в документации).
Схема работы
В нашем представлении процесс аутентификации пользователей может быть построен следующим образом:
Пользователь открывает в браузере страницу с веб-приложением (1). Запрос от пользователя к приложению всегда обрабатывает OAuth2Proxy — он проверяет наличие и актуальность сессионной куки. Если они есть, то проксирует трафик к приложению (6). Если куки просрочены или пока не дошли — перенаправляет пользователя на веб-страницу IAM (2).
IAM в свою очередь запрашивает у пользователя данные для аутентификации. В нашем случае пользователь будет вводить логин и пароль от личного кабинета Cloud.ru (3) (в вашем случае это может быть логин и пароль Active Directory), а также одноразовый код (OTP) (4), сгенерированный на устройстве пользователя. При успехе IAM возвращает пользователя на OAuth2Proxy (5).
OAuth2Proxy генерирует куку и проксирует трафик к приложению (6).
Подготовка
В статье я не буду подробно описывать этап установки и настройки IAM, а также подготовку инфраструктуры. Расскажу только про то, что необходимо перед установкой Oauth2Proxy в режиме ReverseProxy:
Настроить IAM на работу по протоколам OpenID (в статье рассматриваем его) или SAML. Для настройки OpenID вам потребуется:
oidc_issuer_url — адрес конфигурации OpenID. Например, для Keycloack http://keycloakhost:keycloakport/auth/realms/{realm}/.well-known/openid-configuration.
client_id — согласованный и зарегистрированный в IAM идентификатор OpenID Client.
client_secret — сложная парольная фраза.
Зарегистрировать в IAM пользователя, включить для него 2FA и настроить приложение OTP (например, Google Authenticator, Яндекс Ключ и т. п.) на смартфоне пользователя.
Подготовить виртуальную машину (или физический сервер), на котором будет установлен Oauth2Proxy:
Установить ОС (на сайте проекта доступны собранные пакеты под Linux, FreeBSD, а также Docker Image и Kubernetes manifest (Helm)).
Сконфигурировать сетевые интерфейсы.
Настроить сетевую связность и разрешения до IAM и защищаемого приложения.
Настроить доступ в интернет для скачивания дистрибутивов.
Зарегистрировать в DNS А-запись, по которой пользователи будут подключаться к приложению (публичный интерфейс Oauth2Proxy). Также эта DNS-запись потребуется для настройки IAM — этот адрес необходимо использовать в качестве Valid Redirected URL.
Выпустить сертификат и ключ, которые покрывают выбранное на предыдущем шаге доменное имя.
Установка и запуск решения
В нашем примере:
ОС — Ubuntu 20.04,
https://iam.company.ru/auth/system — адрес тестового IAM,
https://webapp.company.ru — внешний адрес приложения,
https://webapp.localcompany.ru — внутренний адрес приложения (недоступен из интернета).
Приступим к установке решения на развернутую на шаге 3 виртуальную машину.
Создаем каталог для размещения дистрибутива:
sudo mkdir /opt/oauth2proxy
cd /opt/oauth2proxy
Скачиваем архив с дистрибутивом (актуальные ссылки для вашей ОС есть на github)
sudo wget https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v7.5.0/oauth2-proxy-v7.5.0.linux-amd64.tar.gz
Извлекаем дистрибутив из архива, делаем файл исполняемым:
sudo tar -xvzf oauth2-proxy-v7.5.0.linux-amd64.tar.gz --strip-components=1
sudo chmod +x oauth2-proxy
Теперь генерируем Cookie Secret и сохраняем полученное значение (его будем использовать дальше в конфигурационном файле):
dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | tr -d -- '\n' | tr -- '+/' '-'; echo
Создаем конфигурационный файл:
sudo vim oauth.cfg
Пример файла можно взять наш — в нем не все доступные настройки. Или на сайте проекта — там полный список.
Важно: команды в этой таблице представлены для CLI. Чтобы необходимый параметр можно было использовать в конфигурационном файле, необходимо заменить «–» на «_» (например, вместо --logging-filename
использовать logging_filename
).
## OAuth2 Proxy Config File
## https://github.com/oauth2-proxy/oauth2-proxy
## <addr>:<port> to listen on for HTTP/HTTPS clients
https_address = ":443" ##указываем какой порт будет использовать приложение
## пути для сертификата и закрытого ключа к нему - требуется для приложений использующих https соединение. В нашем примере – здесь сертификат, который покрывает внешний адрес webapp.company.ru
tls_cert_file = "/etc/crt/certificate.pem"
tls_key_file = "/etc/crt/certKey.key"
upstreams = [ "https://webapp.localcompany.ru" ] #указываем адрес защищаемого приложения в локальной сети
skip_provider_button = "true" #позволяет не показывать страницу Oauth2Proxy, а сразу перенправляет в IAM
oidc_issuer_url = "https://iam.company.ru/auth/system" #Пример для Keyсloack https://keycloakhost:keycloakport/auth/realms/{realm}/.well-known/openid-configuration
#Настройка позволяет указать список пользователей, кому разрешён доступ к приложению. * - любой пользователь IAM, который успешно прошёл аутентификацию по первому и второму фактору.
email_domains = [
"*"
]
provider = "oidc" #В нашем примере мы используем OpenId Client
scope = "openid"
redirect_url = "https://webapp.company.ru:443/oauth2/callback" #В качестве FQDN указываем внешний адрес публикуемого приложения; /oauth2/callback стандартный для Oauth2Proxy путь, на котором работает OpenId Connect. Для Keycloack - provider=keycloak полный список провайдеров тут
client_id = "client_id_from_IAM_provider" #ID клиента, который предварительно зарегистрирован в IAM
client_secret = "veryStr0nG!!SecRet_From_I@M_provider"
cookie_secret = "genereted_cookie_secret" #Секрет, который мы ранее генерировали командой dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | tr -d -- '\n' | tr -- '+/' '-_'; echo
cookie_expire = "6h" #Срок жизни куки. Определяет, как часто вашим пользователям придётся проходить повторную аутентификацию
Теперь проверяем, запустилось ли приложение Oauth2Proxy и правильно ли оно перенаправляет на страницу IAM:
sudo ./oauth2-proxy --config=./oauth2-proxy.cfg
При переходе по внешнему адресу приложения https://webapp.company.ru пользователь должен автоматически попасть на страницу IAM:
Затем система запросит второй фактор:
При успешном вводе первого и второго факторов пользователь должен оказаться на защищенном ресурсе:
Если всё работает, настраиваем автоматический запуск при загрузке системы, чтобы пользователю не пришлось совершать лишних действий. Добавляем Unit в systemd:
vim /etc/systemd/system/oauth-proxy.service
[Unit]
Description=oauth2-proxy daemon service
After=syslog.target network.target
[Service]
ExecStart=/opt/oauth2proxy/oauth2proxy --config=/opt/oauth2proxy/oauth.cfg $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=always
[Install]
WantedBy=multi-user.target
Запускаем сервис командой:
systemctl start oauth2-proxy
Активируем сервис, чтобы он стартовал при рестарте ОС:
systemctl enable oauth2-proxy
Готово.
Что в итоге?
Вот таким нехитрым образом нам удалось наладить доступ верифицированных пользователей даже к приложениям, которые этого не предполагают. К плюсам описанного решения можно отнести:
Доступность. Всё что нужно — виртуальная машина на Linux, бесплатная Oauth2Proxy и любое OTP приложение на устройстве пользователя, при условии, что в компании уже используется какой-то провайдер 2FA;
Универсальность. Если уже есть legacy в виде сторонних продуктов, двухфакторку можно сделать с помощью такого лайфхака;
Удобство. Нам как провайдеру не надо организовывать закупку и доставку всяких физических карт и считывателей на сторону клиента, админам клиента не нужно бить тревогу в случае утери карты или устройства с сертификатом, а самому клиенту не нужно устанавливать никакого специфического ПО — все манипуляции проходят в окне браузера.
Среди недостатков, если уж придираться, можно выделить:
стойкую аллергию безопасников некоторых структур на любое не до конца отечественное ПО, даже если оно open source;
не во всех случаях получится настроить SSO в защищаемое приложение, поэтому пользователям может потребоваться ввести логин и пароль дважды. Сначала на странице IAM, а потом уже в самом приложении (но это уже целых 5 факторов, что, конечно, должно понравиться безопасникам ?).
Интересное в блоге: