
Привет, Хабр!
Сегодня мы предлагаем погрузиться во внутреннюю кухню протокола SSH, заострив особое внимание на его интеграции с доменом FreeIPA. Настройка такого взаимодействия будет интересна администраторам, привыкшим к централизованному управлению Windows-серверами и рабочими местами, входящими в состав MS AD. Развитие нашей продуктовой линейки включает глубокий анализ технологического стека, и мы хотим поделиться с читателями результатами своих исследований.
Как известно, время — деньги, поэтому инженеры стараются настраивать удаленный доступ везде, где только можно, чтобы ничего не администрировать ногами.
Безопасное удаленное подключение
В инфраструктуре Microsoft удаленное управление хостами возможно по протоколу WinRM (англ. Windows Remote Management), который пересылает данные по HTTP в виде объектов SOAP (англ. Simple Object Access Protocol), для чего на удаленном компьютере на портах 5985/TCP (HTTP) и 5986/TCP (HTTPS) запускается одноименная веб-служба. Для проверки аутентичности пользователей протокол WinRM предлагает широкий перечень механизмов аутентификации. В домене MS AD по умолчанию используется Kerberos, что позволяет не только не пересылать учетные данные, но и обеспечить шифрование GSSAPI, что актуально, когда обмен информацией выполняется по небезопасному протоколу HTTP.
Через протокол WinRM работают почти все известные инструменты автоматизации: например, оснастки RSAT (англ. Remote Server Administration Tools) используют технологию PSRemoting, которая позволяет через WinRM запускать удаленную сессию PowerShell (см. командлет Enter-PSSession) или выполнять на удаленных хостах отдельные командлеты (см. параметр ComputerName). Через WinRM работает утилита командной строки winrs.exe (англ. Windows Remote Shell), инструмент автоматизации Ansible, коннектор системы мониторинга Zabbix и другие приложения.
В операционной системе Linux аналогичным протоколом удаленного доступа является SSH (англ. Secure Shell — безопасная оболочка), который появился задолго до WinRM. Протокол SSH позволяет не только выполнять удаленное управление операционной системой, но и туннелировать TCP-соединения, предоставляя шифрованный канал связи для небезопасных протоколов, передающих данные в открытом виде. Этот протокол был разработан в 1995 году на замену зоопарку протоколов администрирования, использовавшихся в то время: Telnet, FTP, Rlogin и RSH, которые уже не удовлетворяли требованиям по функциональности и безопасности. Протокол SSH работает через порт 22/TCP, и в основе его безопасности лежит алгоритм Диффи-Хеллмана, который позволяет согласовать общий секретный ключ, используя незащищенный канал связи.

Согласование ключа для симметричного шифрования
Рассмотрим процесс согласования ключа шифрования при подключении по SSH в упрощенном виде, опуская несущественные детали (рис. 1).

На шаге #1 и #2 происходит обмен идентификационными строками (identification string exchange), что позволяет определить совместимость клиента и сервера. Идентификационная строка имеет формат «SSH-2.0-OpenSSH_7.4p1 Debian-10+deb9u6astra6se5», где:
SSH — указывает на то, что используется протокол SSH;
2.0 — определяет версию протокола (protoversion);
OpenSSH_7.4p1 — версия программного обеспечения (softwareversion);
Пробел — символ разделителя;
Debian-10+deb9u6astra6se5 — дополнительная информация.
На шаге #3 и #4 происходит процесс согласования параметров алгоритма Диффи-Хеллмана. В ходе согласования клиент и сервер договариваются о том, какие значения чисел p (prime number) и g (generator) следует использовать. Эти числа могут быть перехвачены злоумышленником, но это не позволит ему узнать ключ, с помощью которого будет выполняться последующее шифрование. Для демонстрации логики расчетов возьмем числа p = 23 и g = 5 (рис. 2).

