341 lines
26 KiB
Markdown
341 lines
26 KiB
Markdown
# arch-10. Контракт развёртывания
|
||
|
||
> Канонический контракт rollout для всех application VM. OS-роли, SSH/sudo, secrets delivery и hardening — [`arch-06-service-hosting-security.md`](arch-06-service-hosting-security.md); этот документ их не ослабляет.
|
||
> Процедуры конкретной машины — [`module-10-deployment-vm1.md`](../VM1_app/documentation/module-10-deployment-vm1.md) и [`module-10-deployment-vm2.md`](../VM2_services/documentation/module-10-deployment-vm2.md).
|
||
> Nginx TLS — [`arch-08-nginx.md`](arch-08-nginx.md). Redis — [`arch-09-redis.md`](arch-09-redis.md). Telemetry — [`arch-07-observability.md`](arch-07-observability.md). Compose — [`arch-03-docker-compose-blueprint.md`](arch-03-docker-compose-blueprint.md).
|
||
|
||
## Назначение
|
||
|
||
Документ фиксирует то, что **должно совпасть между ВМ1 и ВМ2** и то, что связывает их как систему: независимый deploy, VPC/SG, managed PG, S3, роли `deploy`/`admin`, секреты, TLS/ACME процедура, порядок cutover Safety, backup/rollback/DR.
|
||
|
||
Команды сервисов конкретной машины и её Compose **не** дублируются здесь. Агент репозитория VM читает этот контракт плюс свой runbook.
|
||
|
||
Прямые `docker compose` команды выполняются `admin` только при bootstrap/recovery либо инкапсулируются в утверждённые root-owned systemd-units. Они не являются основанием выдавать `deploy` доступ к Docker daemon. Значения в `<УГЛОВЫХ_СКОБКАХ>` — placeholders.
|
||
|
||
## 1. Неподвижные правила
|
||
|
||
1. Один root Compose project описывается в `<BACKEND_ROOT>` своей VM; в steady state его запускает root-owned systemd-unit/helper, а не пользователь из группы `docker`.
|
||
2. На каждой VM ровно один nginx; ВМ1 и ВМ2 имеют независимые public DNS/TLS ingress и deployment lifecycle.
|
||
3. Application containers не имеют public host ports. Nginx ВМ1 публикует свой `80/443`; nginx ВМ2 — отдельный `80/443` только для exact CRM webhook и private `8443` для Message Safety/internal access.
|
||
4. `/internal/*` не маршрутизируется публично.
|
||
5. Managed PostgreSQL находится вне Compose, в той же VPC, без public IP.
|
||
6. S3 — внешний Selectel-compatible storage; клиент получает только presigned URL.
|
||
7. Секреты не коммитятся, не вставляются в команды shell history и не выводятся в отчёты.
|
||
8. Миграции выполняются отдельными one-shot steps до новой версии приложения.
|
||
9. Message Safety запускается как documented stub до замены; это не production antivirus/moderation.
|
||
10. `bitrix-sync` вводится только после выполнения preflight/cutover gates module-07; до этого `BITRIX_SYNC_ENABLED=false`, public webhook закрыт на edge.
|
||
11. На ВМ1 и ВМ2 отдельные root Compose projects/systemd units; deploy/rollback выполняются независимо.
|
||
12. ВМ2 — самостоятельная service VM с минимальным public webhook ingress, allow-listed egress, отдельным IAM principal и service-specific secret files.
|
||
13. OS-роли, SSH/sudo, secrets delivery, container hardening и private-VM lockdown подчиняются arch-06.
|
||
|
||
## 2. Роли и обозначения
|
||
|
||
- **Cloud admin**: VPC, VM, PG, S3, DNS/security groups.
|
||
- **Deploy operator / OS user `deploy`**: запуск утверждённых release/rollback/migration systemd-units; без группы `docker`, записи в production compose/unit/scripts/config и общего sudo.
|
||
- **Break-glass OS user `admin`**: bootstrap и аварийное восстановление; не используется для штатного деплоя.
|
||
- **OS user `tunnel`**: только allow-listed local TCP forwarding к private endpoints; без sudo/shell operations.
|
||
- **Bitrix admin**: local app, connector, Open Line 8, callbacks.
|
||
- **Security owner**: secrets, Keycloak admin MFA, firewall, retention.
|
||
- **Safety Service Owner**: API/data contract, capacity result и v2 cutover/rollback sign-off.
|
||
- **Rule Pack Owner**: rules bundle, corpus, monitor report и version release.
|
||
- **Product Owner**: mnemonic `safety.chat.blocked` и business acceptance chat flow.
|
||
- **Operations Owner**: VM2 alerts, ClamAV signatures, incident/reprovision/restore rehearsal.
|
||
|
||
```text
|
||
<PUBLIC_HOST> например chat.example.ru
|
||
<VM_PUBLIC_IP> публичный IPv4 ВМ1
|
||
<PROCESSING_PUBLIC_HOST> отдельный public host ВМ2, например processing.example.ru
|
||
<VM2_PUBLIC_IP> публичный IPv4/LB address ВМ2
|
||
<VM_PRIVATE_IP> приватный IPv4 VM
|
||
<VPC_CIDR> например 10.20.0.0/24
|
||
<PG_PRIVATE_HOST> private FQDN/IP managed PG
|
||
<PG_PORT> 5432 или 6432
|
||
<PG_DATABASE> han_chat
|
||
<BACKEND_REPO_URL> URL репозитория этой VM
|
||
<BACKEND_ROOT> /opt/han-chat/backend
|
||
<RELEASE> immutable tag/git SHA
|
||
<ACME_EMAIL> адрес ops, не placeholder в реальном запуске
|
||
<BITRIX_PORTAL> разрешённый портал
|
||
<IDGTL_SENDER_NAME> согласованное в Direct имя отправителя
|
||
<IDGTL_STATIC_EGRESS_IP> фактический статический egress IP `sms-worker`
|
||
<IDGTL_TEST_PHONE> контролируемый номер для provider smoke
|
||
```
|
||
|
||
`<BACKEND_ROOT>` и `<BACKEND_REPO_URL>` **разные** у ВМ1 и ВМ2.
|
||
|
||
## 3. Stage 0 — решения до provisioning
|
||
|
||
Зафиксировать: region/AZ и VPC; hostnames и TTL DNS; VM image Ubuntu 24.04 LTS; sizing каждой VM; PG plan/storage/backups/PITR; S3 region/endpoint/bucket names; container registry и immutable image tags/digests; remote observability backend; RPO/RTO и maintenance window; ответственных за alerts/Bitrix/Keycloak; Safety Service/Rule Pack/Product/Security/Operations owners и approvals cutover.
|
||
|
||
Sizing и load gates конкретной машины — профильный runbook. Monthly availability SLO для MVP не задаётся; это не отменяет latency/load gates и alerts.
|
||
|
||
### Gate 0
|
||
|
||
- [ ] Владельцы и maintenance window назначены.
|
||
- [ ] RPO/RTO приняты хотя бы временно: ориентир RPO PG ≤15 минут/PITR, RTO ≤4 часа.
|
||
- [ ] Решено: images pull из registry или build на VM.
|
||
- [ ] Remote telemetry backend выбран либо явно принят ограниченный debug-only режим.
|
||
- [ ] Риск mock OTP до SMS cutover и Safety stub письменно принят; real SMS не включается без gates module-11.
|
||
|
||
**Ожидаемый результат:** есть release checklist с конкретными values; не создано ни одной публичной БД/Redis.
|
||
|
||
## 4. Stage 1 — VPC, DNS и security groups
|
||
|
||
Создать private subnet для ВМ1, ВМ2, SigNoz и managed PG. ВМ1 и ВМ2 имеют отдельные public IP/LB только для своих nginx; service-to-service и PostgreSQL traffic остаётся private. SSH к обеим VM — только ops VPN/bastion.
|
||
|
||
| Source | Destination | Port | Rule |
|
||
|---|---|---:|---|
|
||
| trusted ops CIDR/VPN | ВМ1, ВМ2 | SSH `<SSH_PORT>` | allow |
|
||
| internet | ВМ1 | TCP 80/443 | allow edge redirect/ACME/application |
|
||
| internet | nginx ВМ2 | TCP 80/443 | allow ACME/redirect + exact CRM webhook |
|
||
| ВМ1 SG | ВМ2 | TCP 8443 | private TLS only |
|
||
| ВМ1/ВМ2 service SG | managed PG | `<PG_PORT>` | allow по нужным DB roles |
|
||
| ВМ2 collector | private SigNoz | TCP 4317 | allow |
|
||
| ВМ2 workers | S3 endpoints | TCP 443 | allow |
|
||
| ВМ2 `bitrix-sync` | approved Bitrix portal | TCP 443 | allow |
|
||
| ВМ2 `freshclam` | approved signature CDN | TCP 443/80 по vendor manifest | allow |
|
||
| ВМ2 | trusted DNS/NTP | UDP/TCP 53, UDP 123 | allow |
|
||
| internet | managed PG | any | deny |
|
||
| internet | ВМ2 | any кроме nginx 80/443 | deny ingress |
|
||
| internet | обе VM | 6379, 4317, 4318, 8000, 8080, 8443, 9000 | deny public |
|
||
|
||
ВМ2 использует default-deny egress. Registry/OS repositories открываются только в bootstrap/controlled window и затем снова закрываются. Если provider SG не умеет destination allow-list, применяется host firewall/proxy/NAT policy; постоянный open egress для ВМ2 не является допустимым production состоянием.
|
||
|
||
DNS: `A <PUBLIC_HOST> → <VM1_PUBLIC_IP>`, `A <PROCESSING_PUBLIC_HOST> → <VM2_PUBLIC_IP>`, private DNS `processing.internal → <VM2_PRIVATE_IP>`. Public host ВМ2 используется только CRM webhook; private name не публикуется во внешнем DNS.
|
||
|
||
### Gate 1
|
||
|
||
- [ ] PG не имеет public endpoint.
|
||
- [ ] SSH доступен только trusted source.
|
||
- [ ] Снаружи открыты только 80/443/ограниченный SSH.
|
||
- [ ] DNS стабильно разрешается с нескольких resolver.
|
||
- [ ] Каждая VM достигает private PG и своих внешних HTTPS endpoints.
|
||
|
||
**Ожидаемый результат:** `nc -vz <PG_PRIVATE_HOST> <PG_PORT>` с VM успешен; с внешней машины PG недоступен.
|
||
|
||
## 5. Stage 2 — hardening Ubuntu
|
||
|
||
Процедура первичная для **каждой** application VM. Скрипт-прототип [`../../HAN_chat/deploy/setup-vm-han-chat.sh`](../../HAN_chat/deploy/setup-vm-han-chat.sh) полезен для UFW, fail2ban, Docker и `DOCKER-USER`. Перед production: review версии; не передавать IP/ключи в git; проверить unattended upgrades; `deploy` не в группе `docker`; `AllowTcpForwarding no` по умолчанию; отдельный `tunnel` при необходимости; root-owned systemd-units и `/etc/sudoers.d/deploy` без wildcard.
|
||
|
||
`PUBLIC_DOCKER_PORTS` задаёт профильный runbook (ВМ1: `80,443`; ВМ2 — свои public 80/443, private 8443 не internet).
|
||
|
||
Проверки: `sshd -t`, UFW, fail2ban, Docker/Compose versions, `iptables -L HAN-CHAT-DOCKER`, timedatectl, disk/swap. Второй SSH session как `deploy`, затем отключить root/password login.
|
||
|
||
### Gate 2
|
||
|
||
- [ ] SSH key login `deploy` проверен во втором сеансе.
|
||
- [ ] Root/password auth выключены.
|
||
- [ ] `deploy` не состоит в группе `docker`; `sudo -l` содержит только утверждённые конкретные systemd-команды.
|
||
- [ ] Production compose, units, deploy scripts и secret mappings принадлежат root и недоступны `deploy` на запись.
|
||
- [ ] UFW и DOCKER-USER активны после restart Docker.
|
||
- [ ] Для published Docker ports allow rules сопоставляют original host destination через `conntrack --ctorigdstport`; positive/negative probes увеличивают counters нужных allow/deny rules после restart Docker и reboot.
|
||
- [ ] После обновления firewall helper active `oneshot RemainAfterExit` unit явно перезапущен; `enable --now` не считается применением новой версии.
|
||
- [ ] Docker Engine/Compose plugin закреплены поддерживаемой версией.
|
||
- [ ] NTP active; disk/swap соответствуют sizing.
|
||
- [ ] Break-glass процедура сохранена вне VM.
|
||
|
||
**Ожидаемый результат:** reboot VM не теряет SSH, firewall и Docker service.
|
||
|
||
### 5.1. Lockdown private/no-egress VM
|
||
|
||
Для SigNoz и другой VM, которая после раскатки не должна иметь internet ingress/egress, bootstrap выполняется по lifecycle arch-06. Checklist закрытия public IP/SSH/egress и запрет постоянного open egress — arch-06; повторное открытие только break-glass с повтором lockdown.
|
||
|
||
## 6. Stage 3 — managed PostgreSQL
|
||
|
||
До создания схем включить daily backup, PITR, encryption at rest, TLS `sslmode=verify-full` + provider CA, alerts (disk/connections/CPU/IO/replication/backup/CA), deletion protection.
|
||
|
||
CA: `/opt/han-chat/secrets/pg/ca.pem`, `root:deploy` `0440` (либо `0400`). Режимы `disable`/`allow`/`prefer`/`require` без проверки CA для production запрещены.
|
||
|
||
Публичные HTTPS-сертификаты `<PUBLIC_HOST>` и `<PROCESSING_PUBLIC_HOST>` выпускаются отдельно через Let's Encrypt на Stage 9 nginx соответствующей VM, не в PostgreSQL.
|
||
|
||
Целевая модель ролей: admin/bootstrap; migration role каждого schema с DDL; runtime без DDL. Прототип `init-managed-postgres.py` слишком широк для production runtime.
|
||
|
||
Шесть schemas: `han_app`, `bitrix_local`, `bitrix_sync`, `keycloak`, `message_safety`, `sms`. Schema owner = migration role; runtime: `USAGE`, DML и sequence grants только на свои objects; `bitrix_sync_user` — только grants module-07 §13.
|
||
|
||
Ownership миграций:
|
||
|
||
1. `api-backend` Alembic — `han_app`;
|
||
2. `bitrix-local-app` — `bitrix_local`;
|
||
3. `message-safety` stub не создаёт PG tables до production implementation;
|
||
4. `bitrix-sync` — schema `bitrix_sync`; api-backend отдельно мигрирует shared `han_app.sync_queue`;
|
||
5. Keycloak — standard tables; custom provider — свои migrations;
|
||
6. `sms-service` — schema `sms`; runtime `sms_user` без доступа к `han_app`/`keycloak`.
|
||
|
||
Только expand/migrate/contract. Destructive migration — отдельный backup, approval и release. Downgrade data migrations не обещается.
|
||
|
||
### Gate 3
|
||
|
||
- [ ] Backups/PITR/TLS/deletion protection включены.
|
||
- [ ] Шесть schemas/roles созданы, включая `sms`/`sms_user`.
|
||
- [ ] Runtime roles не имеют DDL/чужого доступа.
|
||
- [ ] Migration credentials отделены от runtime.
|
||
- [ ] Empty/previous-version migration test успешен.
|
||
- [ ] PITR restore point создан перед первым release.
|
||
|
||
## 7. Stage 4 — S3
|
||
|
||
Три приватных bucket: `<PREFIX>-quarantine`, `<PREFIX>-attachments`, `<PREFIX>-documents`. Public ACL/listing выключены. Versioning для data buckets по policy; SSE включить.
|
||
|
||
IAM: API role — exact prefixes, presign PUT quarantine, Head/copy/delete quarantine, write/read data; Safety role — **read-only quarantine**; backup/ops отдельно; frontend — никаких permanent credentials. Отдельный IAM principal ВМ2.
|
||
|
||
CORS quarantine: `AllowedOrigins` только `https://<PUBLIC_HOST>`; PUT; headers `Content-Type`, `If-None-Match`, checksum; не `*` origin с credentials.
|
||
|
||
Lifecycle: quarantine failed/orphan expire 48 ч только при отсутствии active `safety_tasks`; incomplete multipart abort 1 день; attachments/documents без auto-delete до legal retention.
|
||
|
||
### Gate 4
|
||
|
||
- [ ] Все buckets private.
|
||
- [ ] API key не может list/write вне exact scope.
|
||
- [ ] Safety key не может write/delete.
|
||
- [ ] Browser test origin выполняет presigned PUT с checksum и `If-None-Match: *`; повтор того же key получает `412`.
|
||
- [ ] Complete фиксирует authoritative `version_id`, ETag и checksum; Safety читает только эту version.
|
||
- [ ] Wrong version/ETag и изменённый source дают deny/error и не promote-ятся.
|
||
- [ ] Conditional promote mismatch не создаёт delivery outbox/Bitrix call.
|
||
- [ ] Quarantine lifecycle не удалит active `safety_tasks`.
|
||
- [ ] Data lifecycle соответствует retention.
|
||
|
||
## 8. Общий layout релиза и секретов
|
||
|
||
На каждой VM:
|
||
|
||
```text
|
||
/opt/han-chat/
|
||
backend/ # checkout текущего release
|
||
releases/<RELEASE>/ # optional immutable release dirs
|
||
secrets/ # не в git
|
||
backups/ # только metadata/short-lived encrypted artifacts
|
||
```
|
||
|
||
Рекомендуемый rollout — immutable images из registry. Deploy из mutable branch без recorded SHA запрещён. `latest` отсутствует.
|
||
|
||
`.env` — только несекретный config и `SECRETS_SOURCE=file|selectel`. Секреты выдаёт `deployment/secrets/han-secrets`. `docker compose config` может раскрыть secrets; stdout не публиковать.
|
||
|
||
Validation: нет `change-me`, paired tokens equal, PG TLS, public HTTPS, `FRONTEND_DEV_PROXY_ENABLED=false` на production-like.
|
||
|
||
Состав `.env`/secret groups — профильный runbook.
|
||
|
||
## 9. TLS/ACME процедура
|
||
|
||
Webroot two-phase, независимо в root Compose каждой VM, без `compose down`. Staging CA rehearsal, затем production `--cert-name` текущего host. Сертификат и ACME volume между VM не разделяются.
|
||
|
||
Renew: systemd timer дважды в сутки. Скрипт `<BACKEND_ROOT>/deploy/ssl-renew.sh`:
|
||
|
||
1. взять `flock`;
|
||
2. `docker compose --profile certbot run --rm certbot renew --webroot -w /var/www/certbot --quiet`;
|
||
3. при обновлении проверить `docker compose exec -T nginx nginx -t -c /tmp/nginx.conf`;
|
||
4. только после успеха `docker compose kill -s HUP nginx`;
|
||
5. записать результат и метрику expiry;
|
||
6. ненулевой exit при ошибке;
|
||
7. не удалять действующий сертификат;
|
||
8. success path — `0` и пустой stderr.
|
||
|
||
Пример unit `/etc/systemd/system/han-chat-cert-renew.service`:
|
||
|
||
```ini
|
||
[Unit]
|
||
Description=Renew HAN Chat Let's Encrypt certificate
|
||
Requires=docker.service
|
||
After=docker.service network-online.target
|
||
|
||
[Service]
|
||
Type=oneshot
|
||
User=deploy
|
||
WorkingDirectory=<BACKEND_ROOT>
|
||
ExecStart=<BACKEND_ROOT>/deploy/ssl-renew.sh
|
||
```
|
||
|
||
Timer `OnCalendar=*-*-* 03,15:20:00`, `RandomizedDelaySec=30m`, `Persistent=true`. `enable --now`, `list-timers`, `certbot renew --dry-run`. Alert <21 дней, page <7 дней. Ошибка renew не останавливает nginx.
|
||
|
||
Staging issuance, затем production `--cert-name` текущего host. Host для ВМ1 — `<PUBLIC_HOST>`; для ВМ2 — `<PROCESSING_PUBLIC_HOST>`; private `8443` — internal CA, не Let's Encrypt. Сертификат и ACME volume между VM не разделяются.
|
||
|
||
## 10. Сквозной порядок startup и cutover
|
||
|
||
1. На ВМ2 unit поднимает Redis Safety и local Collector.
|
||
2. Затем `clamd`/`freshclam`, Safety API/worker и `bitrix-sync`.
|
||
3. Последним на ВМ2 — nginx public `80/443` и private `8443`.
|
||
4. На ВМ1 — Redis/Collector, API, SMS, Keycloak, local app, edge nginx.
|
||
5. Только private `MESSAGE_SAFETY_URL` ВМ1 переключается на ВМ2 после Safety gates. Public CRM webhook DNS/routes ВМ2 не требуют изменения ВМ1.
|
||
|
||
Legacy single-VM `docker compose up` не является evidence готовности target ВМ2. Один `message_id` нельзя одновременно отправлять в v1 и v2. После cutover ВМ1 не содержит local Safety/Redis DB2.
|
||
|
||
При потере ВМ2 fail-open запрещён. Reprovision ВМ2 из immutable image/config; Redis пустой; gates повторяются. RTO ≤4 ч; restore rehearsal минимум дважды в год.
|
||
|
||
## 11. Observability, opening traffic, backup, rollback
|
||
|
||
Gate 5–14 не дублируются в этом общем контракте: это профильные release gates конкретной VM, описанные в `module-10-deployment-vm1.md` / `module-10-deployment-vm2.md` и executable runbook соответствующего репозитория. Нумерация внутри VM2 runbook локальна его технической приёмке; системное открытие трафика всегда требует подписанных результатов обоих контуров.
|
||
|
||
**Gate 15 — observability:** arch-07 и профильный module-09 VM spec; сквозной `request_id` через nginx ВМ1 → API → Safety ВМ2 обязателен до объявления production-ready.
|
||
|
||
**Gate 16 — opening traffic:** снять maintenance, включить HSTS после TLS test, сохранить digests/revisions, restore point и on-call, затем наблюдать 60 минут. До открытия должны быть подписаны Gate 0–4 этого документа, применимые Gate 5–14 профильных runbook обеих VM и Gate 15.
|
||
|
||
Backup: PG daily+PITR — business restore; S3 versioning; Redis не business backup; Keycloak в PG. Restore rehearsal в isolated VPC без production DNS/Bitrix callbacks.
|
||
|
||
Rollback приложения: previous immutable digests, без Alembic downgrade, `SCHEMA_BACKWARD_COMPATIBLE_CONFIRMED=true`. Backward-incompatible migration — только forward-fix или PITR. TLS: оставить старый config/cert при failure.
|
||
|
||
Запрещены: `docker compose down -v`, `docker system prune -a --volumes`, `DROP DATABASE` / `DROP SCHEMA`, recursive S3 delete, `certbot delete` active cert, unbounded logs, Redis `KEYS/FLUSH*`, ad-hoc DB DELETE.
|
||
|
||
Routine (автомат ежедневно): health/synthetics, PG backup/PITR, TLS expiry, disk/OTEL queue, Redis AOF/memory, DLQ/quarantine age. Еженедельно: image CVE, login/rate-limit trend, S3 inventory. Ежемесячно: OS patch, secret review, capacity, runbook drill.
|
||
|
||
```bash
|
||
cd <BACKEND_ROOT>
|
||
docker compose ps
|
||
docker compose logs --since=15m <SERVICE>
|
||
docker stats --no-stream
|
||
docker system df
|
||
docker compose exec -T nginx nginx -t
|
||
```
|
||
|
||
Incident triage:
|
||
|
||
```bash
|
||
cd <BACKEND_ROOT>
|
||
date -Is
|
||
docker compose ps
|
||
docker stats --no-stream
|
||
docker compose logs --since=10m --tail=500 <SERVICE>
|
||
df -h
|
||
free -h
|
||
sudo ss -lntp
|
||
sudo iptables -L HAN-CHAT-DOCKER -n -v
|
||
```
|
||
|
||
PG: readonly `select now(), count(*) from pg_stat_activity`. Redis — только ops ACL `PING`. Secret literal не вставлять в ticket. Не replay message/DLQ до idempotency и ambiguous Bitrix outcome.
|
||
|
||
Типовые сценарии: API 503 — DB/Redis/JWKS/Safety circuits; send timeout — checkpoint, не новый key; Bitrix down — OAuth/circuit/DLQ; Redis loss — clean restart + polling; PG outage — не restart storm; disk full — known cache/old images после inventory; cert expiry — webroot/staging; secret leak — rotate, telemetry deletion.
|
||
|
||
Upgrades: notes → compatibility → PITR → staging → expand migration → one service at a time → E2E → contract later. Keycloak не пропускать unsupported majors.
|
||
|
||
DR потеря VM: новая Ubuntu в VPC, hardening, DNS, secrets из vault не со старого disk, exact images, Redis можно clean, existing PG/S3, TLS, ordered startup. Потеря PG: PITR в new instance, остановить writes, reconcile S3 orphans. Потеря S3: без versioning полное восстановление невозможно; отключить file ops. Compromise: isolate, forensic snapshot, rotate all, clean deploy, notify.
|
||
|
||
Перед teardown: inventory без secrets, revoke Bitrix/credentials, legal hold, DNS drain, deletion protection — отдельное approval, shared VPC/PG/S3 проверить.
|
||
|
||
## 12. Общий Definition of Done
|
||
|
||
- VM/VPC/DNS/SG/hardening соответствуют Gate 1–2;
|
||
- managed PG private/TLS/backups/least privilege/migrations работают;
|
||
- S3 private/IAM/CORS/lifecycle проверены;
|
||
- `deploy` не имеет Docker/root-equivalent доступа;
|
||
- независимые public 80/443; ВМ2 дополнительно private 8443;
|
||
- после Safety cutover ВМ1 вызывает ВМ2 только по private HTTPS с проверенным CA bind;
|
||
- container hardening — arch-06;
|
||
- для каждой private/no-egress VM завершён lockdown;
|
||
- backup restore и rollback rehearsed;
|
||
- ops/incident/upgrade/DR owners назначены;
|
||
- все assumptions/TBD приняты до открытия traffic.
|
||
|
||
Профильный DoD VM дополняет свои сервисы, Compose и cutover steps.
|
||
|
||
## 13. Допущения, TBD и конфликты
|
||
|
||
**Допущения:** D-A1 отдельные public hosts; D-A2 обязательный минимум — local Collector; D-A3 managed PG private/TLS/PITR; D-A4 Bitrix portal/connector/line — значения architecture; D-A5 mock OTP до SMS cutover как documented risk.
|
||
|
||
**TBD:** D-TBD1 domains/Expo redirect/Bitrix frame ancestors; D-TBD2 final VM1/PG sizing, public SLO, RPO/RTO; D-TBD3 legal retention; D-TBD4 secret manager; D-TBD5 Safety v2 cutover; D-TBD6 bitrix-sync cutover; D-TBD7 pinned versions; D-TBD8 exact CLI после реализации; D-TBD9 Keycloak admin VPN/MFA; D-TBD10 CSP/CORS/IAM; D-TBD11 SigNoz auth/retention/alert route.
|
||
|
||
**Конфликты:** module-07 documentation ≠ cutover; v1 stub ≠ production Safety; prototype PG init слишком широк; prototype TLS downtime; prototype `/bitrix-internal/*` запрещён; Compose/env могут ещё не содержать VM2/SMS artifacts.
|
||
|
||
## 14. Ссылки
|
||
|
||
- ВМ1: [`module-10-deployment-vm1.md`](../VM1_app/documentation/module-10-deployment-vm1.md).
|
||
- ВМ2: [`module-10-deployment-vm2.md`](../VM2_services/documentation/module-10-deployment-vm2.md).
|
||
- Прототипы: [`../../HAN_chat/Deploy_steps.md`](../../HAN_chat/Deploy_steps.md), [`../../HAN_chat/deploy/setup-vm-han-chat.sh`](../../HAN_chat/deploy/setup-vm-han-chat.sh), [`../../HAN_chat/deploy/init-managed-postgres.py`](../../HAN_chat/deploy/init-managed-postgres.py).
|