63 lines
4.3 KiB
Markdown
63 lines
4.3 KiB
Markdown
# 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-портами -->
|