SSH и Docker: стоит ли подключаться к контейнерам по SSH?

Быстрая навигация
- Нужно ли использовать SSH внутри контейнеров?
- Как установить SSH-сервер в контейнере (пример для Debian)
- Настройка аутентификации: пароли и ключи
- Подключение к контейнеру и варианты порт-форвардинга
- Упрощение с Dockssh
- Альтернативы, шаблоны и рекомендации по безопасности
- Контрольный список для ролей
- Итог
Почему обычно не стоит использовать SSH внутри контейнера
SSH в контейнере часто рассматривают как «быстрый» способ получить интерактивный доступ. Однако контейнеры проектировались как короткоживущие, одноцелевые и воспроизводимые единицы. Вот основные аргументы против:
- Иммутабельность: контейнеры должны быть неизменяемыми после сборки. Правки внутри запущенного контейнера теряются при пересоздании — вместо исправлений нужно пересобрать образ и перезапустить контейнер.
- Дополнительная поверхность атаки: SSH-сервер добавляет зависимости, потенциальные уязвимости и необходимость управлять учётными записями.
- Оверхед управления: если на хосте много контейнеров, потребуется отслеживать отдельные SSH-порты или процессы.
- Инфраструктурная несовместимость: многие CI/CD и оркестраторы ожидают, что контейнер запускает только целевое приложение, а не системные демоны.
Вместо SSH чаще применяют:
- docker exec -it
bash (или sh) — быстрый и аудируемый способ получить shell; - kubectl exec для Kubernetes-кластеров;
- специализированные прокси (например, Dockssh) для удобного внешнего подключения без установки SSH в образ.
Важно: в отдельных сценариях (локальная отладка, интеграция со старыми IDE, тестовые стенды) SSH внутри контейнера может быть допустимым временным решением.
Когда SSH внутри контейнера оправдан
- Интеграция с устаревшими инструментами, требующими SSH-доступ;
- Быстрая интерактивная отладка локального окружения в режиме разработки (не в production);
- Учебные и экспериментальные среды;
- Если невозможно модифицировать образ или процесс деплоя (например, проприетарные образы), и нужен временный доступ.
Как установить SSH-сервер в Docker-контейнер (пример для Debian)
Большинство базовых образов минималистичны — OpenSSH нужно добавить самостоятельно. Пример Dockerfile-фрагмента для Debian-подобного образа:
RUN apt-get update && apt-get install -y openssh-server
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN mkdir -p /var/run/sshd
ENTRYPOINT ["/usr/sbin/sshd","-D"]Пояснения:
- apt-get install устанавливает SSH-сервер;
- sed меняет настройку PermitRootLogin; включать root-доступ не рекомендуется в production;
- /var/run/sshd нужен systemd-less окружению, чтобы sshd мог создать pid-файл;
- ENTRYPOINT запускает sshd в foreground (
-D) вместо запуска systemd или service.
Лучше не давать прямой root-доступ, а создать отдельного пользователя:
RUN useradd -m -s /bin/bash sshuserНастройка аутентификации
Парольный вход — простой, но менее безопасный:
RUN echo "sshuser:Changeme" | chpasswdБолее безопасно использовать ключи SSH. Генерируйте ключи на клиенте и добавьте публичный ключ в образ или смонтируйте его через volume. Пример “вшивания” ключа в образ (не всегда безопасно):
COPY id_rsa.pub /home/sshuser/.ssh/authorized_keys
RUN chown -R sshuser:sshuser /home/sshuser/.ssh
RUN chmod 600 /home/sshuser/.ssh/authorized_keysПримечания безопасности:
- Встраивание публичного ключа в образ делает ключ частью артефакта и доступным всем, у кого есть образ;
- Лучше монтировать ~/.ssh/authorized_keys через volume при запуске контейнера или использовать конфигурационные системы/секрет-менеджеры;
- Убедитесь, что права файлов соответствуют требованиям SSH (600 для authorized_keys, 700 для ~/.ssh).
Важное
Никогда не храните приватные ключи внутри образа. Приватные ключи должны оставаться только на клиентских машинах.
Подключение к контейнеру по SSH: примеры порт-форвардинга и альтернативы
Запуск контейнера и проброс порта 22 на хост (внимание: это может конфликтовать с SSH хоста):
docker run -p 22:22 my-image:latestЕсли уже есть SSH-сервер на хосте или требуется нестандартный порт, пробрасывайте другой хост-порт, например 2220:
docker run -p 2220:22 my-image:latestТогда подключения будут такими:
ssh sshuser@host.example.com -p 2220Если вы подключаетесь с хоста, где запущен Docker, можно получить IP контейнера (в простых сценариях bridge-сети):
docker inspect | grep 'IPAddress' | head -n 1 Затем подключиться по IP:
ssh sshuser@172.17.0.1Но адрес контейнера в bridge-сети часто недоступен извне и не стабилен при пересоздании.
Короткие имена через ~/.ssh/config
Чтобы не запоминать IP и порт, добавьте в ~/.ssh/config запись:
Host my-container
HostName host.example.com
Port 2220
User sshuserПосле этого ssh my-container откроет сессию в контейнере.
Dockssh: прокси, который делает docker exec доступным через ssh
Dockssh — проект, который слушает SSH-подключения и проксирует их в docker exec, избавляя от необходимости ставить sshd в каждом образе.
Пример установки и настройки (порядок действий):
- Установите Redis (Dockssh использует Redis для хранения паролей/настроек):
sudo apt install redis- Добавьте запись для контейнера в Redis
redis-cli set dockssh:my-container:pass "container-password-here"- Скачайте бинарный файл Dockssh и сделайте его исполняемым:
sudo curl https://github.com/alash3al/dockssh/releases/download/v1.1.0/dockssh_linux_amd64 -O /usr/local/bin/dockssh
sudo chmod +x /usr/local/bin/dockssh- Откройте порт брандмауэра (по умолчанию Dockssh слушает 22022):
sudo ufw allow 22022- Запустите Dockssh и проверьте доступ:
dockssh
ssh my-container@example.com -p 22022- Можно зарегистрировать Dockssh как системную службу systemd:
sudo nano /etc/systemd/system/dockssh.serviceСодержимое сервиса:
[Unit]
Description=Dockssh service
After=network.target
[Service]
Type=simple
Restart=always
RestartSec=1
User=root
ExecStart=/usr/local/bin/dockssh
[Install]
WantedBy=multi-user.targetАктивируйте сервис:
sudo systemctl enable dockssh.service
sudo systemctl start docksshПлюсы Dockssh:
- Не требует установки sshd в образах;
- Упрощает подключение к множеству контейнеров;
- Позволяет использовать привычные команды ssh;
- Централизует аутентификацию и аудит.
Ограничения:
- Зависимость от Redis и дополнительного демона;
- Требует настройки и безопасности на хосте;
- Может не подходить для высоконагруженных продакшен-сред.
Альтернативные подходы (когда SSH не подходит)
- docker exec / kubectl exec — стандартный и рекомендованный способ;
- docker attach — прикрепление к рабочему процессу (если приложение поддерживает интерактивный ввод);
- Sidecar-контейнер для отладки — отдельный контейнер с инструментами, подключённый к тому же namespace;
- Remote debugging через IDE (настроить проброс портов от отладчика, а не SSH);
- Использование CI/CD для внесения изменений через сборку новых образов.
Практическое руководство: когда и как безопасно использовать SSH
Мини-методология принятия решения:
- Определите цель доступа: отладка, интеграция, поддержка.
- Оцените риск: production vs dev/test.
- Если цель — временная отладка, используйте docker exec или sidecar.
- Если обязательна внешняя интеграция и альтернатив нет — применяйте SSH только с ключами, без паролей, и с ограниченным доступом по брандмауэру.
- Автоматизируйте: если правка кода нужна постоянно — внедрите CI и пересобирайте образы.
Контрольный список по ролям
Разработчик:
- Использует docker exec вместо SSH для интерактивных сессий;
- Если нужно, запускает временный контейнер с SSH только в локальном окружении;
- Настраивает SAM/Makefile для воспроизводимых билдов.
Сисадмин/DevOps:
- Запускает Dockssh или администрирует контроль доступа на хосте;
- Настраивает firewall и ограничивает доступ по IP/ключам;
- Внедряет аудит и логи для всех подключений;
- Автоматизирует создание образов вместо ручных правок в контейнерах.
Инженер по безопасности:
- Запрещает проброс порта 22 для контейнеров в production;
- Проводит ревью образов на предмет лишних сервисов;
- Обеспечивает управление секретами и rotatation ключей.
Безопасность и харднинг при использовании SSH в контейнере
- Используйте SSH-ключи, отключите вход по паролю (PasswordAuthentication no) для production;
- Ограничьте доступ с помощью AllowUsers/Match Address или firewall;
- Отключите root-вход, создайте привилегированного пользователя с sudo по необходимости;
- Следите за обновлениями пакетов и минимизируйте базовый образ;
- Используйте readonly root filesystem, если приложение позволяет;
- Логируйте сессии и направляйте логи в централизованную систему.
Критерии приёмки
- Контейнер не содержит лишних демонов в production (включая sshd), если нет обоснования;
- Все подключения к контейнерам документированы и централизованы;
- Доступ через SSH защищён ключами, брандмауэр настроен, и есть аудит.
Примеры сценариев и когда это не сработает
Не стоит ставить SSH если:
- Вы используете оркестраторы (Kubernetes), где ожидается управление через kubectl и инструменты CI;
- Контейнеры деплоятся автоматически через CD и пересоздаются часто — ручной доступ приведёт к рассогласованию;
- Требуется минимизация образа и поверхности атаки.
Подходит временно для:
- Локальной разработки и отладки;
- Закрытых тестовых стендов;
- Миграции устаревших систем с ограниченной возможностью изменения процесса деплоя.
Шаблоны и сниппеты (читшит)
Запуск Debian-контейнера с SSHd для локальной отладки:
# Dockerfile
FROM debian:stable-slim
RUN apt-get update && apt-get install -y openssh-server sudo
RUN useradd -m -s /bin/bash sshuser && echo "sshuser:changeme" | chpasswd && adduser sshuser sudo
RUN mkdir -p /var/run/sshd
EXPOSE 22
ENTRYPOINT ["/usr/sbin/sshd","-D"]Запуск контейнера и проброс порта 2222:
docker build -t my-ssh-image .
docker run -d -p 2222:22 --name my-dev my-ssh-image
ssh sshuser@localhost -p 2222Dockssh быстрый старт (повтор):
redis-cli set dockssh:my-container:pass "container-password-here"
/usr/local/bin/dockssh
ssh my-container@example.com -p 22022Рекомендации по миграции от SSH к современным практикам
- Автоматизируйте сборку образов и deployment pipelines;
- Внедрите docker exec / kubectl exec для администрирования; логируйте команды;
- Если необходим постоянный удалённый доступ — рассмотрите централизованные прокси (Dockssh) или bastion-хост на уровне инфраструктуры, но не в каждом образе;
- Используйте Sidecar/Debug-контейнеры для временных инструментов и мониторинга.
Итог
SSH в Docker-контейнерах — инструмент со своим местом, но чаще это антипаттерн. Для одноразовой отладки и интеграции с устаревшими процессами SSH может быть удобен, однако для устойчивых и безопасных рабочих процессов предпочтительнее docker exec, централизация доступа и использование прокси-решений вроде Dockssh. Если всё же используете SSH — строго соблюдайте практики безопасности, учёт прав доступа и автоматизацию обновлений.
Ключевые шаги для безопасного использования SSH:
- По возможности используйте docker exec;
- Если нужен SSH, применяйте ключи и ограничьте доступ;
- Централизуйте управление (Dockssh, bastion);
- Автоматизируйте пересборку образов вместо ручных правок.
Важно: для production-окружений избегайте установки SSH в образах без веской причины.
Похожие материалы
Компьютер завис на экране загрузки — как исправить
Копирование масок в Camera Raw и Lightroom
Как убрать зелёный треугольник в Excel
Как понять, что видеокамеру взломали и как реагировать
Защита от троянов на Android