Ранее я уже писал несколько раз об организации ssh-туннелей: SOCKS-прокси через SSH, Туннель через SSH-сервер. В этой статье я расскажу, как максимально безопасно организовать SOCKS-прокси через ssh-туннель.
Обычно, когда делают SOCKS-прокси-туннель, просто добавляют к команде соединения через ssh аргумент типа -D localhost:8008
. Потенциально это не очень безопасно по нескольким причинам:
- вместо аутентификации по ключу используется интерактивная аутентификация по паролю;
- на сервере может быть включен X-Forwarding, дыра;
- аутентификация происходит под обычным ssh-пользователем в интерактивной сессии.
Интерактивная сессия для туннеля не нужна, более того, если вы позволяете соединяться нескольким клиентам под одним аккаунтом, вы им фактически разрешаете выполнять любые команды на сервере.
Аутентификация по паролю также чревата последствиями. Например, если вы хотите разрешить нескольким разным людям подключения с туннелем, вам придётся создать несколько аккаунтов на сервере с разными паролями. Логин через ключи решает эту и ещё несколько других проблем.
Также для аутентификации для прокси-туннеля можно использовать отдельный ключ с простым паролем, это удобно.
Дальше детальная пошаговая инструкция для настройки.
Начальные условия:
- linux-сервер с установленным openssh-server сравнительно актуальной версии;
- root-доступ к этому серверу;
- локальный компьютер с linux/macos и терминалом.
Создаём специального системного пользователя для туннеля¶
На сервере.
Новый пользователь tunnel будет использоваться только в качестве «туннеля», ему не нужен пароль, однако нужен домашний каталог.
$ sudo adduser --gecos "" --shell /bin/sh --disabled-password tunnel
Adding user `tunnel' ...
Adding new group `tunnel' (1001) ...
Adding new user `tunnel' (1001) with group `tunnel' ...
Creating home directory `/home/tunnel' ...
Copying files from `/etc/skel' ...
Создаём отдельный ssh-ключ для туннеля¶
На клиентской машине.
Это опциональный шаг, вы можете использовать уже имеющийся ключ. Но на всякий случай тут об этом расскажу, чтобы не искать информацию по другим страницам.
$ ssh-keygen -f ~/.ssh/id_rsa-TUNNEL
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/sigsergv/.ssh/id_rsa-TUNNEL.
Your public key has been saved in /Users/sigsergv/.ssh/id_rsa-TUNNEL.pub.
The key fingerprint is:
SHA256:8tX6AUhejsdaQqwA4vDkUbg/oMN3wtAIgB0aScfKKk8 sigsergv@local
The key's randomart image is:
+---[RSA 2048]----+
|O+*=. |
|*B++ . |
|+.*.. + . |
| =o. . = * . |
|o.oo o S B . |
|=.E+o. o * o |
|.+. o. o . . |
| . . . |
| . |
+----[SHA256]-----+
Теперь в файле ~/.ssh/id_rsa-TUNNEL.pub
лежит публичный ключ, который мы используем на следующем этапе.
Настраиваем ssh-аутентификацию¶
На сервере.
Сначала базовые шаги:
$ sudo mkdir /home/tunnel/.ssh
$ sudo touch /home/tunnel/.ssh/authorized_keys
$ sudo chown -R tunnel:tunnel /home/tunnel/.ssh
$ sudo chmod 0700 /home/tunnel/.ssh
Теперь нужно отредактировать файл /home/tunnel/.ssh/authorized_keys
и прописать туда публичный ssh-ключ с некоторыми дополнительными параметрами. Допустим, публичный ключ лежит в файле ~/.ssh/id_rsa-TUNNEL.pub
на локальной машине и имеет вид типа ssh-rsa AAAAB...
.
Когда добавляется просто ключ в файл authorized_keys, его содержимое выглядит так (это одна строчка, я её для читабельности сократил, в жизни она длиннее):
ssh-rsa AAAAB3Nza...MjI3 sigsergv@local
Опции добавляются перед ключом, в данном случае — перед символами ssh-rsa
, для нашей конфигурации опции будут такие (их значение я объясню чуть позже, также помним, что это всё одна строка!):
no-X11-forwarding,no-agent-forwarding,no-pty,command="/bin/true" ssh-rsa AAAAB3Nza...MjI3 sigsergv@local
Опции разделяются запятыми, вот они все с объяснениями (вообще все описаны в man sshd
).
- no-X11-forwarding
- Отключаем X11-forwarding, это нужно сделать обязательно, иначе клиент сможет запустить, например, xterm
- no-agent-forwarding
- Отключаем перенаправление ssh-agent.
- no-pty
- Отключаем аллокацию tty (терминала).
- command="/bin/true"
- Здесь мы задаём команду, которая будет выполняться при старте туннеля и которая не даст юзеру выполнить свою команду.
Теперь нужно создать /home/tunnel/.ssh/rc
со следующим содержимым (это просто сообщение, которое показывается при успешном подключении):
echo "Tunnel is active"
Файл создаётся такой командой:
$ echo 'echo "Tunnel is active"' | sudo -u tunnel tee /home/tunnel/.ssh/rc > /dev/null
Как подключаться к такому туннелю¶
На клиентской машине.
Всё как обычно:
$ ssh -i ~/.ssh/id_rsa-TUNNEL -D 127.0.0.1:8000 [email protected]
PTY allocation request failed on channel 1
SSH tunnel session has been started, press CTRL+C to terminate
Туннель (и локальный SOCKS-proxy по адресу 127.0.0.1:8000) будет работать, пока вы не нажмёте Ctrl+C
Чтобы ещё упростить себе жизнь, можно добавить параметры подключения в файл ~/.ssh/config
:
Host tunnel-example
IdentityFile ~/.ssh/id_rsa-TUNNEL
Hostname example.com
DynamicForward 127.0.0.1:8000
RequestTTY no
Compression yes
User tunnel
Теперь для создания туннеля-прокси достаточно набрать команду ssh tunnel-example
.
История обновлений¶
2018-03-14 Уточнены параметры в ~/.ssh/authorized_keys
, больше секьюрности. Добавлено упоминание .ssh/rc
2021-01-07 Добавлена команда для создания файла /home/tunnel/.ssh/rc
2024-03-23 Уточнение терминологии и минорное форматирование.