На шаге #5 клиент генерирует случайное число а, рассчитывает на его основе открытое число е и пересылает его на сервер. Число е рассчитывается по формуле е = gamod p, где mod — это операция деления по модулю, которая возвращает остаток от деления. Допустим, число a = 6, тогда e = 56 mod 23 = 8.
На шаге #6 сервер в свою очередь генерирует случайное число b, рассчитывает на его основе открытое число f и пересылает его клиенту. Число f рассчитывается по формуле f = gbmod p. Допустим, число b = 7, тогда f = 57 mod 23 = 17.
В сообщении от сервера содержится флаг New Keys, который указывает на то, что сервер рассчитал общий ключ K по формуле:
K = ebmod p = (gamod p)bmod p = gabmod p,
поэтому готов переключиться на шифрованный обмен сообщениями. В нашем случае K = 87mod 23 = 12.
На шаге #7 клиент аналогично рассчитывает ключ:
K = famod p = (gbmod p)amod p = gabmod p
В нашем случае K = 176mod 23 = 12.
Таким образом, клиент и сервер располагают теперь общим ключом K = 12 для выполнения симметричного шифрования.
Проверка сервера с помощью цифровых подписей
Несмотря на то, что злоумышленник не сможет вычислить симметричный ключ, даже если ему будут известны параметры алгоритма, которые передаются по незащищенному каналу связи или являются общеизвестными, алгоритм Диффи-Хеллмана уязвим к MITM-атакам (англ. Man in the middle — человек посередине). Злоумышленник может представиться клиенту сервером, а серверу — клиентом, согласовать с каждой из сторон отдельный симметричный ключ шифрования и получить доступ к пакетам в открытом виде, пропуская весь трафик через себя (рис. 3).

Для устранения указанной проблемы в протоколе SSH используются цифровые подписи. У каждого сервера есть пара ключей асимметричного шифрования, которые он использует следующим образом: при передаче клиенту открытого числа f на шаге #6 сервер прикладывает к нему свой открытый ключ (атрибут KEX host key) и цифровую подпись (атрибут KEX H signature), созданную с помощью закрытого ключа, чтобы клиент мог удостовериться, что сервер является тем, за кого себя выдает (рис. 4). В момент первого подключения к SSH-серверу пользователю нужно проверить отпечаток открытого ключа сервера и подтвердить возможность его использования. В этом случае открытый ключ будет внесен в файл known_hosts (сервер будет считаться доверенным), и все последующие соединения будут установлены без дополнительных запросов.

