Date: 3 Sep 2002
From: Игорь Чубин
Subject: Использование SSH поверх прокси (через SSL CONNECT в squid)
SSH поверх прокси (SSL CONNECT в squid)
Идея
Причиной, которая заставила меня написать эти рекомендации была
необходимость. Необходимость в полноценном доступе к Интернету, когда
под рукой есть только прокси-сервер. Такая проблема сейчас встает
очень часто: существует локальная сеть, подключенная к Интернету через
Squid или другой подбобный ему сервер. Компьютеры сети используют
внутренние адреса: 10.x.x.x, 172.16.x.x или 192.168.x.x. Очевидно,
прямой доступ к серверам Интернета они получить не могут. Выходом мог
бы быть маскарадинг, но он выполняется не всегда: причины могут быть
самые разные -- от соображений безопасности, до элементарной лени.
Обиднее всего, что где-то там, за брандмауэром, есть компьютер,
которому ты не безразличен и вы жаждете соединиться. Что же делать?
Неужто нет никакого выхода? Выход есть, его не может не быть. С
детства известно, настоящая любовь (к полноценному коннекту)
преодолеет любые преграды.
Все прокси поддерживают обработку HTTP-запросов. Это, конечно,
хорошо, но это еще не все. Обычно прокси поддерживает еще и SSL и это
его роковая ошибка :)
Здесь и далее, говоря прокси, мы имеем в виду традиционное
толкование этого термина, т.е. кэширующий прокси-сервер типа Squid,
а не более общее: сервер-посредник, который предоставляет доступ к
какому-лиюо сервису
Конфигурационный файл Squid по умолчанию разрешает соединение с
портами 443 и 563 на которых работает HTTP over SSL и NNTP over SSL.
Фрагмент типового squid.conf файла конфигурации Squid:
acl SSL_ports port 443 563
# Deny CONNECT to other than SSL ports
http_access deny CONNECT !SSL_ports
По большому счету нам все равно, какой из этих портов использовать.
Поскольку обычно все прокси-серверы поддерживают защищенное соединение
https, соединение по порту 443 должно обеспечиваться.
Замечание
Если бы Squid разрешал CONNECT по любому порту:
http_access allow CONNECT all
то можно было бы осуществлять любое исходящее соединение вообще без
всяких проблем. Например, transconnect
(http://transconnect.sourceforge.net/), используя технику подстановки
функций, при помощи замены библиотек позволяет добиться прекрасных
результатов!
Поскольку мы не можем обращаться к любому порту любого сервера
напрямую, нам нужно иметь в Интернете машину, которая будет выполнять
прослушивание этого порта и обрабатывать наши запросы. Схема выглядит
так:
Мы (client) устанавливаем соединение с нашим компьютером в Интернете
(s-proxy) при помощи доступного прокси-сервера (proxy). Соединение,
как мы уже договорились, происходит по https. Приложение на s-proxy, с
которым мы устанавливаем связь, может быть каким угодно. Нужно
добиться как-то, чтобы S-Proxy расшифровывал SSL-трафик, приходящий на
порт 443, и отправлял его интересующему нас приложению. Это
достигается с использование программы stunnel, которая позволяет
делать все что-угодно с каналами SSL.
Какой сервис лучше всего сделать доступным? Добъемся например доступа
к ssh. Для этого есть несколько причин : (самая главная: меня это
сейчас интересует больше всего ;)
* Необходимость. Обычно во внутренней сети все наиболее популярные
службы, как то: e-mail, www, ftp уже доступны. Удаленный же доступ
к компьютерам за пределами сети нередко запрещается или попросту
отсутствует. При этом зачастую он бывает важнее всех остальных
сервисов вместе взятых.
* Универсальность. ssh за счет своей огромнейшей гибкости позволяет
выполнять самые разнообразые вещи, далеко выходящие за рамки
безопасной оболчки, установленные его названием. Фактически, если
у нас есть доступ к удаленной машине по ssh, у нас есть все.
Подсказка
При желании мы можем заставить вообще весь трафик ходить по
SSL-тунелю. Это не проблема, только нужно ли?
Серверная часть
Итак, мы договорились, что данные из внутренней сети во внешнюю и
назад, у нас будут передаваться по SSL-каналу. Все что остается - это
создать его и подключить его к нужным службам.
Ключ -p указывает на файл сертификата. Он обязательно нужен при
использовании stunnel в режиме сервера. Узнать имя файла можно при
помощи ключа -V.
Ключ -r задает порт, на который будет направлен поток, принятый
программой извне. Это как раз и есть данные передающиеся по
SSL-каналу, они расшифровываются и направляются на порт 22, где ведет
прослушивание демон sshd.
Ключ -d определяет порт на котором, сам stunnel выполняет
прослушивание. Мы решили, что будем ходить через https, потому что
скорее всего наш прокси-сервер его обслуживает.
Клиентская часть
Теперь мы долны заняться клиентской частью. Здесь все почти также
просто. Но есть одно небольшое НО. Соединение должно быть установлено
через прокси-сервер, а stunnel, к сожалению, поддерживает только
прямые SSL-соединения.
На www.stunnel.org можно найти небольшой патч к stunnel, который
позволяет использовать прокси-серверы. Патч находится по адресу:
http://www.stunnel.org/patches/desc/proxy_sweeheng.html . Он
разрабатывался для stunnel 3.14, поэтому на stunnel 3.x он
накладывается практически без проблем. Те трудности, которые могут
возникнуть при небольшом несовпадении некоторых строк в файлах версий
>3.14 - не в счет - они легко устраняются ручным вмешательством.
Итак, выполняем сборку stunnel с поддержкой прокси (файлы
proxy_sweeheng.patch.txt и stunnel-3.14-proxy.tar.bz2 находятся в
текущем каталоге, в который у пользователя есть право на запись):
$ tar xvfj stunnel-3.14-proxy.tar.bz2
$ cd stunnel-3.14
$ patch -p0 < ../proxy_sweeheng.patch.txt
$ ./configure
$ make
# make install
Последняя команда должна выполняться от имени суперпользователя root.
Теперь клиентский stunnel с поддержкой прокси у нас есть. Нам осталось
проложить канал на сервер, а дальше преспокойно пользоваться им:
# stunnel -c -d 2222 -Z s-proxy:https -r proxy:https
Команда устанавливает SSL-туннель с текущего хоста на хост s-proxy,
используя хост proxy, как промежуточный (ключ -Z поддерживается только
пропатченным stunnel'ем). Локально тунель доступен по порту 2222.
Этим тунеллированием мы добились того, что все что поступает на порт
2222 локального хоста в результате оказывается на порту 22 хоста
s-proxy. И наоборот, что s-proxy отправляет с порта 22 -- доступно по
локальному порту 2222.
Осталось только воспользоваться плодами своего труда и запустить ssh:
$ ssh user@localhost -p 2222
Мы заставляем обратиться ssh к порту 2222 локального компьютера. Он
наивно полагает, что он общается с локальным сервером и только мы
знаем, что он общается с stunnel, который передает данные по
SSL-тунелю на s-proxy. Понятно, что имя пользователь соответствует не
локальному пользователю, а удаленному, на хосте s-proxy.
Для того чтобы предельно облегчить себе жизнь, можно отключить
аутентификацию по открытым ключам, которую ssh проводит при обращении
к localhost. Для этого в ~/.ssh/config нужно добавить:
Host localhost
PubkeyAuthentication no
Теперь, даже в том случае, если мы используем несколько разных тунелей
с разными хостами или, если, мы любим заходить к себе локально по ssh,
проблем с аутентификацией хоста не возникнет.
Предостережение
Настоятельно не рекомендается отключать проверку подлинности открытыми
ключами с компьютерами, отличными от localhost.