Разделы документации
ОбзорБыстрый стартРедакции и возможностиМодели и поляРедактор контентаМедиатекаЛокализацияПубликация и работа командыAPI, SDK и генерация типовРасширения и инструментыРабочие проектыЗадания, вебхуки и наблюдаемостьАудит и управление даннымиСоветники и доверие к плагинамКорпоративный входПространства, квоты и масштабированиеCommerce и PortalПрава и безопасностьРазвёртывание и обновленияЛицензии и установка пакетовТекущие ограниченияПомощь и диагностикаДанные в кабинетеCore CMSDeveloper PlatformProduction UseWorkflowOperationsComplianceAI AssistantsPlugin TrustEnterprise IdentityEnterprise ScaleEnterprise DeploymentCommerce BundlePortal BundleNotty CMS DocumentationAuth & SecurityContent ModelingDeploymentEcosystem & Packaging ConventionsEditions and First-party ModulesExtensibilityGetting StartedMedia ManagementModule Extraction PathDraft & PublishUpgrade GuideWebhooks & IntegrationsCookbook: Blog with Next.jsCookbook: Custom PluginCookbook: Multilingual SiteOperations DocsBackup AutomationDeployment BlueprintsRunbook — Восстановление БД из бэкапаRunbook — Плановый деплойRunbook — Реакция на инцидентRunbook — Откат релизаRunbook — Горизонтальное масштабированиеRunbook — Ротация секретовRunbook — Major upgradeSecrets ManagementNotty CMS — Capability MapNotty Configuration ModelGenerated App ContractComponents and Dynamic ZonesMiddleware SystemPerformance & Scaling ToolkitDisaster Recovery PlaybookDistribution Model
Документация / Технический справочник

Runbook — Ротация секретов

Техническое руководство из исходного проекта Notty. Примеры, параметры и эксплуатационные ограничения.

По функциям модуляОбновлено 2026-09-30

Когда: плановая (по cadence из secrets-management.md) или внеплановая (подозрение на утечку, увольнение оператора с доступом, аудит).

Общая последовательность

  1. Сгенерировать новый секрет (вне prod-машины).
  2. Записать в secret backend (Vault/SM/External Secrets/k8s Secret).
  3. Применить в runtime через rolling update.
  4. Подтвердить, что Notty работает с новым секретом.
  5. Отозвать/удалить старое значение в backend.
  6. Отметить ротацию в журнале операций.

JWT_SECRET

Эффект: все активные admin-сессии и JWT-токены становятся невалидны. Всем пользователям нужно перелогиниться. API tokens (хранятся в БД) не страдают.

# 1. Сгенерировать новый секрет (никуда не выводя в shell history дольше нужного)
NEW_JWT="$(openssl rand -base64 64 | tr -d '\n')"

# 2a. Kubernetes — рекомендуемый путь: положить новый JWT_SECRET в secret backend
#     (Vault / AWS SM / GCP SM); ESO синхронизирует его в `notty-secrets`.
#     Затем — rolling restart:
kubectl -n notty rollout restart deploy/notty
kubectl -n notty rollout status deploy/notty --timeout=180s

#     Если backend'а нет, патч точечно — JWT_SECRET в base64:
NEW_JWT_B64=$(printf '%s' "$NEW_JWT" | base64 | tr -d '\n')
kubectl -n notty patch secret notty-secrets --type=merge \
  -p "{\"data\":{\"JWT_SECRET\":\"$NEW_JWT_B64\",\"NITRO_JWT_SECRET\":\"$NEW_JWT_B64\"}}"
kubectl -n notty rollout restart deploy/notty
kubectl -n notty rollout status deploy/notty --timeout=180s

# 2b. docker-compose — через готовый скрипт
./deployment/scripts/secret-rotate-jwt.sh --rotate \
  --file .env --reload-compose notty

Подтверждение:

  • verify-deploy.sh зелёный;
  • логин в admin UI работает (после ре-ввода паролей).

DATABASE_URL (пароль БД)

Эффект: при rolling update'е каждый pod на старте откроет новый коннект. Активные сессии БД на старом пароле останутся живыми до перезапуска pod'а.

  1. В managed PG: создать новый пароль или временно второго пользователя с тем же набором прав.
  2. Обновить DATABASE_URL в secret backend.
  3. kubectl rollout restart deploy/notty (или docker compose up -d --no-deps notty).
  4. Дождаться rollout status и /api/readyz.
  5. Удалить старый пароль/пользователя в managed PG.

STORAGE_ACCESS_KEY_ID / STORAGE_SECRET_ACCESS_KEY

S3 / R2 / совместимые позволяют иметь несколько активных ключей.

  1. Создать новый access key в облаке. Старый пока оставить.
  2. Обновить secret backend.
  3. Rolling restart Notty.
  4. Проверить, что media upload и доступ работают (загрузить тестовый файл).
  5. Удалить старый access key.

OAuth client secret

  1. Сгенерировать новый client secret в провайдере (Google/GitHub/VK/Facebook).
  2. Обновить *_CLIENT_SECRET в secret backend.
  3. Rolling restart.
  4. Проверить полный OAuth-флоу (login через провайдер).
  5. Удалить старый secret в провайдере.

API tokens (в БД)

Используйте админ-API:

# Список
curl -H "Authorization: Bearer $ADMIN_TOKEN" $BASE/api/admin/api-tokens

# Revoke
curl -X DELETE -H "Authorization: Bearer $ADMIN_TOKEN" \
  $BASE/api/admin/api-tokens/<id>

# Создать новый
curl -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"name":"ci-runner","scopes":["content:read"]}' \
  $BASE/api/admin/api-tokens

Передайте новый токен потребителю out-of-band; не вешайте в логах.

Webhook signing keys

При компрометации:

  1. Через UI/API regenerate signing key конкретного webhook'а.
  2. Сообщить получателю новый ключ out-of-band.
  3. Получатель должен в течение N минут обновить верификацию подписи.
  4. Замониторить dead-letter (/api/webhooks/dead-letter) — если получатель не успел переключиться, реплейните после.

Чек-лист после любой ротации

  • Smoke зелёный.
  • Логи без всплеска auth/db ошибок.
  • notty_http_request_errors_total стабилен.
  • Запись в operations log: дата, кто ротировал, какой секрет, причина.
  • Старое значение удалено в backend и в провайдере.

Источник: docs/operations/runbooks/secret-rotation.md. Снимок документации исходного проекта. Технический справочник сохраняет язык оригинала.