Files
admin/.tasks/harden-books-vds-exposed-ports.md
vitya 063910e265 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>
2026-05-29 09:31:25 +03:00

63 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` § Стек (2233). 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-портами -->