вход переехал на доверенный заголовок Authelia вместо собственного OIDC

- пришедшего называет заголовок Remote-User от прокси, и верят ему только с
  адреса из перечня trusted_proxies; своего входа у сервиса не осталось — ни
  корня /auth, ни кук, ни срока сессии, ни секрета клиента в конфиге и в базе
- учётная запись заводится первым обращением: EnsureUser в пакете хранилища,
  шаг схемы 202608220001 с колонкой provider_login и снятыми правилами users
- cmd/oidcstub заменён на cmd/devtools с подкомандой proxy; заодно закрыт
  унаследованный DL3066 — пользователь образа назван числом
This commit is contained in:
av
2026-08-22 20:24:22 +03:00
parent e4441f3c49
commit 7f33c957e5
63 changed files with 5257 additions and 2305 deletions
@@ -3,6 +3,7 @@
- **Дата:** 2026-08-12
- **Источник:** [../../openspec/changes/archive/2026-08-12-oidc-login/design.md](../../openspec/changes/archive/2026-08-12-oidc-login/design.md),
раздел «Вход и возврат ведёт наш код, разбор ответа — хранилище»
- **Статус:** заменено на [ADR-2026-08-22-login-by-trusted-header](ADR-2026-08-22-login-by-trusted-header.md)
## Решение
@@ -5,6 +5,7 @@
раздел «Что изменило ревью кода», плюс отчёт триажа
[../../openspec/changes/archive/2026-08-12-oidc-login/review/report.md](../../openspec/changes/archive/2026-08-12-oidc-login/review/report.md),
пункт 6
- **Статус:** заменено на [ADR-2026-08-22-login-by-trusted-header](ADR-2026-08-22-login-by-trusted-header.md)
## Решение
@@ -0,0 +1,73 @@
# Пришедшего называет заголовок доверенного прокси, а не собственный вход OIDC
- **Дата:** 2026-08-22
- **Источник:** openspec/changes/archive/trusted-header-login/design.md
## Решение
Сервис перестаёт вести вход сам. Кто пришёл, он узнаёт из заголовка
`Remote-User`, поставленного обратным прокси, который сходил к Authelia;
заголовку верят только с адреса из объявленного перечня, а адрес берётся у
самого соединения. Учётная запись заводится первым обращением с новым логином и
находится по нему же дальше.
Убраны целиком: корень `/auth` с тремя адресами, куки `transcriber_session` и
`transcriber_login`, сверка состояния и проверочный код PKCE, обмен кода
внутрипроцессным запросом к роутеру хранилища, слои предъявления куки и запрета
продления, приведение настроек провайдера к конфигу, секрет клиента и срок жизни
сессии.
## Почему
Цитата из источника, раздел Р3:
> Сервис не выдаёт браузеру ни куки, ни токена. Каждый запрос узнаётся заново, по
> заголовку, который прокси поставил, сходив к Authelia.
>
> Это и есть выгода задачи: отзыв доступа перестаёт ждать. Пока сервис выдавал
> значение, живущее семь суток, отозванный у провайдера человек работал до
> истечения этого значения, и другого канала отзыва не было.
Оттуда же, Р1 — почему доверие судится адресом соединения, а не пересылаемым
заголовком:
> **`X-Forwarded-For` и его родня.** Значение целиком задаёт тот, кто шлёт
> запрос. Барьер, который подделывается той же строкой, что и обходится, не
> барьер вовсе.
Отвергнут промежуточный вариант — заголовок как вход, сессия хранилища как
продолжение (Р3):
> Дешевле в работе (слой срабатывал бы раз в неделю, а не на каждом запросе), но
> возвращает ровно то, что задача убирает: значение, переживающее отзыв. Семь
> суток вернулись бы вместе с ним.
Контур к решению был готов заранее: обратный прокси уже отдавал `Remote-*` трём
соседним сервисам того же контура, а правила для этого сервиса там не было
вовсе — он не выложен.
## Последствия
- `+` Отзыв доступа действует со следующего запроса, а не через семь суток:
Authelia судит каждое обращение.
- `+` Секрет клиента исчез из конфига и из базы. Изъятие из инварианта «Секрет не
покидает конфиг» снято: чтение файла базы больше не равносильно чтению
секрета.
- `+` Своего протокола входа у сервиса не осталось — вместе с ним исчезли пять
накопившихся задач о его механике.
- `+` Панель закрывается доменом, а не правилом на литерал пути; обход подменой
знака перестаёт существовать.
- `` **Весь барьер держится на настройке прокси.** Прокси, добавляющий заголовок
вместо замены, открывает сервис любому под любым именем. Половину беды сервис
закрывает сам — запрос с двумя значениями заголовка не узнаёт никого, — вторую
проверить отсюда нечем: правило живёт в `pet-project-server`.
- `` **Логин у провайдера переиспользуем**, и новый его владелец получает архив
прежнего. Неизменяемого признака заголовок не приносит; не допускать
переиспользования — работа провайдера. Обратная сторона: переименование
заводит новую запись, а прежняя остаётся с архивом, который нечем ни слить, ни
убрать.
- `` Поиск учётной записи идёт на каждом запросе к области приложения вместо
раза в неделю. Уникальный индекс делает это одним обращением к базе; замера не
требовалось — сервисом пользуются единицы человек.
- `` Половина работы лежит вне репозитория: до того как правило прокси и правило
Authelia на домен заведут, сервис не узнает никого.
+3 -2
View File
@@ -35,6 +35,7 @@
| Дата | Запись | Статус |
| --- | --- | --- |
| 2026-08-22 | [Пришедшего называет заголовок доверенного прокси, а не собственный вход OIDC](ADR-2026-08-22-login-by-trusted-header.md) | |
| 2026-08-15 | [Node зовётся контейнером, а не ставится на машину разработчика](ADR-2026-08-15-node-in-container-not-on-machine.md) | |
| 2026-08-15 | [Приложение живёт своим пространством адресов, а не общим с хранилищем](ADR-2026-08-15-app-namespace.md) | |
| 2026-08-15 | [Страница архива задаётся ключом, а не номером](ADR-2026-08-15-cursor-paging.md) | |
@@ -49,9 +50,9 @@
| 2026-08-13 | [Намерение объявляется признаком, а не выводится из ключа доступа](ADR-2026-08-13-telegram-intent-declared-not-inferred.md) | устарело: вход убран [ADR-2026-08-15-telegram-intake-removed-temporarily](ADR-2026-08-15-telegram-intake-removed-temporarily.md) |
| 2026-08-13 | [Недоступность Telegram подъёму сервиса не мешает](ADR-2026-08-13-telegram-outage-does-not-block-startup.md) | устарело: вход убран [ADR-2026-08-15-telegram-intake-removed-temporarily](ADR-2026-08-15-telegram-intake-removed-temporarily.md) |
| 2026-08-12 | [Файл записи закрыт защищённым полем и отдаётся вошедшему по токену файла](ADR-2026-08-12-protected-file-behind-session.md) | |
| 2026-08-12 | [Сессия живёт семь суток и не продлевает саму себя](ADR-2026-08-12-session-without-refresh.md) | |
| 2026-08-12 | [Сессия живёт семь суток и не продлевает саму себя](ADR-2026-08-12-session-without-refresh.md) | заменено на [ADR-2026-08-22-login-by-trusted-header](ADR-2026-08-22-login-by-trusted-header.md) |
| 2026-08-12 | [Кого пускать в сервис, решает правило провайдера, а не сервис](ADR-2026-08-12-access-delegated-to-provider.md) | |
| 2026-08-12 | [Код провайдера меняется на сессию вызовом собственного адреса хранилища внутри процесса](ADR-2026-08-12-oidc-exchange-via-own-route.md) | |
| 2026-08-12 | [Код провайдера меняется на сессию вызовом собственного адреса хранилища внутри процесса](ADR-2026-08-12-oidc-exchange-via-own-route.md) | заменено на [ADR-2026-08-22-login-by-trusted-header](ADR-2026-08-22-login-by-trusted-header.md) |
| 2026-08-12 | [Спекой нормируется и инструмент сборки, а не только поведение сервиса](ADR-2026-08-12-spec-norms-build-toolchain.md) | устарело |
| 2026-08-12 | [Объявленную версию Go шаг гейта читает из репозитория, а не спрашивает у инструмента](ADR-2026-08-12-version-read-from-repo-not-from-tool.md) | |
| 2026-08-12 | [Ссылка на файл открыта знанием записи, а защищает её отсутствие имени в журнале](ADR-2026-08-12-file-link-open-but-not-logged.md) | заменено на [ADR-2026-08-12-protected-file-behind-session](ADR-2026-08-12-protected-file-behind-session.md) |