Перейти к содержимому

Архонты

Архонт — оператор Soul Stack, запись в реестре operators в PostgreSQL. У него есть идентификатор (AID), набор ролей и жизненный цикл: создание, выпуск токенов, ревокация. Удаления записи нет — Архонты только ревокаются, чтобы аудит-ссылки на инициатора операций оставались валидными.

AID (Archon ID) — устойчивая строка, валидируемая по ^[a-z0-9][a-z0-9._@-]{1,127}$:

  • первый символ — строчная буква или цифра;
  • далее — строчные ASCII-буквы, цифры и символы . _ @ -;
  • длина 2–128 символов.

Подходят, например, archon-alice, email-подобные alice@corp.com, LDAP-uid вида uid-4815, ops-team. Набор символов намеренно узкий и безопасный (нет /, \, кавычек, управляющих символов, unicode) — AID встраивается в имена файлов, JWT-claims, логи.

При первой инициализации кластера реестр operators пуст. Поскольку базовая политика — default-deny, без специального механизма любой вызов API завершился бы 403, и завести первого оператора было бы невозможно. Эту проблему «курицы и яйца» решает административная подкоманда самого Keeper-а:

Окно терминала
keeper init --archon=archon-alice --config=/etc/keeper/keeper.yml \
[--credential-out=/etc/keeper/archon-credential.json]

Что делает команда:

  1. Под блокировкой PostgreSQL (advisory lock) проверяет, что реестр operators пуст. Если в нём уже есть записи — отказывается с сообщением о том, что кластер инициализирован и какой Архонт существует.
  2. Создаёт первого Архонта с указанным AID и привязывает его к встроенной роли cluster-admin (permission * — полный доступ).
  3. Выпускает JWT-credential и кладёт его в файл с правами 0400.

Несколько деталей, важных для эксплуатации:

  • Это не «клиентский режим» Keeper-а. keeper init — административная подкоманда: локально установленный исполняемый файл Keeper-а инициализирует собственное состояние в PostgreSQL. Он не подключается к удалённому Keeper-у.
  • Блокировка снимает гонку HA. Если несколько инстансов одновременно выполняют keeper init, advisory lock гарантирует, что первого Архонта создаст ровно один; остальные увидят непустой реестр и откажутся.
  • TTL bootstrap-токена — 30 дней (дольше обычного), чтобы оператор успел настроить дальнейшее администрирование. Файл 0400 нужно надёжно сохранить — это credential первого администратора.

Если Keeper стартует и видит, что реестр operators пуст, его поведение зависит от явного флага:

  • без --initialize (или переменной KEEPER_INITIALIZE=true) Keeper отказывается стартовать и просит сначала выполнить keeper init;
  • с --initialize Keeper стартует в режиме ожидания: listeners поднимаются, но любой вызов API/MCP возвращает 503, пока keeper init не отработает.

Это защита на случай катастрофической потери PostgreSQL: без явного намерения оператора система не выпустит автоматически новый admin-токен.

Все операторы, кроме первого, заводятся уже через Operator API (REST/MCP/web-UI) Архонтом, у которого есть permission operator.create:

  • создаётся запись в реестре operators, при создании API возвращает JWT нового оператора;
  • если оператор потерял токен, другой Архонт с правом operator.issue-token может выпустить ему новый — без пересоздания самого Архонта.

Привязка нового оператора к ролям — отдельный шаг (Роли и доступ); только что созданный Архонт без ролей не имеет никаких прав (default-deny).

Архонта отзывают, а не удаляют:

  • ревокация выполняется через Operator API с permission operator.revoke — у записи проставляется revoked_at;
  • запись остаётся в реестре, чтобы ссылки «кто создал / кто изменил» (поля created_by_aid / changed_by_aid у других сущностей) оставались валидными для аудита;
  • отозванному оператору больше не выпускают новые токены, а его действующий JWT перестаёт проходить проверку — отзыв распространяется по всем инстансам кластера практически мгновенно. Короткий TTL токена — дополнительный, естественный слой защиты.

Инвариант: нельзя удалить последнего администратора

Заголовок раздела «Инвариант: нельзя удалить последнего администратора»

В кластере всегда обязан оставаться хотя бы один активный Архонт с эффективным полным доступом (*). Операция, которая нарушила бы это — например, ревокация единственного cluster-admin или снятие у него последней *-дающей роли, — отвергается ошибкой 409 would-lock-out-cluster.

Инвариант учитывает все пути получения *: прямую привязку роли и привязку через группу (Synod). Это защита от self-lockout — случайно или злонамеренно «запереть» себя и весь кластер без администратора нельзя.