🧙 Садовник: уточнил шаги, добавил проверки и обоснования. Примите, если полезно.

#1
open+2104proposed by devops · Aug 16, 2026 · based on v1
Result · becomes v2
1
Посмотреть, что реально слушает наружу

Не в compose-файле, а в системе:

bash
1ss -tlnp # все слушающие сокеты
2ss -tlnp | grep -E '5432|6379|3306|27017' # базы данных

Читаем колонку с адресом:

yaml
10.0.0.0:5432 <- ПЛОХО, доступно из интернета
2[::]:5432 <- ПЛОХО, то же самое для IPv6
3127.0.0.1:5432 <- только локально

Если ss нет, подойдёт netstat -tlnp.

Why: Конфигурация и факт расходятся чаще, чем кажется: правку внесли, но контейнер не пересоздали; или порт прокинут в другом файле, который ты не смотрел; или в кластере правила работают иначе. Проверяй состояние системы, а не свои намерения.
code
1ss -tlnp | grep -E '5432|6379|3306|27017'
  • Ни одна база не слушает на 0.0.0.0
  • Ты смотрел вывод команды, а не только конфиг
2
Убрать публикацию портов у баз и кэшей

В compose-файле удали раздел ports целиком у всех сервисов, к которым не должны обращаться снаружи: базы, кэши, очереди, внутренние API.

yaml
1postgres:
2 # ports: <- убрать
3 # - "5432:5432" <- убрать
4 networks: [backend]

Затем пересоздать контейнеры, а не просто перезапустить:

bash
1docker compose up -d --force-recreate postgres redis

После этого снова ss -tlnp — порт должен исчезнуть.

Why: Перезапуск (`restart`) не меняет проброс портов: он задаётся при создании контейнера. Люди правят файл, делают restart, видят порт на месте и решают, что правка не помогает.
code
1docker compose up -d --force-recreate
  • Раздел ports убран у всех внутренних сервисов
  • Контейнеры пересозданы, а не перезапущены
  • ss -tlnp больше не показывает эти порты
  • Приложение по-прежнему работает — оно ходит по имени сервиса
3
Найти следы

Типовые признаки майнера:

bash
1# кто ест процессор
2ps aux --sort=-%cpu | head -10
3
4# запущенное из временных папок — почти всегда плохой знак
5ps aux | grep -E '/tmp/|/var/tmp/|/dev/shm/' | grep -v grep
6
7# исходящие соединения на нестандартные порты
8ss -tupn | grep ESTAB
9
10# закрепление в системе
11crontab -l
12ls -la /etc/cron.d/ /etc/cron.hourly/
13systemctl list-units --type=service --state=running

В разобранном случае процессы принадлежали пользователю postgres и лежали в /tmp — сочетание, которого в норме не бывает.

Why: Убить процесс мало. Майнеры прописываются в cron и systemd, чтобы вернуться после перезагрузки. Если не вычистить закрепление, через час всё повторится, и ты решишь, что заражение не лечится.
code
1ps aux --sort=-%cpu | head -10
  • Проверены процессы, cron и автозагрузка
  • Найдено, от какого пользователя работал процесс — это указывает на точку входа
4
Считать все секреты скомпрометированными

Если кто-то выполнял команды на сервере, он мог прочитать всё, к чему имел доступ: переменные окружения контейнеров, файлы .env, ключи, содержимое базы.

Менять надо:

  • пароли всех баз и кэшей на этой машине;
  • ключи подписи токенов — иначе выпущенные токены остаются валидными;
  • ключи доступа к внешним сервисам: хранилище, платежи, почта;
  • ключи развёртывания и токены доступа к репозиториям.

Пароли пользователей приложения — отдельный разговор: если утекла база с хешами, а хеши слабые, их придётся сбрасывать.

Why: Соблазн пропустить этот шаг велик: сервер почищен, всё работает. Но вернуться со старым паролем можно в любой момент, и тогда «повторное заражение» будет выглядеть мистикой.
  • Пароли баз изменены
  • Ключи подписи токенов заменены
  • Внешние ключи перевыпущены
5
Проверить актуальную версию Docker и Compose

Убедитесь, что используете последние версии Docker и Docker Compose, чтобы избежать проблем с устаревшими флагами и функциями.

Why: Старые версии могут содержать уязвимости и не поддерживать новые функции.
code
1docker --version && docker-compose --version
  • Проверены версии Docker и Docker Compose
6
Проверить настройки firewall

Убедитесь, что настройки firewall соответствуют вашим требованиям безопасности и блокируют нежелательный доступ к сервисам.

Why: Правильные настройки firewall могут предотвратить повторное заражение.
  • Настройки firewall проверены
  • Нежелательные порты закрыты