Перейти к содержанию

Эксплуатация

Повседневная эксплуатация Alatyr: backup/restore PostgreSQL, мониторинг webhook-очереди доставки, мониторинг очереди async-SCEP issuance (ca_pending) и планирование волны одобрений при продлении сертификатов. Про отказоустойчивость при нескольких репликах сервера — отдельная страница, Отказоустойчивость (HA), читайте её тоже, если планируете горизонтальное масштабирование.

Backup/restore PostgreSQL

Alatyr не поставляет backup-инфраструктуру сам

Ни один из поставляемых демо-манифестов (Docker Compose, Helm-чарт) не разворачивает job/cron для бэкапа PostgreSQL — база всегда один под без реплики и без scheduled-снапшотов (см. Отказоустойчивость и Расчёт ресурсов). Backup/restore — целиком забота оператора, разворачивающего PostgreSQL для Alatyr. Ниже — не описание встроенного механизма, а минимальный практический рецепт поверх стандартных инструментов PostgreSQL.

Всё persistent-состояние приложения — одна база, адрес которой задаёт ALATYR_DB_URL (см. Конфигурация). Схема версионируется миграциями, которые применяются через goose при старте сервера — восстановленная база должна быть на той версии схемы, которую ожидает разворачиваемый исполняемый файл сервера.

Логический бэкап (pg_dump/pg_restore, подходит для большинства инсталляций текущего масштаба — см. Расчёт ресурсов про ожидаемый объём данных):

# Бэкап (custom-формат — сжатый, restore умеет частичный/параллельный)
pg_dump --format=custom --file=alatyr-$(date -u +%Y%m%dT%H%M%SZ).dump \
    "$ALATYR_DB_URL"

# Restore в пустую базу той же major-версии PostgreSQL
pg_restore --clean --if-exists --no-owner \
    --dbname="$ALATYR_DB_URL" alatyr-<timestamp>.dump
  • Снимайте бэкап регулярно по расписанию (cron/CronJob вне приложения) и проверяйте pg_restore --list на свежем дампе — непроверяемый бэкап эквивалентен отсутствию бэкапа.
  • Для непрерывной защиты (RPO меньше, чем интервал между pg_dump) — включайте WAL-архивирование или используйте managed-Postgres с point-in-time recovery; ни то, ни другое не настроено ни в одном манифесте репозитория по умолчанию.
  • Секреты, которые приложение хранит зашифрованными в самой базе (значения секретов вебхуков и состояние SCEP-поллинга), расшифровываются тем же ключом, что задан в окружении сервера — сохраняйте резервную копию ALATYR_WEBHOOK_ENC_KEY/ALATYR_SCEP_ENC_KEY отдельно от самой базы (например, в секрет-хранилище), иначе восстановленная база окажется с нечитаемыми полями.
  • После restore на новый инстанс сервера убедитесь, что схема совпадает с ожидаемой версией миграций до того, как пускать туда трафик — goose применит недостающие миграции при следующем старте автоматически, но сверка «какая версия схемы была в дампе» — на операторе.

Мониторинг webhook-очереди (outbox)

Исходящие вебхуки (ALATYR_WEBHOOKS_ENABLED=true) идут через outbox-таблицу webhook_deliveries, которую вычитывает фоновый воркер каждые ALATYR_WEBHOOK_POLL_SECONDS секунд (по умолчанию 10). Статус доставки — pendingdelivered, либо pendingfailed после ALATYR_WEBHOOK_MAX_ATTEMPTS попыток (по умолчанию 6). Устаревшие записи (created_at старше ALATYR_WEBHOOK_RETENTION_DAYS, по умолчанию 30 дней) воркер автоматически удаляет каждые 6 часов — отдельного cron для этого не нужно.

Через API (не требует прямого доступа к БД):

  • GET /api/v1/admin/webhooks/{id}/deliveries — постраничный журнал доставок конкретного эндпоинта (limit/page), включая status/attempts/last_response_code/last_error каждой попытки. См. REST API.
  • POST /api/v1/admin/webhooks/{id}/test — вручную поставить в очередь тестовую доставку, чтобы проверить эндпоинт end-to-end.

