Skip to content
You are reading the docs for version 0.7. The current one is 0.8. Switch →

Вход через Zentro для приложений без SSO (шлюз)

This content is not available in your language yet.

Инструкция для администратора Zentro и того, кто обслуживает приложение.

Если приложение не умеет подключаться к SSO напрямую (нет OIDC/SAML — только свои логины и пароли), вход через Zentro всё равно можно поставить перед ним: шлюз-прокси пускает к приложению только тех, кто вошёл в Zentro и у кого есть нужная роль. Так закрывают старые веб-приложения, веб-интерфейсы оборудования (роутеры, NAS, принтеры, СХД), внутренние админки.

Приложение умеет OIDC — подключайте его напрямую (Подключение приложения), шлюз не нужен.

В примере ниже все данные выдуманы: подставьте свои.

Браузер → https://stock.example.com → шлюз (oauth2-proxy)
├─ нет входа → Zentro: логин + второй фактор → обратно на шлюз
├─ нет права → 403, к приложению не пускает
└─ всё в порядке → http://10.20.0.15:8080 (приложение «Склад-Учёт»)

Шлюз — обычное приложение Zentro (OAuth-клиент). Решение «пускать или нет» он принимает по правам из id_token: права приходят в пространстве, заданном у клиента.

Чего шлюз не даёт:

  • Приложение не узнаёт, кто вошёл. Свой вход у него остаётся: после Zentro оно спросит свой пароль. Если приложение умеет доверять заголовку с именем пользователя — шлюз может его передавать (ниже, «Если приложение доверяет заголовку»), но таких немного.
  • Защищает только то, что идёт через шлюз. Прямой доступ к приложению в обход шлюза нужно закрыть сетью — иначе вход через Zentro ничего не защищает (шаг 5).
Что Значение в примере
Приложение «Склад-Учёт», веб-интерфейс http://10.20.0.15:8080, свои учётки, SSO не умеет
Адрес шлюза https://stock.example.com
Zentro (Identity) https://id.example.com — это PUBLIC_BASE_URL, он же issuer
Пространство прав STOCK
Кто входит сотрудник ivanov
  • Нужна роль IDENTITY_ADMIN (роли и OAuth-клиенты) и второй фактор — панель попросит подтвердить себя.
  • Машина для шлюза с Docker, из которой видно приложение (10.20.0.15:8080) и Zentro (id.example.com). Шлюз сам ходит в Zentro за токеном — одного браузера мало.
  • Имя и TLS-сертификат для адреса шлюза. Без https не работают защищённые cookie шлюза.

Роли → Создать роль:

Поле Значение
Название STOCK_USER
Права STOCK:APP:ACCESS

Пользователи → ivanov → Назначить роль → STOCK_USER. Дать доступ ещё кому-то — назначить ту же роль; забрать — снять. Подробнее о ролях — Роли и права.

OAuth-клиенты → Зарегистрировать клиента → «Люди — вход в приложение через Zentro»:

Поле Значение
Название Склад-Учёт — его видно пользователю
Redirect URI https://stock.example.com/oauth2/callback — точно, без слэша в конце
Публичный клиент нет — у шлюза есть сервер и секрет
Scopes openid profile email
Пространство прав STOCK — без него права в токен не придут и шлюз не пустит никого
Приложение организации да — своё приложение, экран «Разрешить» не нужен

После «Зарегистрировать» сохраните client_id и секрет — он показывается один раз.

Шлюз — oauth2-proxy. Ключ для cookie шлюза:

Окно терминала
python3 -c 'import os,base64;print(base64.urlsafe_b64encode(os.urandom(32)).decode())'

.env (секреты — только здесь, не в compose и не в git):

CLIENT_SECRET=секрет из шага 2
COOKIE_SECRET=результат команды выше

docker-compose.yml:

services:
stock-gate:
image: quay.io/oauth2-proxy/oauth2-proxy:latest # в проде — зафиксируйте версию
restart: unless-stopped
ports: ["4180:4180"]
environment:
OAUTH2_PROXY_CLIENT_SECRET: "${CLIENT_SECRET}"
OAUTH2_PROXY_COOKIE_SECRET: "${COOKIE_SECRET}"
command:
- --http-address=0.0.0.0:4180
- --provider=oidc
- --oidc-issuer-url=https://id.example.com # = PUBLIC_BASE_URL Identity
- --client-id=cid_xxxxxxxx # из шага 2
- --redirect-url=https://stock.example.com/oauth2/callback
- --code-challenge-method=S256 # PKCE в Zentro обязателен
- --scope=openid profile email
- --oidc-groups-claim=permissions # права пользователя из id_token
- --allowed-group=STOCK:APP:ACCESS # без этого права — 403
- --email-domain=*
- --upstream=http://10.20.0.15:8080/
- --pass-host-header=false
- --skip-provider-button=true
- --cookie-secure=true
- --cookie-refresh=5m # снятая роль перестаёт действовать ≤ 5 мин
- --cookie-expire=8h # дольше — снова вход в Zentro
Окно терминала
docker compose up -d && docker compose logs -f stock-gate
Параметр Зачем
--allowed-group Какое право нужно для входа. Можно повторить несколько раз — достаточно любого
--cookie-refresh Как часто шлюз обновляет токен и перечитывает права. Меньше — быстрее отзыв, чаще запросы к Zentro
--cookie-expire Сколько живёт вход в шлюз без повторного входа в Zentro

