SSH tunnel on Mac
В целях организации шифрования последней мили я перепробовал массу сервисов, предоставляющих и VPN-туннели и SSH-туннели. Везде разная стоимость и разная политика использования. В итоге решил попробовать организовать свой собственный сервис.
В качестве VPS я выбрал Selectel , потому что минимальная стоимость сервера составляет 60 рублей в месяц и плюс к тому, у меня на аккаунте уже была небольшая сумма денег от предыдущих опытов.
Фактически, для использования SSH-туннеля, на самом сервере ничего делать не нужно, так как ssh-демон работает по умолчанию. Стоит лишь немного побеспокоиться о безопасности, к примеру, изменить используемые порты, запретить вход по паролю и использовать denyhost. Этого вполне достаточно.
Основные проблемы начинаются на клиентской машине. В статьях по организации и использованию SSH-туннелей постоянно приводятся примеры ручного запуска команды. И за состоянием соединения приходиться следить самостоятельно, что довольно муторно.
Наткнулся на описание программы autossh , которая обеспечивает поддержание туннеля в рабочем состоянии и при потере соединения, автоматически создает новое. Для установки в среде MacOS лучше всего использовать homebrew:
$ brew install autossh
И теперь можно использовать туннель следующим образом (первая команда с использованием ssh, вторая ее аналог с autossh):
$ ssh -q -D 8080 -N shell
$ /usr/local/bin/autossh -M0 -q -D 8080 -N shell
Где shell – это имя сервера, которое я использовал в файле ~/.ssh/config
при описании его конфигурации. Итак, стабильное соединение уже организовано, осталось разобраться, каким образом автоматически его запускать.
Как оказалось, в MacOS была полностью переделана система инициализации и обычные скрипты, как в Linux, уже не работали. Вместо этого стал использоваться демон launchd.
Данный демон при своей работе использует три директории:
/Library/LaunchDaemons – используется для хранения задач, которые запускаются в момент, когда пользователи еще не зашли в систему.
/Library/LaunchAgents – используется для хранения задач, которые запускаются в случае входа в систему пользователей.
$HOME/Library/LaunchAgents – используется для хранения задач, которые запускаются только при входе определенного пользователя, при этом, в отличие от предыдущих директорий, задачи запускаются от имени данного пользователя.
При организации ssh-туннеля наиболее разумным видится использование именно третьего варианта. Переходим в эту директорию и создаем plist-файл с описанием конфигурации создаваемой задачи:
$ cd ~/Library/LaunchAgents
$ vim org.evsyukov.shell.plist
За основу я взял файл, который используется для запуска демона Pow .
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.evsyukov.shell</string>
<key>ProgramArguments</key>
<array>
<string>sh</string>
<string>-i</string>
<string>-c</string>
<string>$SHELL --login -c "'/Users/juev/Library/Scripts/ssh-tunnel.sh'"</string>
</array>
<key>KeepAlive</key>
<true/>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
В данном примере я использую скрипт ssh-tunnel.sh
, который разместил в директории ~/Library/Scripts/
, сам скрипт содержит только строки для запуска туннеля:
#!/bin/bash
/usr/local/bin/autossh -M0 -q -D 8080 -N shell
Фактически можно было бы обойтись без создания отдельного файла, но во время экспериментов с plist, столкнулся с определенными проблемами, которые частично удалось решить созданием скрипта.
Самые интересные опции в приведенном выше plist-файле, это KeepAlive и RunAtLoad.
RunAtLoad – параметр, указывающий на запуск задачи во время входа пользователя в систему. Именно он позволяет нам автоматически запускать задачу.
KeepAlive – параметр, который следит за работоспособностью задачи. Это довольно удобная опция, которая позволяет запускать задачу повторно в случае, если процесс неожиданно завершает свою работу.
Теперь, после создания файла описания конфигурации задачи, ее необходимо загрузить:
$ launchctl load /Users/juev/Library/LaunchAgents/org.evsyukov.shell.plist
Для того, чтобы убедиться, что задача была добавлена, используем следующие команды:
$ launchctl list | grep org.evsyukov
1451 - org.evsyukov.shell
$ ps -e | grep autossh
1453 ?? 0:00.00 /usr/local/bin/autossh -M0 -q -D 8080 -N shell
1730 ttys000 0:00.00 grep autossh
Здесь же показан вывод этих команд, в случае удачного запуска.
Таким образом, с использованием launchd был организован автоматический запуск ssh-туннеля во время старта системы. Данный демон постоянно поддерживает в запущенном состоянии autossh, который постоянно проверяет работоспособность туннеля и при необходимости его пересоздает.
Теперь же можно просто в настройках системы указать прокси-сервер socks5 с адресом 127.0.0.1:8080
и забыть о проблеме запуска и зависания соединения.