nkl-manager Secrets manager

Один вызов вместо прямой работы
с сервером секретов.

Проект никогда не обращается к серверу секретов напрямую — он вызывает get_secrets() со своей identity, контрактом и именами нужных секретов. Всё остальное: шифрованный кэш, per-contract lock, плановый refresh, TTL, деактивация — управляется внутри nkl-manager.

— модулей
— символов API
— методов
— примеров

Быстрый старт

Один менеджер на процесс; сервер секретов настраивается один раз через TOML.

Линия 1.x. Минимальная поддерживаемая версия: nkl-manager>=1.0.0. Для фиксации именно линии 1.x используйте pip install "nkl-manager>=1.0.0,<2.0.0". Для machine enrollment, Protocol v2 и post-install configure используйте документацию 2.0.0.
Инициализация сервер и scheduler по умолчанию
from nkl_manager import NklManager

manager = NklManager()  # ~/.nkl-manager/server.toml, scheduler запущен
Получение секретов NklManager.get_secrets(...)
result = manager.get_secrets(
    project_id="checkout-service",
    contract_id="payments-api",
    contract_version=3,
    secrets=["api_key", "webhook_secret"],
)

if result.success:
    api_key = result.secrets["api_key"]
else:
    log.error(result.error.code)
Никогда не raise. Любой ожидаемый контрактом исход — невалидный запрос, недоступный сервер, повреждённый кэш — возвращается как SecretsResult(success=False, error=...), а не как исключение.

get_secrets(): алгоритм

Валидация → попытка из кэша → per-contract lock → refresh → (при сбое) stale-фолбэк.

strict=False по умолчанию

Если сервер недоступен, но на диске есть кэш, покрывающий все запрошенные секреты, он отдаётся с stale=True вместо ошибки. При strict=True это поведение отключено: без свежих данных — только success=False.

Реактивация

Если существующая запись помечена INACTIVE (см. неактивные контракты), она трактуется как отсутствующая — контракт запрашивается заново, как впервые.

Архитектура

NklManager — единственная публичная точка входа; всё остальное — внутренние компоненты.

nkl_manager NklManager get_secrets() · run_scheduled_refresh() · close()

Кэш и шифрование

Секреты на диске всегда зашифрованы; ключ хранится отдельно от метаданных.

FernetСимметричное шифрование payload'а кэша (cryptography.fernet)
Ключ отдельноМастер-ключ — отдельный файл с правами 0600, никогда не в installation.json
Payloadsecrets, requested_secrets, server_revision, fetched_at
TTLServer-provided ttl_override_seconds либо default_ttl_seconds
АтомарностьЗапись через временный файл + rename, никогда частичный кэш

Registry (registry.db)

SQLite, метаданные о контрактах — секретные значения сюда никогда не попадают.

Таблица contracts PRIMARY KEY (project_id, contract_id, contract_version)
status, requested_secrets, server_revision,
fetched_at, expires_at, last_requested_at,
effective_ttl_seconds, ttl_source,
last_refresh_status, last_refresh_at, last_refresh_error,
cache_path

Locks и scheduler

Один lock на контракт — параллельные запросы к разным контрактам не блокируют друг друга.

REFRESH LOCK Область действия

Ключ — project_id:contract_id:contract_version. In-process и межпроцессный одновременно.

TIMEOUT Если lock занят

RefreshTimeoutError → success=False вместо бесконечного ожидания.

SCHEDULER Ежедневно 00:01

run_scheduled_refresh() обновляет все активные записи и чистит неактивные; сбой одного контракта не останавливает остальные.

Неактивные контракты

Контракты, которые давно не запрашивались, деактивируются, а не хранятся вечно.

Период без обращений Действие
< 30 днейОбычное обновление по расписанию
30–60 днейКандидат на деактивацию при следующей уборке
60–90 дней (inactive)Статус INACTIVE; больше не обновляется планировщиком
> 90 днейЗапись и кэш удаляются полностью
Повторный запрос к INACTIVE-контракту не ошибка — он обрабатывается как новый и снова становится ACTIVE.

Self-update (опционально)

package-updater — необязательная зависимость (extra self-update).

Установлен

pip install "nkl-manager[self-update]". При каждом импорте _bootstrap.run_update_check() вызывает PackageUpdater.check_declared(package="nkl-manager") до импорта остального пакета — ровно так, как требует контракт самообновления.

Не установлен

Полный no-op: ModuleNotFoundError перехватывается, логируется на уровне debug и не всплывает как warning или ошибка. Основная функциональность nkl-manager не зависит от updater вообще.

Конфигурация сервера секретов

Как и в package-updater — доверие живёт вне wheel, HTTPS обязателен.

~/.nkl-manager/server.toml или $NKL_MANAGER_SERVER_CONFIG
base-url = "https://secrets.example.com"
auth-token-env = "NKL_SECRETS_TOKEN"
request-timeout-seconds = 10

Ошибки

Каждая ошибка — стабильный code; сообщения никогда не содержат значения секретов.

INVALID_REQUEST Запрос не прошёл валидацию (contract section 4).
CONTRACT_NOT_FOUND Нет кэша и невозможен fetch с сервера.
CONTRACT_VERSION_UNAVAILABLE У сервера нет данных для запрошенной версии контракта.
SERVER_UNAVAILABLE Сервер секретов недоступен или вернул ошибку.
PARTIAL_SERVER_RESPONSE Ответ сервера не содержит часть запрошенных секретов.
CACHE_CORRUPTED Файл кэша существует, но структурно невалиден.
CACHE_DECRYPTION_FAILED Кэш не расшифровался: неверный/отсутствующий ключ либо подделка.
REFRESH_TIMEOUT Не удалось получить lock — другой процесс уже обновляет контракт.
STORAGE_ERROR Сбой файловой системы или registry (диск, права доступа).

Полный API reference

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

Проверка…
nkl-manager Документация сгенерирована из production source.
Наверх ↑