Введение
Доступ к удалённым сервисам через SSH-туннели — стандартная практика в enterprise-среде. Контейнеризация этих туннелей добавляет изоляцию, упрощает управление и позволяет интегрировать их в инфраструктуру Podman-подов.
Containerfile для SSH-туннеля
FROM docker.io/library/alpine:3.19
RUN apk add --no-cache openssh-client netcat-openbsd
COPY tunnel.sh /tunnel.sh
COPY ssh_config /etc/ssh/ssh_config
RUN chmod +x /tunnel.sh
HEALTHCHECK --interval=10s --timeout=5s --retries=3
CMD nc -z localhost 8088 || exit 1
ENTRYPOINT [“/tunnel.sh”]
Скрипт туннеля (tunnel.sh)
#!/bin/sh
set -euo pipefail
# Добавляем ключ хоста
mkdir -p /root/.ssh
ssh-keyscan -H “$REMOTE_HOST” >> /root/.ssh/known_hosts 2>/dev/null
# Цикл переподключения
while true; do
echo “[$(date)] Connecting to $REMOTE_HOST…”
ssh -N -o ServerAliveInterval=30
-o ServerAliveCountMax=3
-o ExitOnForwardFailure=yes
-L 0.0.0.0:“$LOCAL_PORT”:“$TARGET_HOST”:“$TARGET_PORT”
-i /secrets/ssh_key
“$SSH_USER”@“$REMOTE_HOST” || true
echo “[$(date)] Disconnected. Reconnecting in 5s…”
sleep 5
done
Health Checks
Healthcheck через netcat проверяет, что локальный порт туннеля доступен. Это позволяет другим контейнерам в поде дождаться установления туннеля перед началом работы. Podman выставляет статус здоровья через podman healthcheck run.
Проброс портов (-L 0.0.0.0:port)
Важный момент — привязка к 0.0.0.0 вместо localhost. Внутри Podman-пода контейнеры общаются через общий сетевой namespace. Туннель, привязанный к 0.0.0.0, доступен всем контейнерам пода. При привязке к 127.0.0.1 — только самому контейнеру туннеля.
Управление known_hosts
ssh-keyscan при запуске контейнера автоматически добавляет ключ удалённого хоста. Для повышения безопасности можно предоставить статический known_hosts через volume или Podman secret. StrictHostKeyChecking можно оставить yes при использовании предзагруженных ключей.
Примеры использования
Мы используем контейнеризированные SSH-туннели для доступа к Asterisk ARI (REST-интерфейс телефонии), базам данных PostgreSQL в защищённых сетях и API-сервисам, доступным только из определённых сегментов сети.
Автоматическое переподключение
Бесконечный цикл while true с sleep обеспечивает автоматическое восстановление при разрыве соединения. ServerAliveInterval и ServerAliveCountMax обнаруживают “мёртвые” соединения. ExitOnForwardFailure гарантирует корректный выход при невозможности проброса порта.
Заключение
Контейнеризированные SSH-туннели — надёжный и удобный способ обеспечения безопасного доступа к удалённым сервисам. Healthcheck, автопереподключение и интеграция с Podman-подами делают это решение production-ready.