Рецидив вчерашнего 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>
4.3 KiB
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
- 2026-05-29: exposure audit (таблица выше)
- 2026-05-29: ES :9200 закрыт (в рамках инцидент-фикса)
- 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