Через БД (для алертинга/дашборда, не открывая Admin UI на каждый эндпоинт):

-- Сколько доставок застряло в pending дольше ожидаемого интервала опроса
SELECT endpoint_id, count(*), min(next_attempt_at)
FROM webhook_deliveries
WHERE status = 'pending' AND next_attempt_at < now() - interval '5 minutes'
GROUP BY endpoint_id;

-- Недавние окончательные отказы (превышен max_attempts)
SELECT id, endpoint_id, event_type, attempts, last_response_code, last_error, created_at
FROM webhook_deliveries
WHERE status = 'failed' AND created_at > now() - interval '24 hours'
ORDER BY created_at DESC;

Растущее число pending-строк с next_attempt_at в прошлом обычно значит, что воркер не запущен (ALATYR_WEBHOOKS_ENABLED было включено после старта процесса без рестарта) либо эндпоинт систематически недоступен — проверьте last_error/last_response_code последних попыток через GET .../deliveries.

Мониторинг очереди async-SCEP issuance (ca_pending)

Когда issuer — SCEP (ALATYR_ISSUER=scep), выпуск не синхронный: заявка переходит в статус ca_pending (cert_requests.status), а таблица scep_pending держит одну строку на каждую заявку, ожидающую ответа внешнего CA. Фоновый поллер вычитывает её каждые ALATYR_SCEP_POLL_SECONDS секунд (по умолчанию 30) и повторяет запрос к CA, пока сертификат не будет выпущен или заявка не исчерпает retry-бюджет.

Только одна реплика — см. Отказоустойчивость

Поллинг ca_pending корректен только на одной реплике сервера. При нескольких репликах два поллера могут забрать одну и ту же строку и отправить дублирующий PKCSReq во внешний CA. Подробный разбор механизма — Отказоустойчивость (HA), раздел «Что НЕ безопасно на N репликах сегодня» → «SCEP-поллинг».

Прямого REST-эндпоинта для очереди ca_pending нет — мониторинг идёт через SQL или через сами заявки:

-- Заявки, зависшие в ca_pending дольше нескольких интервалов поллинга
SELECT sp.cert_request_id, sp.attempts, sp.next_poll_at, sp.last_error,
       cr.status, cr.created_at
FROM scep_pending sp
JOIN cert_requests cr ON cr.id = sp.cert_request_id
WHERE sp.next_poll_at < now() - interval '10 minutes'
ORDER BY sp.next_poll_at;

Растущее attempts с непустым last_error на одной и той же строке — сигнал, что внешний SCEP CA систематически не выпускает сертификат по этому запросу (истёкший challenge, недоступность CA, и т.п.) — смотрите last_error за деталями конкретного отказа CA. Единичные «потерянные» сертификаты у осиротевшего SCEP-poll (см. предупреждение выше про несколько реплик) обычно не видны через эту таблицу — они уже покинули scep_pending на стороне Alatyr, но не были никогда получены обратно; искать их нужно в логах CA, не здесь.

Продление сертификатов и волна одобрений

Агент продлевает сертификат самостоятельно, проходя тот же цикл enroll, что и при первичной выдаче, — подробный разбор механизма: Агенты → Продление сертификата. Для планирования эксплуатации важно одно следствие этого механизма: продление создаёт новую заявку, и она проходит ту же проверку одобрения, что и первичная.

  • При ручном одобрении заявок ожидайте периодическую волну заявок на одобрение по мере того, как у устройств флота подходит к концу срок действия сертификата, а не равномерный редкий поток. По умолчанию срок действия машинного сертификата (wifi) — 3 года; это единственная цель, у которой значение настраивается на сервере. У остальных целей срок фиксированный: user_mtls и ad_logon — 1 год, ssh — 24 часа.
  • Если для соответствующего purpose настроено автоодобрение (сервисный аккаунт с ролью cert-auto-approver, см. Администрирование → Approve / reject / revoke заявок), волна проходит без ручных действий со стороны оператора.

Хранение снапшотов логов устройств

Загруженные через POST /api/v1/devices/{serial}/request-logs снапшоты логов устройств хранятся не дольше 7 дней — фоновая задача сама очищает устаревшие снапшоты, отдельного обслуживания не требует.

См. также