Проверять открытые ключи вручную крайне не удобно, поэтому для управления базой known_hosts администраторы всегда использовали различные инструменты автоматизации, а со временем появились такие технологии, как SSHFP-записи в DNS и поддержка сертификатов для SSH-ключей (см. параметр HostCertificate). Мы расскажем о тех механизмах, которые доступны в домене FreeIPA из коробки.
Проверка SSH-ключа сервера в домене через SSSD
В домене FreeIPA доверие между хостами при использовании протокола SSH обеспечивается автоматически за счет интеграции с утилитой ssh и службой sshd.
Как мы знаем, при установке пакета openssh-server в папке /etc/ssh/ создается несколько пар ключей асимметричного шифрования:
admin@dc-1:~$ ls /etc/ssh/ssh_host_*
/etc/ssh/ssh_host_ecdsa_key /etc/ssh/ssh_host_ecdsa_key.pub /etc/ssh/ssh_host_ed25519_key /etc/ssh/ssh_host_ed25519_key.pub /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_rsa_key.pub
В момент присоединения компьютера к домену с помощью утилиты ipa-client-install открытые ключи записываются в атрибуты ipaSshPubKey учетной записи компьютера:
admin@dc-1:~$ ipa host-show dc-1.ald.company.lan
Имя узла: dc-1.ald.company.lan
Имя учётной записи: host/dc-1.ald.company.lan@ALD.COMPANY.LAN
Псевдоним учётной записи: host/dc-1.ald.company.lan@ALD.COMPANY.LAN
Отпечаток открытого ключа SSH: SHA256:97WruOw+taXFGL7/0y8+G3iWhYCAVwKW4lrKvT3VikU root@dc-1.ald.company.lan (ecdsa-sha2-nistp256),
SHA256:MnGMk7JDBgAcIFWJAi3mhL86azD2yX2gBjgzIHP46vo root@dc-1.ald.company.lan (ssh-ed25519),
SHA256:mP7/rQg9sBrFNJZIb/psCdfJM4D2Vyf5oyY6Ef3rDEQ root@dc-1.ald.company.lan (ssh-rsa)
Link to department: ou=ald.company.lan,cn=orgunits,cn=accounts,dc=ald,dc=company,dc=lan
Пароль: False
Участник групп узлов: ipaservers
Таблица ключей: True
Managed by: dc-1.ald.company.lan
При клонировании виртуальной машины SSH-ключи можно перегенерировать с помощью утилиты ssh-keygen:
sudo rm -fv /etc/ssh/ssh_host_*
sudo ssh-keygen -A -v
Если ключи были сгенерированы для хоста, который уже присоединен к домену, новые SSH-ключи можно записать в LDAP-каталог через веб-интерфейс портала управления или с помощью следующих команд:
sudo kinit -kt /etc/krb5.keytab
ipa host-mod $(hostname) \
--sshpubkey="$(cat /etc/ssh/ssh_host_ecdsa_key.pub)" \
--sshpubkey="$(cat /etc/ssh/ssh_host_ed25519_key.pub)" \
--sshpubkey="$(cat /etc/ssh/ssh_host_rsa_key.pub)"
На стороне SSH-клиента в момент присоединения компьютера к домену в конфигурационном файле /etc/ssh/ssh_config настраиваются директивы ProxyCommand и GlobalKnownHostsFile, которые обеспечивают извлечение публичных ключей сервера из службы каталога в момент инициализации SSH-сессии:
$ cat /etc/ssh/ssh_config
...
ProxyCommand /usr/bin/sss_ssh_knownhostsproxy -p %p %h
GlobalKnownHostsFile /var/lib/sss/pubconf/known_hosts
...
, где:
директива ProxyCommand определяет команду, которую нужно запускать в дочернем процессе для подключения к удаленному серверу. Дальнейшая передача данных между родительским процессом ssh и дочерним процессом, который запускается в соответствии со значением ProxyCommand, осуществляется через стандартные потоки stdin/stdout;
директива GlobalKnownHostsFile указывает, что утилите ssh следует использовать файл known_hosts от службы SSSD. Директива позволяет указывать несколько значений через пробел, поэтому при необходимости вы можете добавить /etc/ssh/ssh_known_hosts и любые другие файлы.
Обычно в качестве ProxyCommand используют ту же утилиту ssh с параметрами для подключения к бастион-серверу, но в нашем случае мы используем утилиту sss_ssh_knownhostsproxy из пакета sssd-common, которая обеспечивает интеграцию со службой SSSD.
Утилита sss_ssh_knownhostsproxy извлекает публичный SSH-ключ хоста, указанного в параметре %h, из атрибута ipaSshPubKey учетной записи компьютера через службу SSSD и сохраняет его в формате known_hosts в специальный файл /var/lib/sss/pubconf/known_hosts. Далее sss_ssh_knownhostsproxy выполняет только проксирование стандартных потоков stdin/stdout, а всю остальную работу берет на себя родительский процесс ssh.
Таким образом, в домене FreeIPA возможность MITM-атак при использовании протокола SSH сведена к минимуму и пользователю не приходится проверять отпечатки SSH-ключей вручную.
Проверка SSH-ключа сервера через DNS
Если пользователь подключается к серверу по протоколу SSH с компьютера, который не является участником домена, или с использованием иных приложений, отличных от утилиты ssh, то описанные в предыдущем разделе механизмы безопасности не сработают, и пользователю потребуется самостоятельно принимать решение о доверии к серверу. Вместе с тем служба каталога FreeIPA реализует еще один механизм подтверждения открытых ключей сервера — через DNS с помощью SSHFP-записей.
Как мы уже знаем, в момент присоединения компьютера к домену с помощью клиента freeipa открытые ключи записываются в атрибуты ipaSshPubKey
учетной записи компьютера. Однако при создании атрибута ipaSshPubKey
служба каталога FreeIPA автоматически генерирует на основе этого открытого ключа отпечаток (fingerprint) и записывает его в SSHFP-запись для этого имени хоста. Это дает возможность клиенту автоматически проверить публичный ключ сервера через DNS в момент первого подключения и сразу добавить его в known_hosts. Для возможности использования этой функции в конфигурационном файле /etc/ssh/ssh_config нужно включить параметр VerifyHostKeyDNS, который по умолчанию выключен:
cat /etc/ssh/ssh_config
...
VerifyHostKeyDNS yes
...
Если отпечаток хоста будет представлен среди SSHFP-записей и на DNS-сервере будет корректно настроен DNSSEC, то добавление ключа в known_hosts произойдет автоматически.
Если же DNSSEC не настроен, то пользователь получит уведомление вида «Matching host key fingerprint found in DNS» (Соответствующий отпечаток ключа хоста найден в DNS).
Если ключа не окажется в DNS, то сообщение примет вид «No matching host key fingerprint found in DNS» (Соответствующий отпечаток ключа хоста не найден в DNS).
Методы аутентификации пользователей
Инструменты удаленного доступа OpenSSH поддерживают сразу несколько методов аутентификации, порядок которых определяется директивой PreferredAuthentications из конфигурационного файла клиента /etc/ssh/ssh_config. По умолчанию на хостах в домене эта директива не задана, поэтому методы используются в следующей последовательности:
gssapi-with-mic – аутентификация через GSSAPI по протоколу Kerberos V5 с передачей кода для проверки целостности сообщений (англ. Message Integrity Code, MIC);
hostbased – подключение с рабочего места администратора без аутентификации (см. параметр HostbasedAuthentication). В домене FreeIPA этот метод не используется;
publickey – аутентификация по SSH-ключу;
keyboard-interactive – аутентификация в интерактивном режиме, при которой сервер может запросить дополнительную информацию, например, код из SMS в качестве второго фактора (см. параметры KbdInteractiveAuthentication и KbdInteractiveDevices). В домене FreeIPA этот метод не используется;
password – обычная аутентификация по паролю.
Метод аутентификации gssapi-with-mic
Если у пользователя будет действующий TGT-билет, то при подключении к доменному компьютеру по SSH он сможет выполнить прозрачную аутентификацию по протоколу Kerberos V5. Подключение лучше делать с дополнительным параметром -K (Kerberos), чтобы утилита ssh выписала еще один TGT-билет и переслала его на SSH-сервер, иначе из удаленной сессии вы не сможете выполнять прозрачную аутентификацию при обращении к керберизированным сервисам.
Пример подключения с параметром -K, в удаленной сессии появился TGT-билет:
admin@pc-1:~$ ssh -K dc-1.ald.company.lan
Last login: Mon Aug 18 11:44:00 2025 from 10.0.1.51
admin@dc-1:~$ klist
Ticket cache: FILE:/tmp/krb5cc_959800000_oPElFMadwL
Default principal: admin@ALD.COMPANY.LAN
Valid starting Expires Service principal
18.08.2025 11:44:06 19.08.2025 11:37:14 krbtgt/ALD.COMPANY.LAN@ALD.COMPANY.LAN
Пример подключения без параметра -K, в удаленной сессии нет TGT-билета:
admin@pc-1:~$ ssh dc-1.ald.company.lan
Last login: Mon Aug 18 11:39:59 2025 from 10.0.1.51
admin@dc-1:~$ klist
klist: Credentials cache keyring 'persistent:959800000:krb_ccache_z43Etx2' not found
Метод аутентификации publickey
При отсутствии действующего TGT-билета в связке ключей утилита ssh попытается выполнить аутентификацию пользователя по SSH-ключу из домашней директории. Для возможности использования этого метода аутентификации пользователю достаточно сгенерировать ключевую пару утилитой ssh-keygen и записать открытую часть ключа в атрибут ipaSshPubKey своей учетной записи.
По умолчанию утилита ssh-keygen сохраняет файлы в правильном каталоге ~/.ssh/, закрытый ключ будет называться id_rsa, а открытый id_rsa.pub. С помощью параметра -C в файл открытого ключа можно добавить комментарий с именем пользователя, которому принадлежит эта ключевая пара:
ssh-keygen -C admin@ald.company.lan
Новый SSH-ключ нужно будет записать в LDAP-каталог, что можно сделать через личный кабинет портала управления или с помощью следующих команд:
kinit admin
ipa user-mod admin \
--sshpubkey="$(cat /home/admin/.ssh/id_rsa.pub)"
Как уже было сказано ранее, для подключения к серверу по SSH-ключу у пользователя не должно быть действующего TGT-билета. Для очистки связки билетов воспользуемся командой kdestroy:
kdestroy
ssh dc-1.ald.company.lan
При необходимости вы можете явно выбрать аутентификацию по SSH-ключу с помощью опции PreferredAuthentications:
ssh -o PreferredAuthentications=publickey dc-1.ald.company.local
Если закрытый ключ будет находиться в другом каталоге, то указать полный путь к этому файлу можно будет с помощью параметра -i:
mv /home/admin/.ssh/* /home/admin/
ssh -o PreferredAuthentications=publickey -i /home/admin/id_rsa dc-1.ald.company.lan
На стороне SSH-сервера проверка SSH-ключей пользователей выполняется через утилиту, указанную в директиве AuthorizedKeysCommand конфигурационного файла /etc/ssh/sshd_config:
cat /etc/ssh/sshd_config
…
AuthorizedKeysCommand /usr/bin/sss_ssh_authorizedkeys
AuthorizedKeysCommandUser nobody
...
, где:
директива AuthorizedKeysCommand определяет полный путь к утилите, с помощью которой будет выполняться поиск открытых ключей пользователей. Если дополнительные аргументы не указаны, то будет подставлено имя пользователя, который выполняет подключение к серверу;
директива AuthorizedKeysCommandUser определяет пользователя, от имени которого будет запускаться приложение, указанное в директиве AuthorizedKeysCommand. Рекомендуется указывать пользователя, не имеющего на хосте никаких других ролей.
В директиве AuthorizedKeysCommand указывается утилита sss_ssh_authorizedkeys из состава пакета sssd-common, которая обеспечивает интеграцию со службой SSSD. Утилита извлекает публичный SSH-ключ из атрибута ipaSshPubKey учетной записи пользователя через службу SSSD и выводит его в формате authorized_keys OpenSSH. Для проверки аутентичности пользователя сервер направляет клиенту challenge-запрос, зашифрованный публичным ключом клиента. Клиент его расшифровывает с помощью закрытого ключа и отсылает challenge-ответ, тем самым подтвердив аутентичность.
Для использования утилиты не требуется повышенных привилегий, поэтому вы можете с ее помощью проверить ключ любого пользователя:
$ sss_ssh_authorizedkeys admin
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDvo+JcniK2F6ebV0A0zvTW/+AYG0mLFxeCIbSHEi5u6OhmH+bnqUR0ugzWsAC9JQ8s0Kk1qZPRAb7NzG/cLVfD7zklG7juVnbTg9hREd930yMC6Zm+Q6reVLBKRGqVN/qc/Vjizb+XkmxMAy4BEiviVlMbwZS+LzBd5ARRpk18h2wgs/MeI74K2ZZvinFx7iO7OsBJiPGQPnboK1xjHDG/Y3ktEdiqRLHo89ICbXfaV5M1FQoO/ihR9CtACUKiKKgebSzpQenoJKdNP7mHI7DoaDvPV/DBWnFnX6v6MeOlPkhuijpPpMAxGMpXdqyUPgZQ4VC17wHpQ97I7HxQRFyH admin@ald.company.lan
Метод аутентификации password
Если у пользователя в связке ключей не будет действующего TGT-билета, а в директории ~/.ssh/ не будет SSH-ключа, то утилита ssh предложит ввести пароль:
admin@pc-1:~$ kdestroy -A
admin@pc-1:~$ mv /home/admin/.ssh/* /home/admin/
admin@pc-1:~$ ssh dc-1.ald.company.lan
Password:
Last login: Mon Aug 18 11:44:06 2025 from 10.0.1.51
При необходимости вы можете явно выбрать аутентификацию по паролю с помощью опции PreferredAuthentications следующим образом:
ssh -o PreferredAuthentications=password dc-1.ald.company.local
При использовании этого метода аутентификации утилита пересылает пароль на SSH-сервер открытым текстом (по шифрованному каналу, конечно), и проверка аутентичности выполняется точно так же, как при обычном интерактивном входе в консоль или графический интерфейс. Поэтому в связке ключей будет доступен TGT-билет, с помощью которого пользователь сможет проходить прозрачную Kerberos-аутентификацию при обращении к керберизированным сервисам:
admin@pc-1:~$ ssh -o PreferredAuthentications=password dc-1.ald.company.lan
admin@dc-1.ald.company.lan's password:
Last login: Mon Aug 18 19:18:09 2025 from 10.0.1.51
admin@dc-1:~$ klist
Ticket cache: KEYRING:persistent:959800000:krb_ccache_1sIwfob
Default principal: admin@ALD.COMPANY.LAN
Valid starting Expires Service principal
18.08.2025 19:18:25 19.08.2025 19:18:25 krbtgt/ALD.COMPANY.LAN@ALD.COMPANY.LAN
Следует понимать, что аутентификация по паролю считается недостаточно безопасной, поэтому использование этого метода в домене рекомендуется свести к минимуму. При аутентификации таким способом текст пароля пересылается на SSH-сервер пусть и по шифрованному каналу, но все-таки в открытом виде, поэтому подключение к скомпрометированной машине, на которой запущена модифицированная служба sshd, может привести к компрометации пароля администратора.
Таким образом, использование SSH в связке с доменными службами FreeIPA позволяет значительно повысить удобство и безопасность администрирования Linux-систем. В статье мы постарались раскрыть процессы взаимодействия данных технологий, в том числе с точки зрения информационной безопасности, и мы уверены в том, что их совместные возможности позволяют даже заядлым Windows-администраторам с интересом взглянуть в сторону ОС Linux.