Как защитить HTTP-ресурсы без VPN
Статья описывает технологию Forward Auth как альтернативу VPN для защиты внутренних HTTP-сервисов в условиях блокировок РКН
По хорошему все технические и системные сервисы — Git, Docker Registry, внутренняя админка и т.д. — должны находиться во внутренней сети, чтобы предотвратить доступ к ним не только на уровне HTTP, но и на уровне сети. Это связано с тем, что некоторый софт может быть устаревшим, и в нем могут быть найдены CVE, которые позволяют навредить системе. Как правило, такие системы являются Open Source, что увеличивает потенциальный поиск уязвимостей. По хорошему нужно держать такие приложения всегда обновленными. Большинство стандартных систем не поддерживает автоматическое противодействие brute force атакам, а при неправильных настройках могут отображать приватную информацию, которая не видна невооруженным глазом. Чтобы упростить себе работу и не разбираться с каждым сервисом подробно, мудро будет изолировать их от внешнего мира, чтобы не давать потенциальных направлений для атаки.
Стоит напомнить, что все сертификаты Let’s Encrypt, выданные на ваши домены, отображаются на crt.sh (Certificate Transparency logs), что позволяет заинтересованным лицам раскрыть вашу инфраструктуру. За этим стоит механизм подписи выдачи сертификатов SCT, чтобы их нельзя было подсунуть клиенту. Это можно обойти через регистрацию wildcard-сертификата, который скрывает все поддомены, но требует DNS-01 challenge для управления.
VPN как стандарт
Обычно такие сервисы прячутся за VPN — WireGuard, OpenVPN, IPSec и других технологиях. Это позволяет скрыть все сервисы во внутренней сети, а внутренние сотрудники подключаются к VPN для пользования ими. В принципе это de facto стандарт индустрии, и все крупные компании имеют свой корпоративный частный VPN. Это удобно и для внутренней разработки, когда необходимо подключаться к stage базам данных, очередям и прочим компонентам системы. Трафик через VPN обычно зашифрован современными алгоритмами, которые препятствуют его расшифровке, даже если он был перехвачен между узлами.
Но если ваша инфраструктура расположена не в России, а подключиться нужно из России — в современных реалиях российского интернета, где РКН агрессивно блокирует трафик, это может быть нетривиальной задачей. На практике РКН сразу блокирует такие протоколы на ТСПУ, как WireGuard, потому что он имеет уникальный fingerprint и его легко отследить. OpenVPN сложнее, но тоже возможно на уровне DPI. Есть возможности с obfuscated техниками и отдельными прокси-узлами, но гарантию стабильной работы никто дать не может. Мы не будем останавливаться на этом.
Остается потребность подключиться к внутренним сервисам своей системы из России и при этом не открывать их всем наблюдателям.
Forward Auth
В отсутствии возможности использовать VPN приходит на ум базовая HTTP Auth — это будет работать, но придется настраивать каждый сервер отдельно, и нативное браузерное окно аутентификации зачастую выглядит довольно грубо. Разбирая этот механизм глубже, можно прийти к идее определенного cookie, которое должно присутствовать в запросе чтобы получить доступ. Это избавит от ввода логина и пароля каждый раз.
Эта технология называется Forward Auth. На ingress/nginx настраивается дополнительная прослойка, которая проверяет необходимое cookie в запросах. В случае его отсутствия происходит редирект на страницу аутентификации с последующим возвратом к сервису. Это удобно: вводить логин и пароль больше не придется, сессия зависит от времени активности — может быть неделя, а может и месяц. А все ресурсы, защищенные этой прослойкой, сразу становятся доступны после однократного входа. Простое и современное решение для аутентификации во внутренние ресурсы через HTTP.
Выбор провайдера
Основные популярные провайдеры: KeyCloak, Authelia, Authentik.
KeyCloak - Enterprise решение от Red Hat, написано на Java. Полноценный комбайн с поддержкой OAuth2, OIDC, SAML, федерацией пользователей через LDAP/AD, концепцией realms (мультитенантность). Имеет тяжелую админку с детальной настройкой. Минусы очевидны: требует JVM, в простое легко съедает 500MB-1GB RAM, конфигурация сложная, кривая обучения крутая. Для задачи “защитить пару HTTP-сервисов через Forward Auth” это стрельба по воробьям из пушки. Имеет смысл только если уже есть Java-стек или нужен полноценный IdP с federation для крупной компании. Кстати, Forward Auth там нативно не поддерживается — нужен дополнительный прокси типа oauth2-proxy или traefik-forward-auth.
Authelia - Легковесный сервис, написан на Go, образ ~50MB. Конфигурируется через YAML-файлы, для хранения сессий и устройств 2FA подходит SQLite, MySQL или PostgreSQL. Из коробки поддерживает TOTP, WebAuthn, Duo Push. Встроена защита от brute force (regulation), которая блокирует пользователя после N неудачных попыток. Главный минус — отсутствует UI для управления пользователями: юзеры либо описываются в файле users_database.yml, либо подключается отдельный LLDAP контейнер с веб-панелью. Зато сервис делает свою задачу четко: проверяет cookie, отдает заголовки Remote-User, Remote-Groups и т.д. в Forward Auth, работает быстро и потребляет копейки ресурсов. Идеален когда нужна защита N сервисов без лишнего обвеса.
Authentik - Современный IdP на Python/Django. Образ потяжелее Authelia (~200MB + worker + redis + postgres), но всё равно легче KeyCloak. Имеет полноценную современную админку, поддержку SSO (OAuth2, OIDC, SAML), LDAP outpost для подключения LDAP-only приложений, self-service портал для пользователей, 2FA из коробки. Killer-feature — flow-based аутентификация: можно собирать произвольные сценарии из стадий (stages): проверка пароля, MFA, captcha, согласие, email верификация и т.д. в любом порядке. Это дает гибкость, которой нет у Authelia. Подходит когда нужно среднее между минимализмом Authelia и махиной KeyCloak, либо когда планируется выдавать SSO внешним сервисам, а не только Forward Auth для своих. Активно развивается, релизы каждые пару месяцев.
Краткая таблица для выбора:
| KeyCloak | Authelia | Authentik | |
|---|---|---|---|
| Язык | Java | Go | Python |
| RAM в простое | 500MB-1GB | ~30MB | ~200MB |
| Управление пользователями | Да | Только файл / LLDAP | Да |
| Forward Auth | Через прокси | Нативно | Нативно |
| SSO (OAuth2/OIDC) | Да | Ограниченно | Да |
| Brute force защита | Да | Да | Да |
| Когда использовать | Enterprise + AD | Просто и быстро | Баланс + гибкость |
Настройка Authelia с Traefik
Я рассмотрю настройку аутентификации на Traefik через Authelia, но это можно сделать и через Nginx, Ingress (K8s).
docker-compose.yml
1services:
2 traefik:
3 image: traefik:v3.4.1
4 command:
5 - --entrypoints.web.address=:80
6 - --entrypoints.websecure.address=:443
7 - --providers.docker=true
8 - --providers.docker.exposedByDefault=false
9 - --api.dashboard=true
10 - --api.insecure=true
11 ports:
12 - "80:80"
13 - "443:443"
14 - "8080:8080"
15 volumes:
16 - /var/run/docker.sock:/var/run/docker.sock:ro
17 networks:
18 - proxy
19
20 authelia:
21 image: authelia/authelia:4.39.17
22 user: "1000:1000"
23 volumes:
24 - ./authelia:/config
25 networks:
26 - proxy
27 labels:
28 - "traefik.enable=true"
29 - "traefik.http.routers.authelia.rule=Host(`auth.lvh.me`)"
30 - "traefik.http.routers.authelia.entrypoints=websecure"
31 - "traefik.http.routers.authelia.tls=true"
32 - "traefik.http.services.authelia.loadbalancer.server.port=9091"
33 - "traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/authz/forward-auth"
34 - "traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true"
35 - "traefik.http.middlewares.authelia.forwardauth.maxResponseBodySize=8192"
36 - "traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email"
37
38 whoami:
39 image: traefik/whoami:v1.11
40 networks:
41 - proxy
42 labels:
43 - "traefik.enable=true"
44 - "traefik.http.routers.whoami.rule=Host(`whoami.lvh.me`)"
45 - "traefik.http.routers.whoami.entrypoints=websecure"
46 - "traefik.http.routers.whoami.tls=true"
47 - "traefik.http.routers.whoami.middlewares=authelia@docker"
48
49networks:
50 proxy:
authelia/configuration.yml
1server:
2 address: tcp://0.0.0.0:9091
3
4authentication_backend:
5 file:
6 path: /config/users_database.yml
7 password:
8 algorithm: argon2id
9
10identity_validation:
11 reset_password:
12 # генерируется через openssl rand -hex 32
13 jwt_secret: change_me_jwt_secret_32chars_min
14
15session:
16 secret: change_me_session_secret
17 cookies:
18 - domain: lvh.me
19 authelia_url: https://auth.lvh.me
20 expiration: 1h
21 inactivity: 5m
22
23storage:
24 # генерируется через openssl rand -hex 32
25 encryption_key: change_me_storage_key_32chars_min
26 local:
27 path: /config/db.sqlite3
28
29notifier:
30 filesystem:
31 filename: /config/notifications.txt
32
33access_control:
34 default_policy: deny
35 rules:
36 - domain: "whoami.lvh.me"
37 policy: one_factor
Чтобы сгенерировать хеш пароля для пользователя:
1docker run --rm authelia/authelia:4.39.17 authelia crypto hash generate argon2 --password 'yourpassword'
authelia/users_database.yml
1users:
2 admin:
3 displayname: "Admin"
4 password: "$argon2id$v=19$m=65536,t=3,p=4$94UKNcJ9+1lSucGtgqavMQ$10Pm8VixokKfYyjdmj5Cpx6OmbsKv9xmtrMGE5A6mG0"
5 email: admin@example.com
6 groups: [admins]
Поднимаем через docker compose up.
Будут проблемы с HTTPS-сертификатами, поскольку CA локальный. Мы использовали домен lvh.me, который всегда ссылается на 127.0.0.1 — это позволяет обойти ограничение Authelia, которая начиная с версии 38 требует HTTPS. При заходе на https://whoami.lvh.me/ вас перекинет на страницу аутентификации https://auth.lvh.me, и после успешной авторизации вернет обратно, отобразив HTTP-заголовки.
О минусах подхода
VPN может работать на разных уровнях модели OSI, что позволяет использовать его не только для HTTP, но и для любых TCP и UDP соединений. Это очевидное преимущество, поскольку можно подключаться к разнообразным сервисам и SSH. При Forward Auth такие сервисы остаются открытыми — нужно обязательно использовать TLS для подключения к БД, отключать аутентификацию по паролям к SSH (тогда перебор пароля становится невозможен), но сервисы всё равно будут светить наружу.
Стоит также помнить про health check auth-сервиса. Если ваш Authelia или Authentik упал, то все защищенные им ресурсы становятся недоступны — это single point of failure. Поэтому в production стоит настроить мониторинг доступности самого auth-провайдера и продумать стратегию восстановления. Для критических сервисов имеет смысл оставить bypass route для администратора с белого IP, чтобы можно было починить инфраструктуру если auth-сервер лег.
Итог
В современных реалиях российского интернета, если вам нужен защищенный доступ к HTTP-приложениям, технология Forward Auth является компромиссным решением. Его относительно легко настроить и встроить в инфраструктуру. Конечно, это не панацея и не позволяет получить доступ к внутренним ресурсам не на HTTP-портах. Но отлично справляется с защитой часто публикуемых сервисов — GitLab, Grafana, внутренней админки.
Нужна помощь с инфраструктурой?
Проведу аудит вашей системы и подберу оптимальное решение
Связаться со мной