jwksproxyhttp

package
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 27, 2026 License: AGPL-3.0 Imports: 15 Imported by: 0

Documentation

Overview

Package jwksproxyhttp — cluster-ВНУТРЕННИЙ публикатор набора проверочных ключей.

Запись ОДНА, и она наша

Публикуется ПРОЕКЦИЯ ключницы (keyset.go): только наши ключи, только публичный материал, собственного кэша нет by construction. Путь записи объявляется настройкой своей чеканки, а не выводится из издателя (binding.go).

Прежде рядом стояла вторая запись — зеркало публичного набора прежнего издателя. Оно жило до последней фазы отказа от внешнего сервера и ушло вместе с ним (kaname#361): без внешнего издателя зеркалить нечего, а запись без источника — находка, а не запас. Привязка теперь отвергает вторую запись в старте: вернувшись, она снова поставила бы ключ другого издателя рядом с нашим на том же слушателе.

Снятие authN — задокументированное исключение

Маршрут НАБОРА КЛЮЧЕЙ не требует аутентификации осознанно: на проводе — ТОЛЬКО ПУБЛИЧНЫЙ МАТЕРИАЛ проверки подписи, в форме стандартного документа, на cluster-ВНУТРЕННЕМ слушателе (:9097, никогда внешнем — ban #6), под односторонней TLS с сертификатом внутреннего удостоверяющего центра.

Требовать сертификат у ПОТРЕБИТЕЛЯ набора нельзя: он обязан оставаться origin-agnostic, и взаимная TLS сломала бы ровно это свойство.

Но соседняя поверхность того же слушателя обоснованием НЕ пользуется

Авторитет отзыва (internal/handler/tokenintrospecthttp) стоит на этом же слушателе и принимает ПРЕДЪЯВЛЕННЫЙ ТОКЕН, а не отдаёт публичный материал. Обоснование выше на него не распространяется, поэтому он требует проверенного клиентского сертификата САМ, а слушатель переводится в режим «сертификат запрашивается и верифицируется, если предъявлен» — набор ключей при этом остаётся доступен без сертификата.

Не добавляйте здесь authN-гейт, не пересмотрев это решение (и TLS-клиента потребителя набора).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewMux

func NewMux(b Binding) (*http.ServeMux, error)

NewMux монтирует запись привязки на её путь.

Возвращённый mux выставляется вызывающим на cluster-ВНУТРЕННЕМ слушателе — никогда на внешнем.

Types

type Binding

type Binding struct {
	// contains filtered or unexported fields
}

Binding — объявленная привязка «издатель → путь → обработчик».

func NewBinding

func NewBinding(records []Record) (Binding, error)

NewBinding строит привязку, ОТКАЗЫВАЯ в вырожденной.

Это и есть страж старта записи источника: издатель, объявленный публикуемым, но не имеющий записи, — отказ в старте, а не молчаливый перебор записей подряд. Отказ на пустом перечне — третий экземпляр класса «пустое значение означает „не сужаем“», который дерево уже закрывает на двух других перечнях.

ВТОРАЯ ЗАПИСЬ — ТОЖЕ ОТКАЗ, и отказывает мощность, а не форма: каждая запись по отдельности законна, и потому вернувшееся зеркало чужого набора прошло бы все остальные проверки молча.

func (Binding) PathOf

func (b Binding) PathOf(issuer string) (string, bool)

PathOf резолвит объявленного издателя в путь его записи.

Издатель употребляется ТОЛЬКО как ключ поиска: не совпал с объявленным — отказ. Ни одна часть пути, имени файла, ключа кэша или исходящего адреса из него не строится.

func (Binding) Paths

func (b Binding) Paths() []string

Paths возвращает пути привязки.

Всякий, кому нужен перечень путей публикации — проба замка «только внутри», композиционный корень, страница развёртывания, — ВЫВОДИТ его отсюда, а не выписывает: выписанный перечень разошёлся бы с привязкой молча.

type KeySetConfig

type KeySetConfig struct {
	Source KeySetSource
	Logger *slog.Logger
}

KeySetConfig — настройка обработчика нашей записи.

type KeySetHandler

type KeySetHandler struct {
	// contains filtered or unexported fields
}

KeySetHandler — НАША запись публикуемого набора: ПРОЕКЦИЯ ключницы.

Почему проекция, а не собственный кэш

Порядок «ключ в наборе раньше, чем им подписан первый токен» становится верен ПО ПОСТРОЕНИЮ: опубликованный и подписывающий читаются из одних и тех же строк, и состояния, в котором ключ подписывает, а в ответе его нет, не существует — его не допускает схема.

Собственный кэш вернул бы состояние «строка есть, в ответе нет», и тогда вступление ключа в подпись пришлось бы гейтить на видимость eventually-consistent проекции — запрещённый подтверждающий барьер. С несколькими репликами публикатора «ответ эндпоинта» перестал бы быть одной величиной.

Цена решения названа

Каждый запрос публикации становится чтением своей базы. Величина ограничена сверху числом потребителей, помноженным на частоту их перезапроса, — то есть единицами запросов в минуту, а не функцией от пользовательской нагрузки.

func NewKeySetHandler

func NewKeySetHandler(cfg KeySetConfig) *KeySetHandler

NewKeySetHandler — построитель.

func (*KeySetHandler) ServeHTTP

func (h *KeySetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*KeySetHandler) Stats

func (h *KeySetHandler) Stats() KeySetStats

Stats возвращает величины по каждому исходу.

type KeySetSource

type KeySetSource interface {
	PublishedSet(ctx context.Context) ([]domain.PublishedKey, error)
}

KeySetSource — источник НАШЕЙ записи публикуемого набора.

Реализуется ключницей. Порт назван здесь, у вызывающего: публикатор не знает ни про базу, ни про обёртку приватной половины — да и не может знать, потому что тип, которым ключ сюда приезжает, поля приватной половины не имеет вовсе.

type KeySetStats

type KeySetStats struct {
	Served      uint64
	Unavailable uint64
	Empty       uint64
}

KeySetStats — величины по каждому исходу.

«Ноль отказов за всё время жизни» обязано быть отличимо от «контроль не исполнялся», поэтому величины читаются всегда, включая нулевые.

type Record

type Record struct {
	// Issuer — издатель записи. Ключ поиска, и ТОЛЬКО ключ поиска.
	Issuer string
	// Path — путь записи. ОБЪЯВЛЯЕТСЯ здесь, а не выводится из издателя.
	//
	// Производная конструкция «взять базовый адрес и приклеить издателя»
	// короче и запрещена по двум причинам сразу. Первая — про безопасность:
	// издатель приходит от предъявителя, то есть это недоверенный вход, и
	// значению от предъявителя не место в построении пути. Вторая — про
	// проверяемость: производный путь получается У ВСЯКОГО издателя, поэтому
	// состояние «записи источника нет» не наступает никогда, и страж старта
	// становится тождественно истинным — проверка остаётся в тексте, не имея
	// возможности упасть.
	Path string
	// Handler — обработчик записи: проекция ключницы.
	Handler http.Handler
}

Record — запись привязки «издатель → источник набора».

Запись у публикатора ОДНА — наша. Вторая существовала ради прежнего издателя и ушла вместе с ним (kaname#361); объединять наборы разных издателей в один документ запрещено по той же причине, по которой их прежде разводили: ключ одного издателя проверял бы токен, объявляющий другого.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL