Ключевые слова:ssh, faq, crypt, auth, (найти похожие документы)
From: OpenBSD.ru
Date: Mon, 09 Feb 2009 17:02:14 +0000 (UTC)
Subject: OpenSSH: настройки, секреты, трюки и советы
Оригинал: http://www.openbsd.ru/docs/ssh-tips.html
Некоторые советы взяты из статей "Калейдоскоп тайных знаний" и
"Волшебные криптотуннели", опубликованных в июньском и июльском номерах
журнала "Хакер" за 2008 год. Авторы статей: Андрей Матвеев и
Сергей Яремчук. Коррективы и уточнения введены проектом OpenBSD.ru.
За последние несколько лет OpenSSH из набора программ для защищенной
системы регистрации, выполнения команд на удаленном хосте и передачи
файлов с одной машины на другую превратился в швейцарский армейский
нож, просто потрясающий своими возможностями. Используете ли вы хотя бы
половину из них?
Отключение прослушивания IPv6 адресов
По умолчанию sshd(8) слушает как на IPv4 так и на IPv6 адресах. Для
того что бы отключить возможность работы по IPv6, необходимо изменить
параметр AddressFamily:
AddressFamily inet
Адрес и порт прослушивания
По умолчанию sshd(8) принимает подключения на всех интерфейсах, в чем
не всегда есть необходимость. Если не требуется заходить на сервер "из
вне", следует ограничить его работу определенным адресом с помощью
параметра ListenAddress:
# ListenAddress 0.0.0.0
ListenAddress 192.168.1.2
Дополнительно через двоеточие можно указать и номер порта. В данном
примере используется значение порта, заданное глобально параметром
Port.
Ограничение доступа суперпользователя
В большинстве дистрибутивов в целях безопасности доступ
суперпользователю по SSH закрыт (PermitRootLogin no), и при попытке
зарегистрироваться под root получаем сообщение об ошибке. Для
выполнения задач, требующих привилегий администратора, приходится
заходить под обычным пользователем и использовать su(1) или sudo(8).
Красиво выйти из ситуации поможет директива Match. В качестве аргумента
ей передается критерий отбора (User, Group, Host, Address), его
значение и параметр, который нужно применить. Для примера разрешим
подключение под root только с localhost и из доверенной подсети
192.168.5.0/24:
PermitRootLogin no
Match Host 192.168.5.*,127.0.0.1
PermitRootLogin yes
Контроль неудачных подключений
Следующие две директивы позволяют контролировать неудачные подключения
к серверу:
LoginGraceTime 60
MaxStartups 2:50:10
Параметр LoginGraceTime определяет, по истечению какого времени
простаивающее подключение будет разорвано (в секундах). Значение по
умолчанию 120 явно завышено. Количество параллельных
неаутентифицированных подключений к серверу контролируется при помощи
MaxStartups. Запись параметра имеет форму "start:rate:full". В нашем
случае она означает отключение с вероятностью 50% при наличии двух
неаутентифицированных связей, с линейным ростом вероятности до 100% при
достижении 10.
Контроль за подключениями пользователей
Установки в файлах /etc/ssh/sshrc или ~/.ssh/rc позволяют выполнить
некоторые действия при регистрации пользователя. Здесь можно
использовать любые команды оболочки. Например, отправим администратору
на почту уведомление о том, что в систему по SSH зашел пользователь:
# vi /etc/ssh/sshrc
echo $(date) $SSH_CONNECTION $USER $SSH_TTY | mail -s "ssh login" [email protected]
Пример создания резервных копий
Генерируем пару ключей (секретный и публичный):
$ sudo ssh-keygen -t rsa -C 'remote backup'
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_rsa):
/home/user/.ssh/id_rsa_backup
Добавляем публичный ключ в список авторизованных ключей на удаленной
системе:
$ ssh remotehost "umask 077; cat > .ssh/authorized_keys" < .ssh/id_rsa_backup.pub
Затем редактируем authorized_keys (ключ '-t' следует использовать при
запуске программ, требующих для своей работы наличия псевдотерминала):
$ ssh -t remotehost vi .ssh/authorized_keys
from="192.168.0.*,212.34.XX.YY",command="cd /work; tar cvf - ./* | bzip2 -9",
no-pty,no-agent-forwarding,no-X11-forwarding,no-port-forwarding ssh-rsa AAAA[...]
И запускаем процедуру резервного копирования:
$ ssh -i .ssh/id_rsa_backup remotehost > ~/backup/work-`date +%d%m%Y`.tar.bz2 2>/dev/null
Каталог /work, находящийся на сервере remotehost, будет сохранен в
архив ~/backup/work-11052008.tar.bz2.
Используем dump в связке с SSH
Используя SSH, можно защитить информацию, передаваемую программами, не
имеющими встроенных механизмов шифрования соединения. Например, сделаем
бэкап с помощью dump(8) на удаленный сервер:
$ sudo dump -0au -f - /dev/rwd1a | gzip -9 | ssh remotehost 'dd of=cvs_backup.dump.gz'
Поскольку в dump(8) встроена возможность передавать данные по сети с
использованием RSH, существует возможность использования и SSH,
поскольку его функциональность аналогична:
$ ssh remotehost touch /home/user/cvs.dump
$ env RSH=`which ssh` sudo -E dump 0f remotehost:/home/user/cvs.dump /cvs
Передача файлов и каталогов
Передать файл, используя SSH, можно одним из следующих способов:
$ cat myfile | ssh remotehost 'cat > myfile'
$ tar zcf - ~/coding | ssh remotehost 'cat > coding.tgz'
Чтобы рекурсивно отправить весь каталог, набираем:
$ scp -r mydir [email protected]:
Вариант копирования каталога с использованием ssh(1) и tar(1) с
локального хоста на удаленный:
$ tar cf - source | ssh remotehost "(cd /target; tar xpf -)"
и с удаленного хоста на локальный:
$ ssh remotehost "tar cf - source" | (cd /target; tar xpf -)
Безопасный способ получения почты
Для безопасного получения почты с помощью fetchmail можно использовать
SSH. Для этого в конфигурационном файле ~/.fetchmailrc необходимо
указать следующее:
poll localhost with protocol pop3 and port 8110:preconnect "ssh -f -q -C [email protected] \
-L 8110:213.167.XX.YY:110 sleep 10" password noIdea;
Забираем почту:
$ fetchmail
1 message for user at localhost (8062 octets).
reading message [email protected]:1 of 1 (8062 octets)....... flushed
Почтовый шлюз
Настроим 192.168.1.1 на перенаправление входящей и исходящей почты по
шифрованному каналу для клиентов из 192.168.1.0/24 на mail.domain.ru:
$ vi .ssh/config
Host mail
Hostname mail.domain.ru
LocalForward 192.168.1.1:8025 mail.domain.ru:25
LocalForward 192.168.1.1:8110 mail.domain.ru:110
LocalForward 192.168.1.1:8143 mail.domain.ru:143
GatewayPorts yes
Открываем туннель:
$ ssh mail
Выполнение заданной команды после подключения
Параметр ProxyCommand позволяет выполнить произвольную команду. Для
примера подключимся через шлюз к файловому серверу, который находится
за NAT:
$ vi .ssh/config
Host gateway
HostName ns.domain.ru
Host filesrv
HostName 192.168.5.201
ProxyCommand ssh gateway nc -w 180 %h %p
Подключаемся:
$ ssh filesrv
Мультиплексирование ssh-сессий
Использование параметра ControlMaster позволяет ускорить доступ к
удаленному серверу за счет того, что в специальном файле сохраняются
все параметры предыдущего сеанса, которые и используются при повторном
подключении. Для примера создадим две Host-секции:
$ vi .ssh/config
Host srv1
HostName 213.167.XX.YY
ControlMaster yes
# Здесь %r - имя, %h - хост и %p - порт
ControlPath ~/.ssh/ctl-%r-%h-%p
Host srv1fast
HostName 213.167.XX.YY
ControlMaster no
ControlPath ~/.ssh/ctl-%r-%h-%p
Теперь на сервере srv1 выполняем утилиту uptime(1), логинимся на нем
(чтобы создать локальный сокет для второго подключения), переходим на
другую консоль и снова запрашиваем статистические счетчики:
ttyp0$ time ssh srv1 uptime
5:55PM up 37 days, 9:19, 1 user, load averages: 0.33, 0.32, 0.33
0m0.77s real 0m0.06s user 0m0.01s system
ttyp0$ ssh srv1
ttyp1$ time ssh srv1fast uptime
5:57PM up 37 days, 9:20, 2 users, load averages: 0.37, 0.34, 0.33
0m0.03s real 0m0.00s user 0m0.01s system
Из примера видно, что при использовании мультиплексирования соединений
время выполнения команды uptime(1) на удаленном сервере уменьшилось в
25 раз.
Создание SOCKS-сервера
OpenSSH можно использовать как специальный SOCKS-сервер, который
поддерживает более гибкое проксирование, чем простое перенаправление
портов. Например, команда:
$ ssh -D1080 [email protected]
Создает локальный SOCKS5-сервер, который ждет подключения на
localhost:1080. Альтернативный вариант - прописать директиву
DynamicForward в .ssh/config:
$ vi .ssh/config
Host proxy
HostName ns.domain.ru
DynamicForward 1080
Подключаемся, введя ssh proxy. Протестировать работу SOCKS5-сервера
можно такой командой:
$ echo -n "GET / HTTP/1.0\r\n\r\n" | nc -X 5 -x 127.0.0.1:1080 \
www.domain.ru 80 | head -4
HTTP/1.1 200 OK
Date: Sat, 23 Feb 2008 14:27:43 GMT
Server: Apache
X-Powered-By: PHP/4.4.1
Теперь SOCKS-сервер готов к использованию:
$ tsocks thunderbird
Сажаем пользователей в песочницу
В OpenSSH 4.9 появилась долгожданная поддержка chroot(2) для sshd(8),
контролируемая с помощью опции ChrootDirectory. К примеру, заставим
подключающегося по sftp пользователя worker переходить в измененный
корневой каталог data:
# vi /etc/ssh/sshd_config
#Subsystem sftp /usr/libexec/sftp-server
Subsystem sftp internal-sftp
Match User worker
X11Forwarding no
AllowTcpForwarding no
ForceCommand internal-sftp
ChrootDirectory /data
Пример для хостинговых клиентов:
# vi /etc/ssh/sshd_config
#Subsystem sftp /usr/libexec/sftp-server
Subsystem sftp internal-sftp
Match Group wwwusers
X11Forwarding no
AllowTcpForwarding no
ForceCommand internal-sftp
ChrootDirectory /var/www/hosting/%u
Теперь зарегистрированные пользователи будут допущены только к "своему"
каталогу, при подключении модификатор %u будет заменен именем
пользователя. При необходимости можно использовать %h, который
соответствует домашнему каталогу юзера.
Скрываем записи о серверах, к которым мы подключались
Некоторые администраторы, возможно, захотят зашифровать все IP и
доменные адреса из файла .ssh/known_hosts. Делается это следующим
образом:
$ echo 'HashKnownHosts' >> ~/.ssh/config
$ ssh-keygen -H -f ~/.ssh/known_hosts
$ head -1 ~/.ssh/known_hosts
+|1|TJ2SaXGqO8uHYeiA92KuNRIKR7M=|GpQB8Qz0tQPqA+nF+ghe37mpcHA= ssh-rsa AAAA[...]
Управляющие последовательности SSH
Управляющие последовательности SSH станут доступны, если в SSH-сессии
сначала нажать <Enter>, затем управляющий символ сеанса (по умолчанию
тильда, задается директивой EscapeChar) и специальную клавишу, которая
указывает, какую именно функцию следует выполнить.
Допустим, мы с mail.domain.ru зашли на bastion.domain2.ru и решили, что
не плохо было бы открыть обратный шифрованный туннель к почтовому
серверу для безопасной загрузки сообщений. С помощью комбинации клавиш
"<Enter>~C" можно интерактивно управлять локальным и удаленным
форвардингами (ключи '-L' и '-R'):
bastion$ <Enter>~C
ssh> -R 8110:mail.domain.ru:110
Forwarding port.
Проверяем работу созданного почтового туннеля:
bastion$ telnet localhost 8110
+OK Dovecot ready.
В ответ получен баннер от Dovecot, значит, все в порядке.
Кстати, обратившись к подсказке, получим список всех доступных ключей и
дополнительных параметров:
bastion$ <Enter>~C
ssh> help
Commands:
-L[bind_address:]port:host:hostport Request local forward
-R[bind_address:]port:host:hostport Request remote forward
-KR[bind_address:]port Cancel remote forward
Если в ~/.ssh/config установить значение директивы PermitLocalCommand в
yes, то мы сможем выполнять команды в локальном шелле, т.е. на хосте, с
которого зашли:
ns$ ssh mx
mx$ <Enter>~C
ssh> !uptime # команда выполняется на хосте ns
7:02PM up 100 days, 11 mins, 1 user, load averages: 0.13, 0.21, 0.23
<Enter>
mx$ uptime # команда выполняется на хосте mx
7:02PM up 4 days, 7:34, 1 user, load averages: 0.21, 0.23, 0.19
Если на предыдущем узле требуется выполнить сразу несколько команд, то
SSH-сессию лучше временно засуспендить (приостановить выполнение
программы ssh):
mx$ <Enter>~<Ctrl-Z>
[1] + Suspended "ssh" "$@"
Чтобы перевести SSH-сессию из остановленного режима в активный, следует
воспользоваться командой fg.
Список текущих SSH-соединений можно просмотреть комбинацией:
mx$ <Enter>~#
The following connections are open:
#0 client-session (t4 r0 i0/0 o0/0 fd 5/6 cfd -1)
А для быстрого завершения SSH-сессии ставим точку:
mx$ <Enter>~.
Connection to 213.167.XX.YY closed.
Сокращенный набор
Чтобы в консоли не вводить полное доменное имя, порт и учетную запись
для подключения к удаленной системе, стоит заручиться поддержкой
директивы Host:
$ vi ~/.ssh/config
Host mx
Hostname mx.domain.ru
Port 2022
User admin
Таким образом, достаточно ввести ssh mx, чтобы соединиться с нужным
хостом.
Получение доступа к закрытому сервису
Многие администраторы в целях безопасности скрывают свои сервера в
демилитаризованной зоне, либо за NAT'ом, и разрешают входящие
соединения только с доверенных IP-адресов и по определенными портам.
Поэтому доступ ко многим полезным ресурсам получить напрямую нельзя.
Это как раз тот случай, когда использование SSH-форвардинга может
исправить ситуацию.
$ vi ~/.ssh/config
Host gate
Hostname gate.domain.ru
# Для ускорения соединений включаем мультиплексирование SSH-сессий
ControlMaster auto
ControlPath ~/.ssh/ctl-%r-%h-%p
# Перенаправляем локальный порт на файловый сервер (Win2k3 с поднятым VShell)
LocalForward 8022 192.168.1.101:22
# Подключаясь к localhost:8022, мы будем попадать на файловый сервер
Host fileserver
Hostname localhost
Port 8022
ControlMaster auto
ControlPath ~/.ssh/ctl-%r-%h-%p
HostKeyAlias fileserver
Соединяемся с узлом gate и проверяем возможность подключения к
локальному порту 8022:
$ ssh -N -f gate
$ telnet localhost 8022
SSH-2.0-VShell_3_0_4_656 VShell
Теперь можно подключиться к файловому серверу, который находится за
NAT'ом, в обход правил файерола, установленных на шлюзе:
$ ssh fileserver
Microsoft Windows [Version 5.2.3790]
C:\Documents and Settings\Username\My Documents>
Ограничение возможностей перебора паролей с помощью Pf
Сервис SSH является любимой мишенью злоумышленников, поэтому следует
принять некоторые меры безопасности. Одна из них - ограничение
количества подключений, чтобы избежать DoS-атаки и перебора паролей.
# vi /etc/pf.conf
table <sshbf> persist
block in log quick on $ext_if inet from <sshbf>
pass in log on $ext_if inet proto tcp to $ext_if port ssh keep state \
(max-src-conn-rate 5/60, overload <sshbf> flush global)
Данный набор правил инструктирует фильтр пакетов не допускать более 5
одновременных соединений к 22 порту за 60 секунд.
Перенаправление X11-подключений
Для перенаправления X11-подключений следует использовать ключ '-Y':
$ ssh -Y [email protected]
Причем в конфигурационном файле /etc/ssh/sshd_config параметр
X11Forwarding должен быть установлен в "yes". Если X-сервер запущен на
локальной системе, то необходимо включить и X11UseLocalhost.
Использование аутентификации на базе публичного ключа
Генерируем пару ключей (секретный и публичный):
% ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/andrushock/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/andrushock/.ssh/id_rsa.
Your public key has been saved in /home/andrushock/.ssh/id_rsa.pub.
The key fingerprint is:
25:95:5b:a6:d7:26:b6:f5:f9:a7:49:d4:a8:2a:0d:7d andrushock@midian
Проверяем корректность прав доступа к директории .ssh и RSA-ключам:
% ls -la .ssh | egrep -v 'total|\.\.'
drwx------ 2 andrushock wsrc 512 Oct 19 20:42 ./
-rw------- 1 andrushock wsrc 1743 Jun 11 03:35 id_rsa
-rw-r--r-- 1 andrushock wsrc 413 Jun 11 03:35 id_rsa.pub
Добавляем публичный ключ в список авторизованных ключей на удаленной
системе:
% ssh user@host "cat >> .ssh/authorized_keys" < .ssh/id_rsa.pub
В случае, если подкаталог .ssh и файл .ssh/authorized_keys на удаленной
системе не существуют:
% ssh user@host "mkdir -m 700 .ssh; umask 077; cat > .ssh/authorized_keys" < .ssh/id_rsa.pub
Для сохранения парольных фраз к приватным ключам запускаем ssh-agent(1):
% eval `/usr/bin/ssh-agent`
Agent pid 3855
С помощью ssh-add(1) добавляем в память агента парольную фразу от
нашего ключа:
% ssh-add
Enter passphrase for /home/andrushock/.ssh/id_rsa:
Identity added: /home/andrushock/.ssh/id_rsa (/home/andrushock/.ssh/id_rsa)
Для проверки просматриваем отпечаток секретного ключа:
% ssh-add -l
2048 25:95:5b:a6:d7:26:b6:f5:f9:a7:49:d4:a8:2a:0d:7d /home/andrushock/.ssh/id_rsa (RSA)
Выполняем вход на удаленный сервер без ввода пароля и парольной фразы:
% ssh user@host
OpenBSD 3.7-current (GENERIC) #1: Mon Aug 1 00:37:53 MSD 2005
Welcome to OpenBSD: The proactively secure Unix-like operating system.
$
Пример использования функций оболочки для упрощения беспарольной
аутентификации:
% vi .profile
ssh_agent_start() {
id1=$HOME/.ssh/identity
id2=$HOME/.ssh/id_dsa
id3=$HOME/.ssh/id_rsa
if [ ! "$SSH_AGENT_PID" ] && [ -f $id1 -o -f $id2 -o -f $id3 ]; then
eval `/usr/bin/ssh-agent -s`
/usr/bin/ssh-add < /dev/null
export SSH_AGENT_SHELL=$$
fi
}
ssh_agent_stop() {
if [ "$SSH_AGENT_PID" -a "$SSH_AGENT_SHELL"x = "$$"x ]; then
/usr/bin/ssh-add -D < /dev/null
eval `/usr/bin/ssh-agent -sk`
fi
}
ssh_agent_start
trap ssh_agent_stop 0 1
VPN на базе SSH
Для примера возьмем два сервера: srv1 с IP-адресами 212.34.XX.YY и
192.168.2.1 подключен к сегменту внутренней сети 192.168.2.0/24, а srv2
с 213.167.XX.YY и 192.168.1.1 шефствует над подопечными из
192.168.1.0/24. Настроим VPN-туннель средствами OpenSSH, в котором
будут использоваться адреса 10.0.0.1 и 10.0.0.2. Для наглядности
сценарий можно представить следующим образом:
(10.0.0.1) 212.34.XX.YY 213.167.XX.YY (10.0.0.2)
192.168.2.0/24 --- srv1 --- [ internet ] --- srv2 --- 192.168.1.0/24
192.168.2.1 192.168.1.1
Ключевые элементы сетевой конфигурации рассмотрены, теперь приступаем к
настройкам. Логинимся на srv1 и правим главный конфигурационный файл sshd(8):
srv1# vi /etc/ssh/sshd_config
# Разрешаем туннелирование layer-3
# PermitTunnel point-to-point
# VPN на базе OpenSSH требует привилегий суперпользователя,
# поэтому аутентификацию под учетной записью root разрешаем
# только с доверенных хостов
#
PermitRootLogin no
Match Host 213.167.XX.YY,192.168.2.*,127.0.0.1
PermitRootLogin yes
По окончании настроек не забываем отправить демону сигнал SIGHUP, чтобы
он смог перечитать свой конфиг:
srv1# kill -HUP `sed q /var/run/sshd.pid`
Далее разрешаем прохождение пакетов на используемых туннельных
псевдоустройствах [2]tun(4) (на tun0 у меня висит OpenVPN, tun1 - для
OpenSSH):
srv1# vi /etc/pf.conf
pass quick on { tun0, tun1 } inet all
Загружаем правила из конфига:
srv1# pfctl -f /etc/pf.conf
Создаем интерфейс tun1 и назначаем ему IP-адрес:
srv1# ifconfig tun1 create
srv1# ifconfig tun1 10.0.0.1 10.0.0.2 netmask 255.255.255.252
При помощи команды [3]ifconfig(8) проверяем его состояние:
srv1% ifconfig tun1
tun1: flags=51<UP,POINTOPOINT,RUNNING> mtu 1500
groups: tun
inet 10.0.0.1 --> 10.0.0.2 netmask 255.255.255.252
Не забываем добавить в таблицу маршрутизации удаленную подсеть:
srv1# route add 192.168.1.0/24 10.0.0.2
Второй сервер выступает в роли SSH-клиента, поэтому процедура
конфигурирования здесь чуть проще:
srv2# echo 'Tunnel point-to-point' >> /etc/ssh/ssh_config
Остальные настройки и действия практически идентичны описанным выше:
правим и активируем рулесеты файервола, поднимаем tun1, присваиваем ему
сетевой адрес (обратите внимание, порядок следования IP-адресов
изменен) и добавляем статический маршрут:
srv2# vi /etc/pf.conf
pass quick on { tun0, tun1 } inet all
srv2# pfctl -f /etc/pf.conf
srv2# ifconfig tun1 create
srv2# ifconfig tun1 10.0.0.2 10.0.0.1 netmask 255.255.255.252
srv2# route add 192.168.2.0/24 10.0.0.1
И, наконец, самый ответственный момент: устанавливаем защищенное
соединение между двумя сетями:
srv2# ssh -f -w 1:1 212.34.XX.YY true
Чтобы снизить накладные расходы, к списку аргументов имеет смысл
добавить ключи "-o Compression=yes -x -a -n" (сжимать передаваемые
данные, отключить пересылку пакетов X11, запретить аутентификацию с
помощью агента и направить /dev/null на стандартный входной поток
stdin(4)). Теперь проверим доступность удаленного узла, находящегося
"за первым сервером":
srv2% ping 192.168.2.101
PING 192.168.2.101 (192.168.2.101): 56 data bytes
64 bytes from 192.168.2.101: icmp_seq=0 ttl=127 time=2.508 ms
Если все ОК, можно дальше развивать предложенную схему, упрощая или,
наоборот, усложняя настройки. Например, применить беспарольную
аутентификацию на базе ключей, создать конфигурационный файл для
автоматического создания псевдоустройства tun1:
srv2# echo '10.0.0.2 10.0.0.1 netmask 255.255.255.252' > /etc/hostname.tun1
Занести необходимые статические маршруты и запуск "ssh -f -w" в один из
сценариев начальной загрузки (/etc/rc.local) или в отдельный скрипт,
чтобы все выполнялось одной командой, без дополнительных телодвижений.
Чтобы использовать OpenSSH на уровне OSI 2, в качестве значения
директив PermitTunnel и Tunnel следует использовать ethernet, а затем
объединить в мост внешний сетевой интерфейс и псевдоустройство tunX
Стоит отметить, с помощью OpenSSH возможно построение не только
Site-to-Site VPN (межсайтовое подключение, в котором два маршрутизатора
создают туннель в интернете), но и Client-to-Site (VPN-подключение
удаленного доступа для проводных и беспроводных клиентов).