Шлюз слушает :4180 без TLS — поставьте перед ним ваш nginx/Caddy/балансировщик с сертификатом на stock.example.com. Если ничего нет, проще всего Caddy — сертификат он получит сам:

stock.example.com {
reverse_proxy localhost:4180
}

Проверка: открыть https://stock.example.com в режиме инкогнито → экран входа Zentro → логин и второй фактор → открывается «Склад-Учёт» (со своим экраном входа, если он у него есть).

Делайте после успешной проверки на шаге 4 — иначе можно отрезать доступ и себе.

  • Сеть: к 10.20.0.15:8080 разрешить подключения только с машины шлюза (межсетевой экран на сервере приложения, на коммутаторе или в настройках оборудования). Сначала — правило «разрешить со шлюза», потом «запретить остальным».
  • Доступ снаружи: выключить публикацию приложения в интернет мимо шлюза — проброс портов, облачный/удалённый доступ производителя, старые DNS-имена.
  • Другие входы: SSH, Telnet, API приложения — закрыть так же или оставить осознанно.
  • Аварийный путь: решите заранее, как попасть в приложение, если шлюз или Zentro недоступны (консоль, отдельный хост администратора). Запишите его.

Приложение по-прежнему спрашивает свой пароль. Рекомендуем:

  • Именные учётки в приложении (ivanov, а не общая admin) — тогда его собственный журнал показывает, кто что делал.
  • Встроенного администратора — длинный пароль в хранилище паролей, только для аварий.
  • Не подставлять пароль приложения на шлюзе. Это требует своего кода и держит пароль администратора приложения на шлюзе — проще и безопаснее два рубежа: Zentro (кто ты, второй фактор, есть ли роль) и вход приложения.

Некоторые приложения умеют брать пользователя из заголовка от прокси (обычно X-Forwarded-User, X-Forwarded-Email или Remote-User — смотрите документацию приложения). Тогда добавьте шлюзу:

- --pass-user-headers=true

и обязательно выполните шаг 5: если приложение доступно в обход шлюза, такой заголовок подделает кто угодно.

Выход из шлюза — https://stock.example.com/oauth2/sign_out. Он завершает вход в шлюз, но не в Zentro: следующий заход пройдёт без пароля, пока жива сессия Zentro. Выйти отовсюду — в кабинете Zentro (Личный кабинет, «Сессии»).

  • Вход в инкогнито: Zentro (логин + второй фактор) → приложение.
  • Пользователь без роли получает 403 от шлюза.
  • Сняли роль — доступ пропал не позже чем через --cookie-refresh.
  • Прямой заход на http://10.20.0.15:8080 с другой машины не открывается.
  • Аварийный путь записан.
Что видно Причина Что сделать
Ошибка про redirect_uri на экране Zentro --redirect-url не совпал с Redirect URI клиента Сверить посимвольно: https, хост, путь /oauth2/callback, слэш
403 от шлюза у того, кому доступ нужен Нет роли, у клиента не задано пространство прав или право в --allowed-group написано иначе Роль — Пользователи; пространство — OAuth-клиенты → Изменить; сверить право
Шлюз пишет про email (email not verified, пустой email) У пользователя нет почты или она не подтверждена Добавить --insecure-oidc-allow-unverified-email=true; при пустой почте — ещё --user-id-claim=sub
Шлюз не стартует: ошибка discovery / issuer Шлюз не видит Zentro или --oidc-issuer-url не равен PUBLIC_BASE_URL curl https://id.example.com/.well-known/openid-configuration с машины шлюза; сверить issuer
invalid_grant после входа PKCE не включён или код просрочен Проверить --code-challenge-method=S256; повторить вход
Бесконечный круг входа Нет https перед шлюзом — браузер не сохраняет защищённую cookie Шаг 4
Приложение открывается кривым, ссылки ведут на 10.20.0.15 Приложение строит адреса из своего имени хоста Попробовать --pass-host-header=true; иначе настроить в приложении внешний адрес
Роль сняли, а доступ остался Действует до следующего обновления шлюза Подождать --cookie-refresh; срочно — перезапустить шлюз со сменой COOKIE_SECRET (выйдут все)