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:
62
.tasks/harden-books-vds-exposed-ports.md
Normal file
62
.tasks/harden-books-vds-exposed-ports.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# harden-books-vds-exposed-ports
|
||||
|
||||
## Goal
|
||||
|
||||
Закрыть/ограничить публично торчащие host-порты на books VDS (89.253.255.133). Выявлены
|
||||
во время инцидента `restore-elasticsearch-indices-books-vds` (2026-05-29): ES был снесён
|
||||
ransom-ботом через открытый `0.0.0.0:9200` в обход traefik+firewalld. Тот же класс дыры
|
||||
(docker-publish обходит firewalld INPUT-зоны) зияет ещё на ряде stateful-сервисов. Цель —
|
||||
ни один stateful-сервис не должен быть доступен с публичного IP напрямую; доступ либо через
|
||||
traefik (под auth), либо по внутренней docker-сети, либо по SSH-туннелю для admin.
|
||||
|
||||
## Exposure audit (2026-05-29, `docker ps` + `ss -tlnp`)
|
||||
|
||||
| Сервис | Порт наружу | Auth на сервисе | Действие |
|
||||
|---|---|---|---|
|
||||
| `elasticsearch` | ~~`0.0.0.0:9200`~~ | ❌ free-ES без auth | ✅ ЗАКРЫТ (Fix #3, инцидент) |
|
||||
| `mongo` | `0.0.0.0:27017` | ✅ enabled | убрать публикацию (app ходит по docker-сети) |
|
||||
| `books-db` (mariadb) | `0.0.0.0:3306` | ✅ root+pass | убрать публикацию / SSH-туннель для admin |
|
||||
| `bookva-db` (mariadb) | `0.0.0.0:33306` | ✅ | убрать публикацию |
|
||||
| `minio` | `0.0.0.0:9000` | ✅ | оставить только через traefik (minio.kzntsv.site) |
|
||||
| `bookva-minio` | `0.0.0.0:9001` | ✅ | то же |
|
||||
| rsync | `:873` | ? проверить | проверить нужен ли наружу |
|
||||
| imgproxy / imgproxy-nginx / proxy-chain | `:8787/8788/8778` | ? | проверить, internal? |
|
||||
|
||||
## Key files / endpoints
|
||||
|
||||
- Portainer API `https://portainer.kzntsv.site` (key в `pass books-vds/full-env`), PUT `/api/stacks/<id>?endpointId=1` — паттерн как в Fix #3 (убрать `ports:` блок из compose).
|
||||
- Stack ids: см. `.wiki/entities/books-vds.md` § Стек (22–33). mongo=31, books-db=32, minio=30, ES=33. bookva-* стек(и) — id уточнить через Portainer API list.
|
||||
- firewalld активен но docker его обходит — закрытие через docker port-publish, НЕ через firewalld rules.
|
||||
|
||||
## Decisions log
|
||||
|
||||
- 2026-05-29: Не закрывать в emergency-режиме инцидента — БД credentialed (не дыра-нараспашку как free-ES), и публикация может использоваться для внешнего admin (DBeaver/Compass/mc). Нужно сперва проверить по каждому: ходит ли приложение через host-порт или по docker-сети, и нужен ли внешний admin-доступ (тогда SSH-туннель вместо публикации).
|
||||
|
||||
## Open questions
|
||||
|
||||
- [ ] Каждый сервис: приложение коннектится через `service-name:port` (docker DNS) или через host-порт? Если через docker-сеть → публикацию убрать безопасно.
|
||||
- [ ] Нужен ли кому-то внешний admin к mongo/mariadb? Если да → SSH local-forward, не публичный порт.
|
||||
- [ ] rsync:873 — это backup-pipeline или забытый демон? Проверить.
|
||||
- [ ] imgproxy/proxy-chain порты — реально нужны наружу или artefact?
|
||||
|
||||
## Completed steps
|
||||
|
||||
- [x] 2026-05-29: exposure audit (таблица выше)
|
||||
- [x] 2026-05-29: ES :9200 закрыт (в рамках инцидент-фикса)
|
||||
- [x] 2026-05-29: проверена auth — mongo/mariadb/minio требуют креды (не auth-less)
|
||||
|
||||
## Notes
|
||||
|
||||
Главный learning из инцидента: auth должна быть **на самом сервисе**, не только в
|
||||
traefik-мидлваре. firewalld не защищает от docker-publish. См.
|
||||
`.wiki/concepts/es-destructive-delete-incident-2026-05-26.md` § «Рецидив 2026-05-29».
|
||||
|
||||
## Branch
|
||||
|
||||
n/a (admin ops)
|
||||
|
||||
## Status
|
||||
|
||||
ready 2026-05-29
|
||||
|
||||
<!-- created-by: vitya@.admin-exec / 2026-05-29 / trigger: exposure-audit во время ES ransom-incident — 5 stateful-сервисов с публичными host-портами -->
|
||||
Reference in New Issue
Block a user