247 lines
17 KiB
Markdown
247 lines
17 KiB
Markdown
# Инструкция по развертыванию HAN Chat в production-like окружении
|
||
|
||
Это исполняемый чек-лист для контура на одной виртуальной машине. PostgreSQL и S3
|
||
используются как внешние управляемые сервисы. Во время развертывания запрещено
|
||
использовать `docker compose down -v`, откат миграций Alembic и изменяемые теги образов.
|
||
|
||
Подробная пошаговая инструкция для первого запуска находится в
|
||
`deployment/DEPLOYMENT_GUIDE.ru.md`.
|
||
|
||
## Этап 0 — решения и зоны ответственности
|
||
|
||
- [ ] Зафиксированы SHA/дайджесты релиза, окно обслуживания, дежурный и ответственный за откат.
|
||
- [ ] Согласованы RPO/RTO; начальные цели: RPO PostgreSQL не более 15 минут и RTO не более 4 часов.
|
||
- [ ] Выбран удаленный OTLP-бэкенд либо принято ограничение на использование только отладочного контура.
|
||
- [ ] Явно приняты риски mock OTP, заглушки Safety и заглушки bitrix-sync.
|
||
|
||
## Этап 1 — VPC, DNS и группы безопасности
|
||
|
||
- [ ] Управляемый PostgreSQL имеет только приватную точку доступа и принимает трафик от группы безопасности VM.
|
||
- [ ] Из интернета доступны только TCP-порты VM 80/443; SSH ограничен VPN или CIDR администраторов.
|
||
- [ ] Порты 6379, 4317/4318, 8000, 8080 и 9000 закрыты для внешнего доступа.
|
||
- [ ] DNS-запись `A` для `PUBLIC_HOST` указывает на VM; исходящий HTTPS доступен.
|
||
|
||
## Этап 2 — защита виртуальной машины
|
||
|
||
На новой Ubuntu 24.04 можно выполнить подготовительный скрипт:
|
||
|
||
```sh
|
||
sudo deployment/scripts/setup-vm.sh
|
||
```
|
||
|
||
Перед включением `HARDEN_SSH=true` обязательно проверьте вход по ключу в отдельной
|
||
SSH-сессии. Параметры запуска и безопасные значения по умолчанию описаны в начале скрипта.
|
||
|
||
- [ ] Установлена Ubuntu 24.04; работают NTP, автоматические обновления безопасности и оповещения о заполнении диска.
|
||
- [ ] Вход учетной записью развертывания по ключу проверен во второй сессии; вход root и SSH по паролю отключены.
|
||
- [ ] Правила UFW/облачной группы безопасности и политика `DOCKER-USER` сохраняются после перезагрузки.
|
||
- [ ] Docker Engine и Compose поддерживают `include` и полную форму `env_file`.
|
||
|
||
## Этап 3 — управляемый PostgreSQL
|
||
|
||
- [ ] Включены ежедневные резервные копии, PITR, защита от удаления, шифрование и оповещения.
|
||
- [ ] CA-сертификат провайдера установлен по пути `PG_CA_HOST_PATH`; все DSN используют `verify-full`.
|
||
- [ ] Для схем `han_app`, `bitrix_local`, `bitrix_sync`, `message_safety`, `keycloak`
|
||
созданы отдельные роли миграций и выполнения; запрет лишних прав проверен тестами.
|
||
- [ ] Миграции проверены на пустой БД и на клоне БД предыдущего релиза.
|
||
|
||
## Этап 4 — Selectel S3
|
||
|
||
- [ ] Бакеты карантина, вложений и документов закрыты от публичного доступа и зашифрованы.
|
||
- [ ] Права API ограничены префиксами; учетные данные Safety имеют доступ к карантину только на чтение.
|
||
- [ ] CORS бакетов разрешает только точный HTTPS-origin браузера и необходимые заголовки PUT.
|
||
- [ ] Срок хранения карантина превышает время Safety polling/recovery; политика хранения данных согласована.
|
||
|
||
## Этап 5 — неизменяемый релиз
|
||
|
||
- [ ] Репозиторий переключен на утвержденный SHA в detached-режиме; рабочее дерево чистое.
|
||
- [ ] Образы сервисов неизменяемы и просканированы; нерешенных критических и высоких уязвимостей нет.
|
||
- [ ] Корневой `docker-compose.yml` является единственной точкой запуска.
|
||
|
||
## Этап 6 — окружение и секреты
|
||
|
||
```sh
|
||
umask 077
|
||
cp .env.example .env
|
||
chmod 600 .env
|
||
# Замените заглушки через защищенный редактор или менеджер секретов.
|
||
./scripts/validate-env .env
|
||
docker compose --env-file .env config --quiet
|
||
```
|
||
|
||
- [ ] Парные токены совпадают, PostgreSQL проверяет TLS, публичные URL используют HTTPS.
|
||
- [ ] Риск mock OTP принят; все секреты уникальны и содержат не менее 128 бит энтропии.
|
||
- [ ] Установлено `FRONTEND_DEV_PROXY_ENABLED=false`; таймауты Safety и nginx согласованы.
|
||
|
||
## Этап 7 — образы и статический frontend
|
||
|
||
```sh
|
||
docker compose --env-file .env pull
|
||
docker compose --env-file .env build --pull frontend-static nginx redis
|
||
docker compose --env-file .env run --rm frontend-static
|
||
```
|
||
|
||
- [ ] Экспорт frontend проверен и просканирован, затем скопирован сервисом `frontend-static` в именованный volume.
|
||
- [ ] Артефакты сборки не содержат секретов и непредусмотренных source map.
|
||
- [ ] На диске VM остается не менее 30% свободного места.
|
||
|
||
## Этап 8 — топология
|
||
|
||
```sh
|
||
docker compose --env-file .env config --services
|
||
python3 -m unittest discover -s tests -v
|
||
```
|
||
|
||
- [ ] Только nginx публикует `80:80` и `443:443`; сервиса PostgreSQL в Compose нет.
|
||
- [ ] Присутствуют volumes Redis AOF/RDB/ACL и постоянной очереди OTEL.
|
||
- [ ] Сети `backend` и `observability` являются внутренними.
|
||
|
||
## Этап 9 — первоначальная настройка ACME/TLS
|
||
|
||
Установите `NGINX_TLS_ENABLED=false` только для команды первоначального запуска:
|
||
|
||
```sh
|
||
NGINX_TLS_ENABLED=false docker compose --env-file .env up -d nginx
|
||
docker compose --profile certbot run --rm certbot certonly \
|
||
--webroot -w /var/www/certbot -d "$PUBLIC_HOST" \
|
||
--cert-name "$PUBLIC_HOST" --email "$ACME_EMAIL" \
|
||
--agree-tos --no-eff-email --non-interactive
|
||
docker compose --env-file .env up -d --force-recreate nginx
|
||
docker compose exec -T nginx nginx -t -c /tmp/nginx.conf
|
||
```
|
||
|
||
Сначала выполните проверку с параметром Certbot `--staging`. Установите systemd-таймер,
|
||
запускающий `deployment/scripts/ssl-renew.sh` дважды в сутки, и проверьте
|
||
`certbot renew --dry-run`. Включайте HSTS только после проверки цепочки сертификатов,
|
||
имени хоста, перенаправления и поддержки TLS 1.2/1.3.
|
||
|
||
## Этап 10 — миграции и начальные данные
|
||
|
||
Создайте у провайдера точку восстановления PITR, затем выполните:
|
||
|
||
```sh
|
||
PITR_MARKER_CONFIRMED=true deployment/scripts/migrate.sh
|
||
deployment/scripts/seed.sh
|
||
```
|
||
|
||
- [ ] Активны ожидаемые ревизии Alembic; runtime-пользователи не выполняли DDL.
|
||
- [ ] Повторный seed завершается успешно; обязательные настройки не содержат секретов.
|
||
- [ ] Схема остается обратно совместимой с образами предыдущего релиза.
|
||
|
||
## Этап 11 — Keycloak
|
||
|
||
```sh
|
||
docker compose up -d keycloak
|
||
docker compose ps keycloak
|
||
```
|
||
|
||
- [ ] Issuer discovery/JWKS точно совпадает с публичным HTTPS URL `/auth`.
|
||
- [ ] Frontend-клиент является публичным PKCE S256; implicit, password и social flows отключены.
|
||
- [ ] Неверный или повторно использованный OTP и превышение лимитов безопасно отклоняются; settings bridge работает fail-closed.
|
||
- [ ] При `KEYCLOAK_YANDEX_CAPTCHA_ENABLED=true` initial send и resend требуют свежий SmartCaptcha token; техническая недоступность Yandex подтверждена как fail-open в логах.
|
||
- [ ] CSP login-страницы содержит `smartcaptcha.cloud.yandex.ru`/`yastatic.net`, а `/auth/realms/master/protocol/openid-connect/3p-cookies/step2.html` и Admin Console работают без CAPTCHA CSP.
|
||
- [ ] Временный администратор удален либо его пароль изменен; для именного администратора включена MFA.
|
||
|
||
Если предыдущая попытка сохранила custom CSP в realm, сбросьте только это поле через `kcadm`; `.env` как shell-файл не загружать:
|
||
|
||
```sh
|
||
docker compose exec -T keycloak sh -lc '
|
||
set -eu
|
||
cfg=/tmp/han-kcadm.config
|
||
/opt/keycloak/bin/kcadm.sh config credentials --config "$cfg" \
|
||
--server http://127.0.0.1:8080/auth --realm master \
|
||
--user "$KC_BOOTSTRAP_ADMIN_USERNAME" \
|
||
--password "$KC_BOOTSTRAP_ADMIN_PASSWORD"
|
||
/opt/keycloak/bin/kcadm.sh update realms/han-chat --config "$cfg" \
|
||
-s "browserSecurityHeaders.contentSecurityPolicy="
|
||
rm -f "$cfg"
|
||
'
|
||
```
|
||
|
||
## Этап 12 — последовательный запуск и готовность
|
||
|
||
```sh
|
||
docker compose up -d redis
|
||
docker compose up -d keycloak otel-collector
|
||
docker compose up -d message-safety
|
||
docker compose up -d api-backend
|
||
docker compose up -d bitrix-local-app bitrix-sync
|
||
docker compose up -d nginx
|
||
docker compose ps
|
||
```
|
||
|
||
- [ ] Нет циклических перезапусков и OOM; критические readiness-проверки успешны.
|
||
- [ ] Сохраняется только документированная деградация: Bitrix не установлен и bitrix-sync работает как заглушка.
|
||
- [ ] Внешний запрос `/internal/*` возвращает 404; OTEL принимает телеметрию.
|
||
|
||
## Этап 13 — Bitrix24
|
||
|
||
- [ ] URL установки, обработчика и placement используют точные публичные HTTPS-пути.
|
||
- [ ] Коннектор `han_mobile_app` активен в Открытой линии 8; события привязаны однократно.
|
||
- [ ] OAuth зашифрован; callback-, application- и service-токены не попадают в логи.
|
||
- [ ] Исходящие сообщения и ответы оператора идемпотентны; внутренний статус не опубликован наружу.
|
||
|
||
## Этап 14 — smoke- и E2E-тесты
|
||
|
||
```sh
|
||
deployment/scripts/smoke.sh
|
||
```
|
||
|
||
- [ ] Успешны сценарии гостя, OTP/PKCE/bootstrap/session, обновления токена и выхода.
|
||
- [ ] Проверены Safety allow/deny/pending/timeout и один параллельный медленный poll.
|
||
- [ ] Проверены карантин, перенос и удаление файлов, скачивание только владельцем и аудит.
|
||
- [ ] Проверены переподключение WS с REST-сверкой, 404 при обращении к чужому ресурсу, идемпотентность и 429.
|
||
- [ ] Логи не содержат PII, текстов сообщений, токенов и query-параметров presigned URL.
|
||
|
||
## Этап 15 — наблюдаемость
|
||
|
||
- [ ] Известный request ID связывает трассировку nginx, API и downstream-сервисов; UX ID не используется как label.
|
||
- [ ] Все три сигнала поступают в выбранный бэкенд; SLO-запросы и оповещения проверены.
|
||
- [ ] При недоступности удаленного сервиса ограниченная постоянная очередь заполняется и опустошается без остановки бизнес-функций.
|
||
- [ ] Тестовые секреты и PII отсутствуют; проверены метрики перезапуска, потерь, отказов и очереди Collector.
|
||
|
||
Только для локальной приемки запустите отладочный Collector с удалением чувствительных данных:
|
||
`docker compose --profile observability-local up -d otel-collector-local`.
|
||
|
||
## Этап 16 — открытие трафика
|
||
|
||
- [ ] Этапы 0–15 подписаны; имеются свежие подтверждения backup/PITR и предыдущие образы.
|
||
- [ ] HSTS включен; дайджесты релиза, версии схем и realm зафиксированы.
|
||
- [ ] Активных инцидентов нет; дежурный и владелец продукта приняли ограничения заглушек.
|
||
- [ ] В течение 60 минут контролируются 5xx, auth, доставка, БД, Redis, OOM, очередь OTEL и Bitrix.
|
||
|
||
## Резервное копирование и восстановление
|
||
|
||
Основным механизмом являются backup/PITR провайдера. Дополнительный проверенный логический дамп:
|
||
|
||
```sh
|
||
PG_BACKUP_DSN='postgresql://...?...sslmode=verify-full&sslrootcert=...' \
|
||
deployment/scripts/backup.sh /opt/han-chat/backups
|
||
```
|
||
|
||
Ежеквартально восстанавливайте PostgreSQL и S3 в изолированной VPC, развертывайте те же
|
||
дайджесты образов, не направляйте туда production DNS и callbacks Bitrix, выполняйте
|
||
smoke-тесты и фиксируйте фактические RPO/RTO. Redis можно восстановить пустым:
|
||
его AOF/RDB не является резервной копией бизнес-данных.
|
||
|
||
## Откат
|
||
|
||
Откатывайтесь только на образы, совместимые с текущей схемой:
|
||
|
||
```sh
|
||
SCHEMA_BACKWARD_COMPATIBLE_CONFIRMED=true \
|
||
deployment/scripts/rollback.sh /secure/path/previous-release.env
|
||
ENV_FILE=/secure/path/previous-release.env deployment/scripts/smoke.sh
|
||
```
|
||
|
||
## Дополнение: rollout реальной SMS-авторизации
|
||
|
||
Текущий runbook остаётся mock-only, пока артефакты module-11 не реализованы. Для SMS release обязательны: schema/role `sms`, migrations/seed active approved `auth_otp`, `sms-service`/worker, exact callback route, парные service tokens, Direct `TOKEN_1`, согласованные sender/template, отдельные callback credentials, подтверждённый callback source IP и статический egress IP worker.
|
||
|
||
Порядок: App DB OTP seed → SMS schema/migrations/seed → test с mock Direct → production SMS deploy при `KEYCLOAK_OTP_MOCK_ENABLED=true` → Keycloak expand migration/SPI → provider smoke и callback/redaction evidence → real mode. Rollback: вернуть mock, не удалять journal/schema, остановить новые real orders и зафиксировать in-flight/`uncertain`; downgrade только при доказанной совместимости.
|
||
|
||
Никогда не выполняйте downgrade Alembic. После обратно несовместимой миграции используйте
|
||
исправление вперед либо согласованный PITR с восстановлением S3 и сверкой Bitrix во время
|
||
технического обслуживания. Всегда проверяйте outbox, inbox и recovery, чтобы сообщение
|
||
с неопределенным статусом не было отправлено повторно.
|