Files
AWatch-rus/docs/PRODUCTION_READINESS_RU.md
T

340 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Контроль готовности промышленного внедрения
`detmir-readiness` - единая команда preflight-контроля перед внедрением,
релизом или изменением production runtime.
Команда проверяет:
- runtime env без public placeholders;
- активность обязательных systemd units;
- реальную запись в InfluxDB;
- health Grafana datasource.
## Portal production hardening
Портал AWatch-rus дополнен отдельным production-hardening слоем. Он не заменяет
`detmir-readiness`, а закрывает HTTP/API надежность портала: liveness,
readiness, version metadata, Prometheus metrics, request id/correlation id,
bounded payload/query limits и role-gate smoke.
### HTTP endpoints
| Endpoint | Назначение | Внешние зависимости |
| --- | --- | --- |
| `GET /healthz` | Liveness процесса; возвращает `200 OK`, если процесс отвечает. | Не проверяет |
| `GET /readyz` | Готовность приложения обслуживать запросы. | Только реально настроенные локальные зависимости |
| `GET /version` | Версия приложения, schema version, build metadata. | Не проверяет |
| `GET /metrics` | Prometheus text format. | Не проверяет |
`/readyz` не заявляет SIEM, DLP ingestion или pfSense ingestion. pfSense
отображается как `contract_only`: контрактная готовность, не реальный
полноценный сборщик.
### Конфигурация и лимиты
Портал валидирует конфигурацию при старте и завершает работу с понятной
ошибкой, если значение небезопасно или некорректно. Секреты в ошибку не
попадают.
| Параметр | Env | Назначение |
| --- | --- | --- |
| `--bind` | `DETMIR_PORTAL_BIND` | `host:port` HTTP-сервера |
| `--max-page-size` | `AWATCH_PORTAL_MAX_PAGE_SIZE` | Верхний предел `page_size`/`limit` |
| `--default-page-size` | `AWATCH_PORTAL_DEFAULT_PAGE_SIZE` | Значение по умолчанию для страниц |
| `--max-report-date-range-days` | `AWATCH_PORTAL_MAX_REPORT_DATE_RANGE_DAYS` | Максимальный диапазон отчетов |
| `--request-timeout-seconds` | `AWATCH_PORTAL_REQUEST_TIMEOUT_SECONDS` | Целевой timeout запроса/операции |
| `--max-request-body-bytes` | `AWATCH_PORTAL_MAX_REQUEST_BODY_BYTES` | Общий лимит тела запроса |
| `--slow-request-log-ms` | `AWATCH_PORTAL_SLOW_REQUEST_LOG_MS` | Порог медленного запроса для логов |
| `--environment` | `AWATCH_PORTAL_ENVIRONMENT` | Безопасное имя окружения |
| `--enabled-modules` | `AWATCH_PORTAL_ENABLED_MODULES` | Разрешенные модули портала |
Ограничения применяются к тяжелым API:
- `/api/reports`;
- `/api/executive`;
- `/api/workforce`;
- `/api/security`;
- `/api/forensics`;
- `/api/ueba`;
- `/api/pfsense`;
- `/api/workforce/kpi/explain`.
Поведение:
- слишком большой `page_size` или `limit` возвращает `400`;
- слишком широкий диапазон `date_from/date_to`, `from/to`, `start/end`
возвращает `400`;
- слишком большое тело запроса возвращает `413`;
- role gate возвращает `403`.
### Request ID, logs и metrics
Портал принимает `X-Request-Id` и `X-Correlation-Id`. Если заголовки не
переданы, `X-Request-Id` генерируется сервером, а `X-Correlation-Id` получает
то же значение. Оба заголовка возвращаются в ответе.
HTTP-ответы пишутся в stderr как JSON-строки с полями:
- `timestamp`;
- `level`;
- `request_id`;
- `correlation_id`;
- `method`;
- `path` без query params;
- `route`;
- `status`;
- `latency_ms`;
- `user_role`;
- `module`;
- `error_code`;
- `response_bytes`.
В логах не должно быть токенов, тел запросов, IP-адресов клиента,
`employee_id`, сырых query params или персональных данных.
`GET /metrics` возвращает:
- `awatch_http_requests_total`;
- `awatch_http_request_duration_seconds`;
- `awatch_reports_generated_total`;
- `awatch_ingestion_records_total`;
- `awatch_ingestion_rejected_total`;
- `awatch_role_denied_total`;
- `awatch_readyz_status`.
Labels ограничены низкой кардинальностью: `method`, `route`, `status`,
`module`. Запрещены high-cardinality labels: `user_id`, `employee_id`, IP, raw
URL, query params.
### Portal smoke
Минимальный smoke:
```bash
AWATCH_PORTAL_SMOKE_URL=http://127.0.0.1:8720 \
node scripts/awatch-production-hardening-smoke.mjs
```
Smoke проверяет `/healthz`, `/readyz`, `/version`, `/metrics`, возврат
`X-Request-Id`, reject слишком большого `page_size`, reject слишком широкого
report range, role gates и `/api/workforce/kpi/explain`.
## Базовый запуск
На AW server:
```bash
detmir-readiness --json
```
Ожидаемый результат:
```json
{
"ok": true,
"status": "OK"
}
```
Коды возврата:
- `0` - готово к промышленной эксплуатации;
- `2` - readiness check нашел `WARN`;
- `3` - readiness check нашел `FAIL`;
- `1` - сама команда не смогла выполниться.
## Private production inventory
Перед rollout private override-файлы проверяются отдельно:
```bash
scripts/check_production_inventory_placeholders.sh --strict \
private-config/runtime.env \
private-config/ansible-vars.yml
```
`--strict` предназначен только для private production-файлов. Публичные
tracked defaults и `.example` файлы могут содержать `HOST-EXAMPLE` и TEST-NET
адреса, потому что они не являются production source of truth.
## Что считается отказом
`detmir-readiness` возвращает `FAIL`, если:
- включенный Influx exporter получил пустой или example URL/org/bucket/token/host;
- systemd unit из обязательного списка не active;
- Influx write-probe не смог записать heartbeat;
- Grafana datasource health не `OK`.
## Акт готовности стенда
`detmir-readiness` может сохранить акт готовности в JSON, Markdown, HTML и PDF:
```bash
detmir-readiness --json \
--output-json /var/lib/activitywatch/health/detmir-readiness-latest.json \
--output-markdown /var/lib/activitywatch/health/detmir-readiness-act.md \
--output-pdf /var/lib/activitywatch/health/detmir-readiness-act.pdf
```
PDF-вывод требует один из render tools на хосте: `weasyprint`, `chromium`,
`chromium-browser` или `google-chrome`. Если PDF renderer не установлен,
используйте `--output-markdown` и `--output-html` как обязательный минимальный
артефакт внедрения.
## Readiness bundle
Для промышленного контура предпочтителен единый bundle:
```bash
detmir-readiness --output-dir /var/lib/activitywatch/health/readiness-bundle
```
Команда создает:
- `detmir-readiness-latest.json` - машинный отчет;
- `detmir-readiness-act.md` - акт готовности для оператора;
- `detmir-readiness-act.html` - HTML-версия акта;
- `sha256sums.txt` - контрольные суммы bundle-файлов;
- `sha256sums.txt.sig` - detached signature для `sha256sums.txt`;
- `public-key.pem` - публичный ключ проверки подписи;
- `detmir-readiness-status.json` - короткий machine-readable статус bundle;
- `detmir-readiness.prom` - Prometheus textfile metric.
Архив хранится по датам:
```text
/var/lib/activitywatch/health/readiness-bundle/
2026-06-03/
062000Z/
detmir-readiness-latest.json
detmir-readiness-act.md
detmir-readiness-act.html
sha256sums.txt
sha256sums.txt.sig
public-key.pem
```
Файлы в корне `readiness-bundle/` являются latest-копией последнего архива.
Проверка целостности:
```bash
cd /var/lib/activitywatch/health/readiness-bundle
sha256sum -c sha256sums.txt
openssl dgst -sha256 -verify public-key.pem \
-signature sha256sums.txt.sig sha256sums.txt
```
В JSON и акт добавляются технические поля `generated_by`, `host`, `version`,
`git_commit`, а также раздел `Ограничения проверки`. Секреты, токены и пароли
в артефакты не включаются.
Private signing key хранится только на сервере:
```text
/etc/detmir-readiness/signing-key.pem
```
Публичный ключ попадает в bundle как `public-key.pem`. Retention архивов
управляется переменной `DETMIR_READINESS_RETENTION_DAYS`.
Fingerprint публичного ключа считается как SHA-256 файла `public-key.pem` и
дублируется в `detmir-readiness-status.json`:
```bash
sha256sum /var/lib/activitywatch/health/readiness-bundle/public-key.pem
jq -r '.signature.public_key_fingerprint_sha256' \
/var/lib/activitywatch/health/readiness-bundle/detmir-readiness-status.json
```
Для публичной поставки вместо live fingerprint используется placeholder
`<READINESS_PUBLIC_KEY_SHA256_FINGERPRINT>`; конкретный customer contour
фиксирует свой fingerprint в private acceptance package.
## Ежедневное формирование
При штатном развертывании Ansible устанавливает:
- `detmir-readiness.service`;
- `detmir-readiness.timer`.
Таймер ежедневно формирует readiness bundle в
`/var/lib/activitywatch/health/readiness-bundle`.
Операторская проверка:
```bash
systemctl list-timers detmir-readiness.timer
systemctl start detmir-readiness.service
systemctl status detmir-readiness.service --no-pager
```
Если Grafana находится на отдельном узле, параметры доступа передаются через
серверный private env-файл `/etc/detmir-grafana-check.env` или
`/etc/detmir-readiness.env`. Эти файлы не входят в публичный репозиторий.
Поддерживаемые private env-переключатели:
- `DETMIR_READINESS_SIGNING_KEY=/etc/detmir-readiness/signing-key.pem`;
- `DETMIR_READINESS_REQUIRE_SIGNATURE=true`;
- `DETMIR_READINESS_RETENTION_DAYS=30`;
- `DETMIR_READINESS_SKIP_SYSTEMD=true`;
- `DETMIR_READINESS_SKIP_INFLUX_WRITE=true`;
- `DETMIR_READINESS_ALLOW_DISABLED_INFLUX=true`;
- `DETMIR_READINESS_SKIP_GRAFANA=true`;
- `DETMIR_GRAFANA_DATASOURCE_UID=<uid>`;
- `DETMIR_GIT_COMMIT=<commit>`.
## Portal endpoints
`detmir-portal` публикует read-only endpoints:
- `/api/readiness/latest` - последний readiness JSON;
- `/api/readiness/bundle` - индекс latest bundle и список артефактов;
- `/api/readiness/verify` - проверка `sha256sum -c` и detached signature.
В UI портала карточка `Готовность системы` показывает статус `OK/WARN/FAIL`,
дату формирования, состояние checksum/signature и fingerprint публичного ключа.
Кнопка `Проверить bundle` запускает lightweight verify endpoint без повторного
запуска runtime checks.
## Prometheus alerts
Поставочный файл правил:
```text
aw-server/detmir-readiness-alerts.yml
```
Критичные условия:
```promql
detmir_readiness_ok == 0
detmir_readiness_signature_verified == 0
```
## Полезные параметры
```bash
detmir-readiness --json \
--aw-env-file /etc/activitywatch/aw-server.env \
--grafana-env-file /etc/detmir-grafana-check.env \
--grafana-datasource-uid influxdb_aw
```
Для диагностики без write-probe:
```bash
detmir-readiness --json --skip-influx-write
```
Для контура, где Influx временно не входит в профиль внедрения:
```bash
detmir-readiness --json --allow-disabled-influx
```
Такой запуск допустим только как временный исключительный режим; для полного
commercial AWatch-rus contour Influx/Grafana должны быть зелеными.