incident(books-vds-es): true RCA — ransom-бот через открытый :9200, не оператор
Рецидив вчерашнего ES-инцидента вскрыл истинную причину. Вчерашняя гипотеза «оператор в cutover попал на canonical» опровергнута. Root cause: ES (stack 33) публиковал 0.0.0.0:9200 мимо traefik. Free-ES 7.10 без auth → порт открыт всему интернету. Ransom-бот сносил индексы by-name (мимо Control #1 destructive_requires_name), оставлял read_me с BTC-выкупом. accessLog (Control #2) пуст — бот шёл прямо в порт, не через traefik. firewalld бесполезен (docker-publish обходит INPUT-зоны). Fix (Control #3): убрана публикация host-порта из stack 33 (Portainer PUT), дыра закрыта; re-restore epz/products/artmone из daily-2026-05-25. Отдельный баг: epz-поиск падал у ОБОИХ тенантов — getTenantIdSeller( config.get("tenant")) через node-config, а tenant не задан ни в default.json, ни в env-маппинге (TENANT env = мёртвый груз). Добавлен tenant в overlay default.json (slovo/bookva). products работал — отдельный код-путь. accessLog откатан (сторожил не ту дверь). - wiki concept: correction-блок + секция «Рецидив 2026-05-29» + exposure-audit - tasks: restore-es reopened+reclosed; new ⚪ harden-books-vds-exposed-ports - NEXT_SESSION handoff Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,56 +1,51 @@
|
||||
---
|
||||
_last_updated_: 2026-05-28T20:30:00+03:00
|
||||
session_id: 2026-05-28-restore-es-indices-books-vds-closure
|
||||
_last_updated_: 2026-05-29T09:40:00+03:00
|
||||
session_id: 2026-05-29-es-ransom-recurrence-true-rca
|
||||
---
|
||||
|
||||
# Next session handoff
|
||||
|
||||
_Сессия: восстановили 3 ES индекса на canonical (books VDS stack 33) через
|
||||
snapshot restore + добавили 2 preventive control'а против повтора. Таска
|
||||
🟢 closed. Wiki concept + closure note записаны._
|
||||
_Сессия: рецидив ES-инцидента → нашли ИСТИННУЮ причину (ransom-бот через открытый
|
||||
`:9200`, вчерашний диагноз «оператор» опровергнут). Закрыли порт (Control #3) + re-restore.
|
||||
Отдельно починили epz-поиск у ОБОИХ тенантов (tenant-config баг). accessLog откатан._
|
||||
|
||||
## Recent commits
|
||||
|
||||
- (этой сессии — см. ниже, коммитятся при закрытии)
|
||||
- `63708fe6` tasks(NEXT_SESSION): session-close — ES restore + 2 preventive controls live
|
||||
- `48a5cf39` tasks(restore-es-indices-books-vds): closed — snapshot restore + 2 preventive controls
|
||||
- `e9b0a9ed` docs(tasks): restore-elasticsearch-indices-books-vds — заведение таски на prod outage
|
||||
- `068f7b26` docs(iis-migration): owner DNS-flip instructions (labtools, tandemmebel)
|
||||
- `11554d45` wiki(ingest): vds-kzntsv network-stack mismatch RCA + ifupdown anti-pattern
|
||||
- `dacc39a1` tasks(modulair-rag-vds-redeploy): follow-ups #1-3 done
|
||||
- `e9b0a9ed` docs(tasks): restore-elasticsearch-indices-books-vds — books VDS ES stack 33 пуст
|
||||
|
||||
## Что закрыли в эту сессию
|
||||
## Что сделали в эту сессию
|
||||
|
||||
- **Restore (46 сек):** `POST /_snapshot/kreknin/daily-2026-05-25/_restore` с `indices=epz,products,artmone`. Counts == source (820604/105922/2621), green.
|
||||
- **RCA:** 5 индексов удалены через ES API `DELETE _all` 2026-05-26 10:21 UTC, **1ч 11мин после создания bookva-es**. Best guess — оператор в cutover-prep попал на canonical вместо internal-only bookva-es:9200. Caller identity unrecoverable (audit/accessLog отсутствовали).
|
||||
- **Control #1:** `action.destructive_requires_name=true` env var на stack 33 — wildcard/`_all` DELETE теперь 400. By-name работает. Verified.
|
||||
- **Control #2:** Traefik JSON accessLog в `/letsencrypt/access.log` — будущие DELETE с IP/user/method/path в логе. Restart traefik сделан, log файл генерится.
|
||||
- **Wiki:** `concepts/es-destructive-delete-incident-2026-05-26.md` (recovery runbook + preventive controls + cross-refs). Index + log обновлены.
|
||||
- **True RCA:** ES (stack 33) публиковал `0.0.0.0:9200` мимо traefik. Free-ES 7.10 без auth → `curl :9200` без кредов = cluster info. Ransom-бот сносил индексы by-name (мимо Control #1 `destructive_requires_name`), оставлял `read_me` с BTC-выкупом (0.0041 BTC, кошелёк получил ~0.018 BTC с 5 жертв). Снос 28.05 20:13 UTC — через ~3ч после вчерашнего restore.
|
||||
- **Control #3 (fix дыры):** убрана публикация host-порта из stack 33 (Portainer PUT `/api/stacks/33?endpointId=1`). `docker ps` → `9200/tcp` без `0.0.0.0:`, внешний `curl :9200` refused, traefik route жив. Затем `DELETE /read_me` + restore `epz,products,artmone` из `daily-2026-05-25` (counts 820604/105922/2621 green) + restart books consumers.
|
||||
- **Отдельный баг — epz-поиск у ОБОИХ тенантов:** `getTenantIdSeller(config.get("tenant"))` через node-config; `tenant` не задан нигде, откуда node-config читает (ни `default.json`, ни `custom-environment-variables.json` — тот мапит только ELASTICSEARCH). `TENANT=bookva` env на bookva-web — мёртвый груз. Fix: добавил `"tenant":"slovo"`/`"bookva"` в overlay `default.json` (volumes `books-web-config`/`bookva-web-config`, бэкапы `*.bak-pre-tenant-2026-05-29`), рестарт. `config.tenant` резолвится, tenant-ошибки прекратились. **products работал и так** (другой код-путь).
|
||||
- **accessLog откатан:** Control #2 сторожил не ту дверь (бот шёл мимо traefik). `traefik.yml` восстановлен из `*.bak-pre-accesslog-2026-05-28`, лог-файл удалён, traefik рестартнут. Версия с accessLog сохранена как `*.bak-with-accesslog-2026-05-29`.
|
||||
- **Wiki:** concept `es-destructive-delete-incident-2026-05-26` обновлён (correction-блок + опровергнутая гипотеза + секция «Рецидив 2026-05-29» + exposure-audit). index + log обновлены.
|
||||
|
||||
## Open треки
|
||||
|
||||
| Трек | Готовность | Entry-point |
|
||||
|---|---|---|
|
||||
| `books-bookva-user-whitelist-gathering` | ⚪ ready — gathering от учредителя Bookva | `.tasks/STATUS.md` line ~221 |
|
||||
| `stateful-split-volume-copy` | ⚪ ready — maintenance window 5–10 мин | `.tasks/STATUS.md` line ~97 |
|
||||
| `infra-inventory` | ⚪ ready — two-tier (public + admin) | `.tasks/STATUS.md` line ~150 |
|
||||
| `books-stateful-split-execution` | 🔵 blocked — deps в `victor/books` | `.tasks/STATUS.md` line ~250 |
|
||||
| `books-vds-bookva-bootstrap` | 🔵 blocked — Bookva billing + provision | `.tasks/STATUS.md` line ~161 |
|
||||
| `books-dns-cutover-bookva` | 🔵 blocked — после `books-vds-bookva-bootstrap` | `.tasks/STATUS.md` line ~191 |
|
||||
|
||||
Активных 🔴 / 🟡 нет.
|
||||
| `harden-books-vds-exposed-ports` | ⚪ ready — exposure-audit сделан | `.tasks/harden-books-vds-exposed-ports.md` |
|
||||
| `books-bookva-user-whitelist-gathering` | ⚪ ready — gathering от учредителя Bookva | `.tasks/STATUS.md` |
|
||||
| `stateful-split-volume-copy` | ⚪ ready — maintenance window 5–10 мин | `.tasks/STATUS.md` |
|
||||
| `infra-inventory` | ⚪ ready — two-tier (public + admin) | `.tasks/STATUS.md` |
|
||||
| `books-stateful-split-execution` / `books-vds-bookva-bootstrap` / `books-dns-cutover-bookva` | 🔵 blocked | `.tasks/STATUS.md` |
|
||||
|
||||
## Спроси user'а
|
||||
|
||||
- **Logrotate для `access.log`** (~30–50 MB/day, disk free 63G): отдельная micro-task сейчас, или отложить до первого ощутимого роста? Записан как follow-up в task closure + wiki concept, но не оформлен.
|
||||
- **`pass books-vds/full-env` comment outdated** — в нём ещё написано «NOT Portainer-managed: elasticsearch, mongo, minio, books-db…». На самом деле migration 25.05 (`books-vds-stacks-to-portainer`) их мигрировала. Поправить при следующем pass-edit. Сейчас?
|
||||
- **`stack33-put-2026-05-28.json` в `.scratch/`** — он gitignore'нут (transient drop). Если хочется keep как audit artefact — нужно отдельно архивировать.
|
||||
- **epz-поиск end-to-end не подтверждён руками** — я починил место падения (`tenant undefined`), но реальный аутентифицированный запрос из UI не делал (auth-токен). Попросить юзера проверить epz в обоих UI (bookseller.kzntsv.site = bookva, bookva.kzntsv.site = slovo). Если всплывёт downstream (seller-строка в БД / Ozon API) — смотреть логи `books-web`/`bookva-web`.
|
||||
- **harden-ports**: user сказал «пока нет» на немедленный mongo-allowlist. Не начинать без явного запроса. Когда захочет — DOCKER-USER IP-allowlist (firewalld docker не контролит), + mongo 4.2 EOL upgrade + развод reused-пароля `FNud4Um47y`.
|
||||
|
||||
## Не делать (preemptive guards)
|
||||
|
||||
- **Не снимать `action.destructive_requires_name=true`** на canonical ES. Если ОЧЕНЬ нужен wildcard DELETE — сначала остановиться и подумать на каком endpoint.
|
||||
- **Не использовать `ssh + docker compose up -d`** на VDS для управления Portainer stacks — anti-pattern из CLAUDE.md. Только Portainer API / UI (как делали PUT stack 33 в эту сессию).
|
||||
- **Никогда не делиться `elasticsearch.kzntsv.site`** между slovo и bookva. Bookva-es сейчас internal-only через docker network — это правильно. Если когда-нибудь нужен external — отдельный hostname.
|
||||
- **branch ahead by 1 commit от origin/master** — push без explicit user grant (project-discipline Rule 4). Сейчас в working tree 2 unpushed commit'а: `e9b0a9ed` + `48a5cf39`.
|
||||
- **Не возвращать публикацию `:9200`** (и любых stateful-портов) на `0.0.0.0` без IP-allowlist. Auth должна быть НА сервисе, не только в traefik-мидлваре — free-ES auth не имеет.
|
||||
- **Не трогать mongo/mariadb/minio порты** без подтверждения user'а — он сказал mongo «нужен» снаружи. Сначала выяснить кто коннектится (`ss -tnp | grep 27017`).
|
||||
- **Не использовать `ssh + docker compose up -d`** на VDS для Portainer-stacks — только Portainer API (как делали PUT stack 33). Исключение: traefik/portainer (management-plane, ad-hoc compose — как правка `traefik.yml`).
|
||||
- **branch ahead от origin** — push без явного grant'а (project-discipline Rule 4). Этой сессии grant НЕ давали.
|
||||
|
||||
## Memory updates за сессию
|
||||
|
||||
(нет на этом раунде — ничего не сохраняли в `~/.claude/projects/.../memory/`)
|
||||
- Стоит сохранить: **books VDS — docker port-publish обходит firewalld; stateful-сервисы наружу = vector; ransom-бот уже отметился через :9200**. (не сохранял в memory/ — кандидат на следующий заход, см. `[[vds-kzntsv-traefik-and-minio-hostnames]]` соседний контекст books VDS.)
|
||||
|
||||
Reference in New Issue
Block a user