Реализация на отдельных двух машинах с протестированным взаимодействием по проверке сообщений
This commit is contained in:
@@ -1,8 +1,12 @@
|
||||
# Ранбук развёртывания Processing на VM2
|
||||
|
||||
Этот каталог — независимая основа VM2. Он не разворачивает VM1 и не
|
||||
затрагивает `codebase/backend`. Все команды ниже — операторские; создание
|
||||
репозитория их не выполняет.
|
||||
Этот каталог — независимая основа VM2 в репозитории `VM2_services`. Он не
|
||||
разворачивает VM1 и не затрагивает `VM1_app/codebase/backend`. Все команды
|
||||
ниже — операторские; создание репозитория их не выполняет.
|
||||
|
||||
Корень репозитория ВМ2: `HAN_chat_specification/VM2_services`. Compose и
|
||||
deployment-артефакты: `VM2_services/codebase/services/`. Локальные команды
|
||||
ниже предполагают текущий каталог `VM2_services`, если не указано иное.
|
||||
|
||||
## Блокеры production перед первым запуском
|
||||
|
||||
@@ -64,6 +68,33 @@
|
||||
не входит в `docker`/`lxd`; каждый вход и sudo-вызов считается инцидентной
|
||||
операцией.
|
||||
|
||||
## Предварительные условия (до §1)
|
||||
|
||||
Этот runbook описывает операции **на уже созданной VM2**. До bootstrap
|
||||
подготовьте вне Compose:
|
||||
|
||||
1. **Инфраструктура Selectel** — VPC/subnet, SG (`80/443/22` public;
|
||||
`8443` только private; egress default-deny после bootstrap), sizing
|
||||
(4 vCPU / 8 ГБ RAM / 80 ГБ SSD — см.
|
||||
[`module-10-deployment-vm2.md`](../../../documentation/module-10-deployment-vm2.md)),
|
||||
public и private IP VM2, DNS A-запись `PROCESSING_PUBLIC_HOST`.
|
||||
2. **Managed PostgreSQL** — schemas/roles для `message_safety` и
|
||||
`bitrix_sync`, отдельные migration/runtime DSN; см.
|
||||
[`arch-10-deployment.md`](../../../../architectory/arch-10-deployment.md) §6.
|
||||
3. **Образы** — собрать и push `han-message-safety`, `han-bitrix-sync`;
|
||||
получить immutable digest для всех `*_IMAGE` в `.env.example` (nginx, redis,
|
||||
clamav, otel-collector).
|
||||
4. **Selectel Secrets Manager** — заполнить все remote names из
|
||||
`deployment/secrets/config.example.json` (DSN, tokens, S3 read-only keys,
|
||||
`REDIS_SAFETY_ACL`, internal TLS PEM для `8443`). Отдельный IAM principal
|
||||
VM2 с read-only доступом только к этим именам.
|
||||
5. **S3 quarantine bucket** и SigNoz OTLP endpoint — значения в `.env`.
|
||||
6. **Internal TLS** — сертификат внутренней CA с SAN = private DNS VM2;
|
||||
PEM хранится в Secrets Manager, не в каталоге релиза.
|
||||
|
||||
Порядок разделов §1–§5 → Gates 1–9 → §7 (post-acceptance). `systemctl enable`
|
||||
и `systemctl start han-processing.service` — **только после успешного Gate 5**.
|
||||
|
||||
## 1. Bootstrap свежей VM2
|
||||
|
||||
На локальном компьютере один раз создайте **два разных** ключа. Закрытые части
|
||||
@@ -85,8 +116,9 @@ break-glass оператору и храниться отдельно от deplo
|
||||
каталог:
|
||||
|
||||
```powershell
|
||||
# текущий каталог: ...\HAN_chat_specification\VM2_services
|
||||
scp -i C:\Users\MI\.ssh\hansel `
|
||||
.\HAN_chat_specification\codebase\services\deployment\scripts\setup-vm.sh `
|
||||
.\codebase\services\deployment\scripts\setup-vm.sh `
|
||||
root@<VM2_PUBLIC_IP>:/root/setup-vm2.sh
|
||||
scp -i C:\Users\MI\.ssh\hansel `
|
||||
C:\Users\MI\.ssh\han_vm2_deploy.pub `
|
||||
@@ -161,8 +193,8 @@ sudo rm -f /root/han_vm2_deploy.pub /root/han_vm2_admin.pub
|
||||
```
|
||||
|
||||
## 2. Передача релиза под `deploy`
|
||||
|
||||
На локальном компьютере из каталога `HAN_chat_specification`:
|
||||
|
||||
На локальном компьютере из каталога `VM2_services`:
|
||||
|
||||
```powershell
|
||||
$Release = "<VERSION_OR_GIT_SHA>"
|
||||
@@ -390,71 +422,16 @@ Nginx с primary GID `11001` получает только подготовле
|
||||
`/etc/letsencrypt` остаётся доступен только root/Certbot. Не копируйте private
|
||||
key в каталог релиза и не делайте его world-readable.
|
||||
|
||||
## 6. Preflight, миграции и первый запуск под `root`
|
||||
## 6. Gates 1–9: preflight, миграции и первый запуск под `root`
|
||||
|
||||
Сначала синхронизируйте секреты. Затем выполните статический preflight:
|
||||
|
||||
```sh
|
||||
systemctl start han-secrets-vm2.service
|
||||
/opt/han-chat/services/deployment/preflight.sh
|
||||
/usr/local/sbin/han-vm2-compose config --quiet
|
||||
```
|
||||
|
||||
До runtime выполните миграции отдельными DB roles и активируйте начальный
|
||||
Message Safety config:
|
||||
|
||||
Перед первым `bitrix-sync-migrate` владелец `han_app` или администратор БД
|
||||
выдаёт Bitrix migration-role временный read-only доступ к legacy mapping:
|
||||
|
||||
```sql
|
||||
GRANT USAGE ON SCHEMA han_app TO <BITRIX_SYNC_MIGRATION_ROLE>;
|
||||
GRANT SELECT ON TABLE han_app.entity_external_mapping
|
||||
TO <BITRIX_SYNC_MIGRATION_ROLE>;
|
||||
```
|
||||
|
||||
```sh
|
||||
/usr/local/sbin/han-vm2-compose --profile ops run --rm message-safety-migrate
|
||||
/usr/local/sbin/han-vm2-compose --profile ops run --rm bitrix-sync-migrate
|
||||
|
||||
/usr/local/sbin/han-vm2-compose --profile ops run --rm \
|
||||
--entrypoint message-safety-config message-safety-migrate \
|
||||
create /app/app/artifacts/seed-config.yaml --version 1 --actor '<OPERATOR>'
|
||||
/usr/local/sbin/han-vm2-compose --profile ops run --rm \
|
||||
--entrypoint message-safety-config message-safety-migrate \
|
||||
activate --version 1 --approved-by '<APPROVER>'
|
||||
```
|
||||
|
||||
После успешного `bitrix-sync-migrate` администратор БД отзывает временные
|
||||
права. Право `USAGE` отзывайте только если оно не требуется этой роли для
|
||||
других согласованных операций:
|
||||
|
||||
```sql
|
||||
REVOKE SELECT ON TABLE han_app.entity_external_mapping
|
||||
FROM <BITRIX_SYNC_MIGRATION_ROLE>;
|
||||
REVOKE USAGE ON SCHEMA han_app FROM <BITRIX_SYNC_MIGRATION_ROLE>;
|
||||
```
|
||||
|
||||
Первый запуск и enable выполняет `root` только после прохождения gates:
|
||||
(внутри gate5)
|
||||
|
||||
```sh
|
||||
systemctl enable han-secrets-vm2.service han-processing.service
|
||||
systemctl start han-processing.service
|
||||
systemctl --no-pager status han-processing.service
|
||||
journalctl --no-pager -u han-processing.service
|
||||
```
|
||||
|
||||
Дальнейшие штатные операции может выполнить `deploy`:
|
||||
|
||||
```sh
|
||||
sudo systemctl restart han-secrets-vm2.service
|
||||
sudo systemctl restart han-processing.service
|
||||
sudo systemctl --no-pager status han-processing.service
|
||||
sudo journalctl --no-pager -u han-processing.service
|
||||
```
|
||||
Выполняйте gates **строго по порядку** 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9.
|
||||
Не включайте `han-processing.service` и не делайте `systemctl enable`, пока
|
||||
Gate 5 не завершился успешно.
|
||||
|
||||
Установка/редактирование unit, Compose, `.env`, secret mapping, credential,
|
||||
TLS, allow-list и запуск migration jobs остаются операциями `root`.
|
||||
После Gate 5 штатный restart/status/logs для `deploy` — см. блок
|
||||
«Дальнейшие штатные операции» ниже.
|
||||
|
||||
### Gate 1 — секреты материализованы
|
||||
|
||||
@@ -490,7 +467,39 @@ deployment/preflight.sh
|
||||
|
||||
### Gate 3 — миграции и активный Message Safety config
|
||||
|
||||
Команды миграций из предыдущего раздела выполняются под `root`. После них:
|
||||
Под `root`. Перед первым `bitrix-sync-migrate` владелец `han_app` или
|
||||
администратор БД выдаёт Bitrix migration-role временный read-only доступ к
|
||||
legacy mapping:
|
||||
|
||||
```sql
|
||||
GRANT USAGE ON SCHEMA han_app TO <BITRIX_SYNC_MIGRATION_ROLE>;
|
||||
GRANT SELECT ON TABLE han_app.entity_external_mapping
|
||||
TO <BITRIX_SYNC_MIGRATION_ROLE>;
|
||||
```
|
||||
|
||||
```sh
|
||||
/usr/local/sbin/han-vm2-compose --profile ops run --rm message-safety-migrate
|
||||
/usr/local/sbin/han-vm2-compose --profile ops run --rm bitrix-sync-migrate
|
||||
|
||||
/usr/local/sbin/han-vm2-compose --profile ops run --rm \
|
||||
--entrypoint message-safety-config message-safety-migrate \
|
||||
create /app/app/artifacts/seed-config.yaml --version 1 --actor '<OPERATOR>'
|
||||
/usr/local/sbin/han-vm2-compose --profile ops run --rm \
|
||||
--entrypoint message-safety-config message-safety-migrate \
|
||||
activate --version 1 --approved-by '<APPROVER>'
|
||||
```
|
||||
|
||||
После успешного `bitrix-sync-migrate` администратор БД отзывает временные
|
||||
права. Право `USAGE` отзывайте только если оно не требуется этой роли для
|
||||
других согласованных операций:
|
||||
|
||||
```sql
|
||||
REVOKE SELECT ON TABLE han_app.entity_external_mapping
|
||||
FROM <BITRIX_SYNC_MIGRATION_ROLE>;
|
||||
REVOKE USAGE ON SCHEMA han_app FROM <BITRIX_SYNC_MIGRATION_ROLE>;
|
||||
```
|
||||
|
||||
Проверьте head revision и активную config version:
|
||||
|
||||
```sh
|
||||
/usr/local/sbin/han-vm2-compose --profile ops run --rm \
|
||||
@@ -623,6 +632,16 @@ Message Safety; проверьте её без вывода секретов:
|
||||
systemctl enable han-secrets-vm2.service han-processing.service
|
||||
systemctl start han-processing.service
|
||||
systemctl --no-pager status han-processing.service
|
||||
journalctl --no-pager -u han-processing.service
|
||||
```
|
||||
|
||||
Дальнейшие штатные операции может выполнить `deploy`:
|
||||
|
||||
```sh
|
||||
sudo systemctl restart han-secrets-vm2.service
|
||||
sudo systemctl restart han-processing.service
|
||||
sudo systemctl --no-pager status han-processing.service
|
||||
sudo journalctl --no-pager -u han-processing.service
|
||||
```
|
||||
|
||||
### Gate 6 — host ports и сертификаты
|
||||
@@ -811,47 +830,10 @@ unset CANARY
|
||||
упавший receiver должен возвращать retryable `503`/закрытую маршрутизацию,
|
||||
никогда успешный `2xx ignored`.
|
||||
|
||||
## Политика отказов
|
||||
## 7. После Gate 9 — post-acceptance
|
||||
|
||||
- Отказ зависимости Safety — fail-closed: VM1 не должна отправлять/продвигать
|
||||
контент.
|
||||
- Устаревшие/недоступные сигнатуры ClamAV отключают только файловую
|
||||
capability; ошибка сканирования никогда не превращается в allow.
|
||||
- Потеря Redis может убрать ускорение, но PostgreSQL остаётся источником
|
||||
истины.
|
||||
- Сбой OTEL ставит в очередь в пределах ограниченного тома и не должен
|
||||
менять вердикты.
|
||||
- Rollback не понижает схемы, не удаляет durable tasks/mappings и не
|
||||
запускает `docker compose down -v`.
|
||||
|
||||
## Аварийный MOCK
|
||||
|
||||
Разрешены только эти пять sudo-команд:
|
||||
|
||||
```text
|
||||
han-message-safety-mode standard
|
||||
han-message-safety-mode mock --text-free true --file-free true
|
||||
han-message-safety-mode mock --text-free true --file-free false
|
||||
han-message-safety-mode mock --text-free false --file-free true
|
||||
han-message-safety-mode mock --text-free false --file-free false
|
||||
```
|
||||
|
||||
Хелпер атомарно пишет только
|
||||
`/etc/han-chat/message-safety-mode.env`, пересоздаёт только Safety API,
|
||||
проверяет health и при сбое восстанавливает предыдущий режим. У MOCK нет
|
||||
таймаута: держите high-severity alert активным до явного `standard`, затем
|
||||
проверьте нормальные text/link/file capabilities и EICAR-canary.
|
||||
|
||||
## Известные исключения по образам
|
||||
|
||||
Образы ClamAV могут потребовать корректировок UID/path после валидации
|
||||
точного digest. Не ослабляйте `read_only`, capabilities или mounts глобально:
|
||||
задокументируйте минимальные writable пути для сигнатур/runtime и
|
||||
компенсируйте сетевыми и ресурсными лимитами. Egress к signature-CDN
|
||||
получает только `freshclam`; `clamd` — нет.
|
||||
|
||||
|
||||
# Gate 9 завершает техническую приёмку VM2, но не означает production cutover сервисов.
|
||||
Gate 9 завершает техническую приёмку VM2, но **не** означает production
|
||||
cutover Message Safety на VM1 и **не** разрешает включать Bitrix sync.
|
||||
|
||||
Дальнейший порядок:
|
||||
|
||||
@@ -912,6 +894,237 @@ BITRIX_SYNC_ENABLED=false
|
||||
BITRIX_SYNC_MODE=disabled
|
||||
```
|
||||
|
||||
Public allow-list — только `deny all;`. Включать Bitrix можно лишь после выполнения gates `module-07`: поля портала, webhooks, migrations, grants, backfill/watermark и rollback rehearsal.
|
||||
Public allow-list — только `deny all;`. Включать Bitrix можно лишь после
|
||||
выполнения gates [`module-07-bitrix-sync.md`](../../../documentation/module-07-bitrix-sync.md):
|
||||
поля портала, webhooks, migrations, grants, backfill/watermark и rollback
|
||||
rehearsal.
|
||||
|
||||
Таким образом, ближайший шаг сейчас — reboot-gate и фиксация приёмки VM2. Затем переход к интеграции VM1, а не немедленное включение Bitrix.
|
||||
После успешного Gate 9 выполните reboot-gate (п. 2 выше), зафиксируйте
|
||||
приёмку (п. 3), затем выполните отдельный controlled cutover ниже. Gate 9 сам
|
||||
по себе не разрешает переключать caller.
|
||||
|
||||
### Controlled cutover Message Safety на VM1
|
||||
|
||||
Cutover выполняется в согласованное окно совместно с Safety Service,
|
||||
Rule Pack, Security, Product и Operations. До начала зафиксируйте текущий и
|
||||
предыдущий schema-compatible immutable release VM1, ответственного за rollback
|
||||
и stop conditions. `bitrix-sync` в это окно не включается.
|
||||
|
||||
#### 1. Предварительные условия
|
||||
|
||||
До изменения VM1 должны быть выполнены все условия:
|
||||
|
||||
- reboot-gate VM2 и повторные Gates 6–8 успешны;
|
||||
- Safety работает в `standard`, не в `mock`;
|
||||
- active config и rules bundle утверждены, Safety v2 migrations находятся на
|
||||
ожидаемом head;
|
||||
- `text`, `links`, `files`, `worker` имеют состояние `ready`;
|
||||
- VM2 имеет только read-only доступ к versioned S3 quarantine objects;
|
||||
- performance, egress negative tests и redaction Gate 9 закрыты;
|
||||
- private DNS VM2 резолвится с VM1 только в private VPC address;
|
||||
- security group/firewall разрешает `8443` от VM1 и approved ops, но не из
|
||||
интернета;
|
||||
- на VM1 подготовлен release без local `message-safety`, Redis DB2, local rules
|
||||
env и stub fallback;
|
||||
- один и тот же production service token подготовлен в раздельных secret
|
||||
bundles VM1 и VM2; значение токена не печатается и не копируется в
|
||||
`/etc/han/vm1.env`.
|
||||
|
||||
На VM1 под `root` повторите проверку TLS и readiness:
|
||||
|
||||
```sh
|
||||
openssl s_client -connect <VM2_PRIVATE_IP>:8443 \
|
||||
-servername <VM2_PRIVATE_DNS_NAME> \
|
||||
-verify_hostname <VM2_PRIVATE_DNS_NAME> \
|
||||
-CAfile /etc/han/ca/vm2-internal-ca.pem \
|
||||
-verify_return_error </dev/null
|
||||
|
||||
curl --fail --silent --show-error \
|
||||
--cacert /etc/han/ca/vm2-internal-ca.pem \
|
||||
https://<VM2_PRIVATE_DNS_NAME>:8443/internal/safety/status
|
||||
```
|
||||
|
||||
В TLS-выводе ожидается успешная проверка chain/SAN. В status ожидаются
|
||||
`processing_mode=standard`, непустой `config_version` и
|
||||
`text|links|files|worker=ready`. `stub`, `mock`, `not_ready` или недоступная
|
||||
capability — stop condition.
|
||||
|
||||
#### 2. Прямой pre-cutover smoke с VM1
|
||||
|
||||
Прямой smoke доказывает route, CA и paired token до перезапуска caller:
|
||||
|
||||
```sh
|
||||
SAFETY_TOKEN="$(cat <MESSAGE_SAFETY_SERVICE_TOKEN_FILE_ON_VM1>)"
|
||||
MESSAGE_ID="$(uuidgen)"
|
||||
curl --silent --show-error --write-out '\nHTTP %{http_code}\n' --config - <<EOF
|
||||
url = "https://<VM2_PRIVATE_DNS_NAME>:8443/internal/safety/v2/messages/check"
|
||||
cacert = "/etc/han/ca/vm2-internal-ca.pem"
|
||||
request = "POST"
|
||||
header = "X-Service-Token: ${SAFETY_TOKEN}"
|
||||
header = "X-Request-ID: ${MESSAGE_ID}"
|
||||
header = "Content-Type: application/json"
|
||||
data = "{\"message_id\":\"${MESSAGE_ID}\",\"content_kind\":\"text\",\"text\":\"VM1 to VM2 cutover canary\",\"attachment\":null}"
|
||||
EOF
|
||||
unset SAFETY_TOKEN MESSAGE_ID
|
||||
```
|
||||
|
||||
Ожидается `HTTP 200`, `verdict=allow`, `processing_mode=standard` и непустые
|
||||
`config_version`/`rules_version`. Отдельный запрос с фейковым token marker
|
||||
должен вернуть `401`; production token для negative test не изменяйте.
|
||||
|
||||
До переключения также выполните через API VM2:
|
||||
|
||||
- deny smoke на утверждённом безопасном corpus case — ожидается `403`;
|
||||
- повтор запроса с тем же `message_id` и тем же body — тот же sticky result;
|
||||
- тот же `message_id` с другим body — `409`;
|
||||
- file smoke только с реальным versioned quarantine object:
|
||||
`202 + Location + Retry-After`, затем terminal `200` или `403`;
|
||||
- lease/fencing smoke с остановкой/возвратом worker по утверждённому test case:
|
||||
task не исполняется двумя владельцами и сохраняет sticky terminal result.
|
||||
|
||||
Не используйте выдуманные S3 key/version/ETag и не загружайте EICAR в
|
||||
production bucket вне согласованного security test.
|
||||
|
||||
#### 3. Переключение caller на VM1
|
||||
|
||||
На VM1 установите и проверьте internal CA по процедуре
|
||||
[`RUNBOOK.production.ru.md`](../../../../VM1_app/codebase/backend/deployment/RUNBOOK.production.ru.md)
|
||||
§6. В `/etc/han/vm1.env` должны быть:
|
||||
|
||||
```dotenv
|
||||
MESSAGE_SAFETY_URL=https://<VM2_PRIVATE_DNS_NAME>:8443
|
||||
MESSAGE_SAFETY_CA_HOST_PATH=/etc/han/ca/vm2-internal-ca.pem
|
||||
MESSAGE_SAFETY_API_PREFIX=/internal/safety/v2
|
||||
```
|
||||
|
||||
В root-owned Selectel secret mapping VM1 переменная
|
||||
`MESSAGE_SAFETY_SERVICE_TOKEN` должна ссылаться на согласованный remote secret.
|
||||
После review config и mapping:
|
||||
|
||||
```sh
|
||||
cd /opt/han-chat/current/backend
|
||||
./scripts/validate-env /etc/han/vm1.env
|
||||
|
||||
systemctl restart han-secrets@production.service
|
||||
systemctl is-active han-secrets@production.service
|
||||
journalctl --no-pager -u han-secrets@production.service
|
||||
|
||||
./deployment/preflight.sh
|
||||
/usr/local/sbin/han-vm1-compose config --quiet
|
||||
/usr/local/sbin/han-vm1-compose config --services
|
||||
/usr/local/sbin/han-vm1-compose config --images
|
||||
```
|
||||
|
||||
В `config --services` не должно быть local `message-safety`, `bitrix-sync`,
|
||||
Redis DB2 или test stub. Не сохраняйте resolved Compose в файл и не выводите
|
||||
secret values. Если preflight успешен, переключите caller:
|
||||
|
||||
```sh
|
||||
systemctl restart han-stack@production.service
|
||||
systemctl is-active han-stack@production.service
|
||||
/usr/local/sbin/han-vm1-compose ps
|
||||
```
|
||||
|
||||
#### 4. Post-cutover проверки через caller
|
||||
|
||||
Проверки выполняются через public API/штатный UI VM1, а не только прямым curl к
|
||||
VM2:
|
||||
|
||||
1. benign text проходит Safety и отправляется ровно один раз;
|
||||
2. утверждённый deny text не отправляется в Bitrix и возвращает клиенту generic
|
||||
`message_blocked` без internal `rule_id`;
|
||||
3. сообщение с безопасной HTTP/HTTPS-ссылкой проходит, запрещённая
|
||||
private/link-local/metadata ссылка блокируется без HTTP fetch этой ссылки;
|
||||
4. реальный quarantine file проходит `pending` и terminal result, после allow
|
||||
продвигается штатным caller flow; deny-файл не продвигается;
|
||||
5. повтор client/idempotency request не создаёт второе сообщение или второй
|
||||
Safety task;
|
||||
6. correlation request ID виден в VM1, VM2 и SigNoz без текста сообщения,
|
||||
token, object key и других секретов.
|
||||
|
||||
Затем согласованным способом кратко сделайте VM2 недоступной **только для
|
||||
test request** и подтвердите fail-closed: VM1 не отправляет и не продвигает
|
||||
контент, возвращает контролируемую retryable ошибку, а local/stub fallback не
|
||||
активируется. Сразу восстановите доступ и повторите benign smoke. Не имитируйте
|
||||
отказ остановкой всей VM2, если на ней уже есть другой production traffic.
|
||||
|
||||
#### 5. Rollback rehearsal
|
||||
|
||||
Rollback caller — только на заранее проверенный предыдущий
|
||||
schema-compatible immutable release VM1 по
|
||||
[`RUNBOOK.production.ru.md`](../../../../VM1_app/codebase/backend/deployment/RUNBOOK.production.ru.md)
|
||||
§12. Он не меняет nginx VM2, не понижает schema и не удаляет уже созданные
|
||||
Safety tasks:
|
||||
|
||||
```sh
|
||||
PREVIOUS='<PREVIOUS_COMPATIBLE_GIT_SHA>'
|
||||
test -d "/opt/han-chat/releases/${PREVIOUS}/backend"
|
||||
ln -s "releases/${PREVIOUS}" /opt/han-chat/.current-new
|
||||
mv -Tf /opt/han-chat/.current-new /opt/han-chat/current
|
||||
systemctl daemon-reload
|
||||
systemctl restart han-secrets@production.service
|
||||
/opt/han-chat/current/backend/deployment/preflight.sh
|
||||
systemctl restart han-stack@production.service
|
||||
```
|
||||
|
||||
После rehearsal повторите public smoke, верните approved current release тем же
|
||||
атомарным способом и снова повторите smoke. Потеря VM2 не разрешает fail-open,
|
||||
переключение на local stub или обход Safety. При несовместимой migration
|
||||
rollback запрещён: используйте forward fix либо заранее согласованный recovery
|
||||
plan.
|
||||
|
||||
#### 6. Фиксация cutover
|
||||
|
||||
Сохраните без secret values:
|
||||
|
||||
- VM1/VM2 release и image digests, Safety schema head;
|
||||
- private certificate fingerprint/expiry, `config_version` и `rules_version`;
|
||||
- результаты allow/deny/pending/file/timeout/fail-closed/idempotency checks;
|
||||
- firewall counters и доказательство недоступности `8443` с запрещённого
|
||||
source;
|
||||
- traces/log search и результат redaction canary;
|
||||
- фактическое время переключения и rollback rehearsal;
|
||||
- approvals Safety Service, Rule Pack, Security, Product и Operations.
|
||||
|
||||
Только после успешного выполнения всех пунктов Message Safety cutover считается
|
||||
завершённым. Cutover `bitrix-sync` остаётся отдельным изменением по
|
||||
[`module-07-bitrix-sync.md`](../../../documentation/module-07-bitrix-sync.md).
|
||||
|
||||
## Политика отказов
|
||||
|
||||
- Отказ зависимости Safety — fail-closed: VM1 не должна отправлять/продвигать
|
||||
контент.
|
||||
- Устаревшие/недоступные сигнатуры ClamAV отключают только файловую
|
||||
capability; ошибка сканирования никогда не превращается в allow.
|
||||
- Потеря Redis может убрать ускорение, но PostgreSQL остаётся источником
|
||||
истины.
|
||||
- Сбой OTEL ставит в очередь в пределах ограниченного тома и не должен
|
||||
менять вердикты.
|
||||
- Rollback не понижает схемы, не удаляет durable tasks/mappings и не
|
||||
запускает `docker compose down -v`.
|
||||
|
||||
## Аварийный MOCK
|
||||
|
||||
Разрешены только эти пять sudo-команд:
|
||||
|
||||
```text
|
||||
han-message-safety-mode standard
|
||||
han-message-safety-mode mock --text-free true --file-free true
|
||||
han-message-safety-mode mock --text-free true --file-free false
|
||||
han-message-safety-mode mock --text-free false --file-free true
|
||||
han-message-safety-mode mock --text-free false --file-free false
|
||||
```
|
||||
|
||||
Хелпер атомарно пишет только
|
||||
`/etc/han-chat/message-safety-mode.env`, пересоздаёт только Safety API,
|
||||
проверяет health и при сбое восстанавливает предыдущий режим. У MOCK нет
|
||||
таймаута: держите high-severity alert активным до явного `standard`, затем
|
||||
проверьте нормальные text/link/file capabilities и EICAR-canary.
|
||||
|
||||
## Известные исключения по образам
|
||||
|
||||
Образы ClamAV могут потребовать корректировок UID/path после валидации
|
||||
точного digest. Не ослабляйте `read_only`, capabilities или mounts глобально:
|
||||
задокументируйте минимальные writable пути для сигнатур/runtime и
|
||||
компенсируйте сетевыми и ресурсными лимитами. Egress к signature-CDN
|
||||
получает только `freshclam`; `clamd` — нет.
|
||||
|
||||
Reference in New Issue
Block a user