вход переехал на доверенный заголовок 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
+34
View File
@@ -56,3 +56,37 @@ func ApplyAppRateLimit(app core.App) error {
}
return nil
}
// ApplyTrustedProxyHeaders называет хранилищу заголовок, из которого брать
// адрес спрашивающего.
//
// Без этого ограничитель частоты ключует счётчик адресом **пира**, а пир с
// переездом входа на заголовок всегда один и тот же — обратный прокси. Бюджет
// в этом случае общий на весь сервис: восемь одновременно открытых карточек
// выбирают его целиком, и девятый человек получает отказ, не сделав ни одного
// запроса. Норма при этом требует обратного — бюджет считается по адресу
// спрашивающего.
//
// Доверие здесь той же природы, что и к `Remote-User`, и той же ширины: адрес
// берётся из пересылаемого заголовка, а верить пересылаемому можно ровно
// потому, что до нас дотянулся доверенный пир. Отсюда требование к контуру,
// записанное в модели угроз: прокси обязан `X-Forwarded-For` **перезаписывать**,
// а не дописывать к присланному, — иначе спрашивающий назначает себе ключ
// счётчика сам и обходит ограничитель, меняя значение.
//
// Барьером узнавания этот заголовок не служит и служить не может: кто пришёл,
// по-прежнему решает адрес самого соединения.
func ApplyTrustedProxyHeaders(app core.App) error {
settings := app.Settings()
settings.TrustedProxy.Headers = []string{"X-Forwarded-For"}
// Пустой заголовок означает, что прокси адреса не назвал; счётчик тогда
// падает обратно на адрес пира — то есть на общий, как было. Лучше общий,
// чем один пустой ключ на всех.
settings.TrustedProxy.UseLeftmostIP = true
if err := app.Save(settings); err != nil {
return fmt.Errorf("failed to apply trusted proxy headers: %w", err)
}
return nil
}