Введение
Начиная с верcии 1803
, в Windows 10
доступны SSH
клиент и SSH
сервер, причём, SSH
клиент установлен и готов к использованию, как говорится, прямо из коробки, а SSH
сервер надо устанавливать, но делается это буквально в пару-тройку кликов мышкой[1]. Что это означает? С точки зрения клиента можно говорить о том, что сторонние программы, такие как PuTTY
, вроде как больше не нужны. С точки зрения сервера - не надо устанавливать никакие сторонние серверы, если есть решение интегрированное.
В работе что клиент, что сервер, практически не отличаются от того ПО, к которому я привык в Debian
. Но, как ни крути, есть некоторые отличия, и вот об одном из них попробую сейчас рассказать. Речь пойдет о подключении к SSH
серверу, работающему на Windows
, с клиента, в моем случае, работающего на Debian Jessie
, причем, без использования пароля, то есть, задействуя ключи.
На самом деле, начало процесса не отличается от стандартного: если у вас нет набора ключей, вам его надо сгенерировать, если есть - используйте существующий. Речь сейчас идёт о той машине, которая будет клиентом. И я уже как-то писал об этом, но на некоторых моментах всё-таки остановлюсь ещё раз: повторенье - мать ученья 😉.
Про генерацию ключей
Итак, если ключей нет и вы работаете на системе под управлением Linux
, то вот эта команда поможет вам их сгенерировать:
ssh-keygen -t rsa
Если же вы работаете под Windows
, то у вас есть несколько возможностей сгенерировать ключи:
- Если вы работаете под
Windows 10
и включили возможность использовать встроенныйSSH
клиент, то смело используйте командуssh-keygen
- должно сработать... 🙄😉 - Если вы работаете под
Windows 10
и включили возможность использовать WSL, то можете воспользоваться возможностями этой подсистемы, то есть, использовать в ней... всё ту же командуssh-keygen
. - Если вы работаете под
Windows 10
и у вас не установлен встроенныйSSH
клиент и не включена возможность использованияWSL
, или же у вас более ранняя версияWindows
, то придется использовать стороннее ПО, тот же PuTTY с его генераторомPuTTYgen
- для этого случая есть достаточно подробная документация.
Если пара ключей успешно сгенерирована, или уже была у вас, то необходимо "доставить" публичный ключ на сервер и там сделать его доступным для использования SSH
сервером. И вот тут то и начинаются отличия от обычного - для мира Linux
- процесса.
Доставка публичного ключа на сервер Linux
Что я делал, когда мне надо было "доставить" ключ на SSH
сервер, работающий на Linux
? Всё очень просто - запуск следующей команды на клиентской машине решал все вопросы:
ssh-copy-id user_name@server_name_or_ip
где user_name - имя пользователя, ключ которого передаётся на сервер, а server_name_or_ip - имя или адрес хоста с сервером SSH
, к которому есть желание подключаться без ввода пароля (от имени пользователя с ключом). Иногда команда не работала и приходилось явно указывать файл (при помощи параметра командной строки -i
), в котором хранился публичный ключ, но это, в большей степени, зависело от устройства, на котором выполнялась эта команда, вернее, от версии ОС, ну и от реализации и версии криптографического ПО, конечно.
Доставка публичного ключа на сервер Windows
Но, в случае, когда в качестве сервера выступает машина с Windows
, этот приём не прокатывает - ключ не передаётся на нужный хост и всё. Не знаю, эксперименты эти я проводил довольно давно, может, в новых версиях Windows
эту "особенность" исправили, а может и нет. В любом случае, тогда мне пришлось искать обходной путь.
Собственно, сам этот путь очевиден - раз не получается сделать передачу ключа автоматом, надо всё выполнить вручную. А для этого необходимо знать, где и как Windows
хранит публичные ключи, используемые SSH
сервером для аутентификации клиентов. К счастью, в документации Microsoft
есть необходимая информация и её надо просто использовать. Давайте её детально разберём, при том держа в уме, что документация предполагает работу с клиентской машины под управлением Windows
с заранее настроенным доступом по SSH
к необходимому серверу.
Создание каталога для хранения ключей
Итак, из документации становится очевидно, что Windows
хранит пользовательские ключи, используя тот же принцип, что и Linux
: на сервере в файле authorized_keys
в подкаталоге .ssh
домашнего каталога пользователя (а это, как правило, c:\Users\user_name
, где user_name - имя пользователя), от имени которого вы хотите работать в установившемся SSH
сеансе. Если этого каталога нет, его надо создать, для чего предлагается использовать команду:
ssh user_name@domain_name@host_name "mkdir C:\\users\\user_name\\.ssh\\"
где user_name - имя пользователя, domain_name - имя домена, в который входит пользователь (его можно опустить для локальных пользователей на удалённом сервере), host_name - имя или адрес хоста, к которому подключаемся. Приведённая мною команда несколько отличается от той, которая дана в документации, но следует помнить, что я работаю с клиентской машины под управлением Linux
.
Копирование публичного ключа
Далее, предлагается скопировать во вновь созданный каталог файл с публичным ключом пользователя, от имени которого вы работаете на клиентской машине при подключении к серверу по SSH
(команда слегка отличается от той, которая приведена в документации, так как я работаю с машины под управлением Debian
):
scp ~/.ssh/public_key_file_name.pub user_name@domain_name@host_name:C:\Users\user_name\.ssh\authorized_keys
где public_key_file_name.pub - имя файла публичного ключа, например, id_ed25519.pub
или id_rsa.pub
(далее в примерах я буду использовать для простоты id_rsa.pub
).
На этом моменте хотелось бы остановиться подробнее. Обычно вы работаете на своём компьютере (или виртуалке) под своим собственным пользователем. Когда вы подключаетесь к удалённой машине по SSH
, вы можете подключаться под именем своего текущего пользователя локальной машины, или использовать имя какого-либо пользователя удалённого компьютера, или же - доменное имя. Конечно, в любом случае на удалённом хосте должен существовать соответствующий пользователь (или разрешено использовать доменное имя), даже если его имя будет совпадать с именем пользователя, под которым вы работаете на своём локальном хосте. Так вот, совсем не обязательно, что вы единственный подключаетесь к удалённому хосту под определенным пользователем, вполне возможно, что с других хостов другие люди (или вы сами?) также подключаются по SSH
, используя ту же самую учётную запись.
Возможно то, что я написал выше, это "ужас-ужас" с точки зрения безопасности, но такая ситуация весьма вероятна в домашних и небольших офисных сетях (да и не только 🙁), в которых не сильно заморачиваются с администрированием. И вот в таких случаях, копировать файл со своим публичным ключом - плохая идея: вы просто затрёте существующий файл authorized_keys
с публичными ключами других пользователей (или ваших собственных ключей на других компьютерах - вряд ли вы переносите свою единственную пару ключей с хоста на хост 😉). Поэтому следует рассмотреть возможность добавлять свой ключ к соответствующему файлу на удалённом хосте.
Добавление публичного ключа
Естественно, возникает вопрос, как это можно сделать. И на этот вопрос существует множество ответов. Например, если у вас есть доступ к удалённому хосту по RDP
, то можно отредактировать на нём файл authorized_keys
с помощью того же notepad
-а, добавив содержимое своего файла с публичным ключом. Или же, можно скопировать свой файл с публичным ключом на нужный сервер и объединить его с существующим файлом, а затем - удалить (конечно, при этом у вас, вернее, у вашего пользователя на удалённом компьютере, должны быть права на редактирование файла authorized_keys
):
scp ~/.ssh/id_rsa.pub user_name@domain_name@host_name:C:/Users/user_name/.ssh/my_public_key_file_name.pub
ssh user_name@domain_name@host_name "type C:\\Users\\user_name\\.ssh\\my_public_key_file_name.pub >> C:\\Users\\user_name\\.ssh\\authorized_keys"
ssh user_name@domain_name@host_name "del /Q C:\\Users\\user_name\\.ssh\\my_public_key_file_name.pub"
Обратите внимание на использование символов '/' в команде scp
и '\' в командах ssh
- так как мы работаем на Debian
, то в команду scp
можно передать путь на хосте с Windows
с использованием нестандартного для Windows
разделителя '/', а вот в команды, выполняемые при помощи ssh
на том же удалённом компьютере, следует передавать символы '\',то есть, стандартный для Windows
разделитель '\' с предшествующим символом '\', так называемый "escaped backslash", иначе Windows
не найдёт нужные файлы.
Назначение прав доступа к файлу с публичными ключами
Вот мы и подошли к последнему шагу - предоставлению прав доступа к файлу authorized_keys
. Именно этим занимается команда:
ssh --% user_name@domain_name@host_name powershell -c $ConfirmPreference = 'None'; Repair-AuthorizedKeyPermission C:\Users\user_name\.ssh\authorized_keys
Основную смысловую нагрузку в этой составной команде несёт функция Repair-AuthorizedKeyPermission
из модуля OpenSSHUtils
для PowerShell
(да, именно PowerShell
используется в качестве командной оболочки в этот раз). Этот модуль надо устанавливать отдельно, например, так (выполнять эту команду надо, естественно, из PowerShell
):
Install-Module -Force OpenSSHUtils -Scope AllUsers
Так вот, когда я запустил эту команду, ответом мне стало сообщение об ошибке:
Совпадения для указанных условий поиска и имени пакета "OpenSSHUtils" не найдены.
Естествено, я начал разбираться в сложившейся ситуации, после чего, если честно, желание использовать этот модуль у меня стало исчезающе малым.
Суть в том, что Windows 10
предъявляет определённые требования к безопасности файла authorized_keys
(на самом деле, к безопасности публичных ключей). Причины, по которым это происходит, наверное, не надо объяснять. Так вот, в документации Microsoft
указывается, что при использовании Windows 10
доступ может быть предоставлен только администаторам и специальному пользователю SYSTEM
. Там же советуется использовать модуль OpenSSHUtils
, который должен оказать помощь при установке нужных прав. Собственно, при использовании предложенного в документации подхода я и наткнулся на ошибку. Но кроме документации от Microsoft
я нашёл довольно много информации о проблемах, вызванных использованием этого модуля. Если попробовать кратко изложить содержимое ответов на возникающие у пользователей вопросы и проблемы, то получится что-то типа:
"Не используйте этот модуль, он дополнительно предоставит права пользователю
sshd
, после чего у вас перестанут соблюдаться требования к безопасности публичных ключей."
Вот честно, не знаю, так это, или нет, но проверять расхотелось, тем более, что совсем не трудно задать нужные права самостоятельно. После некоторого изучения вопроса - я не большой специалист в PowerShell
- получился вот такой вот набор команд[2] (я приведу их полностью, потом разберу для чего нужна каждая из них):
$acl = Get-Acl C:\Users\user_name\.ssh\authorized_keys
$acl.SetAccessRuleProtection($true, $false)
$adminsRule = New-Object system.security.accesscontrol.filesystemaccessrule("Администраторы","FullControl","Allow")
$sysRule = New-Object system.security.accesscontrol.filesystemaccessrule("SYSTEM","FullControl","Allow")
$acl.SetAccessRule($adminsRule)
$acl.SetAccessRule($sysRule)
Set-Acl -Path C:\Users\user_name\.ssh\authorized_keys -AclObject $acl
Теперь, как и обещал, небольшие пояснения по командам. Итак, для начала, при помощи cmdlet
-а Get-Acl получаем дескриптор безопасности, содержащий ACL
(Access Control List) нужного нам объекта файловой системы (параметр командной строки Path
можно опустить) и сохраняем результат в переменной $acl
. Далее, используя метод SetAccessRuleProtection полученного объекта, запрещаем наследование прав (true
в первом параметре) и отказываемся от сохранения унаследованных ранее прав (false
во втором параметре). Затем создаём два объекта, описывающих правила доступа к объектам файловой системы: один (сохраняется в переменной $adminsRule
) - для Администраторов, второй (сохраняется в переменной $sysRule
) - для специального пользователя SYSTEM
. Теперь, при помощи метода SetAccessRule, добавляем только что соданные ACL
к дескриптору безопасности нашего файла, хранящегося в переменной $acl
. После чего, всё, что нам остаётся сделать - применить полученный дескриптор, для чего используем cmdlet
Set-Acl.
Ну вот, теперь, когда мы выполнили все шаги, всё должно заработать. Но, в моём случае, не заработало. Очередная неудача заставила меня вновь полезть в документацию, что обогатило меня новыми знаниями. Рассказываю...
Публичные ключи для работы от имени пользователей администраторов
Причиной того, что при соединении с SSH
сервером мне, несмотря на все предыдущие мытарства, продолжало выводиться требование ввести пароль, было то, что я пытался подключиться под пользователем, который входил в группу локальных Администраторов. У Windows 10
в этом случае есть требование - публичные ключи должны храниться в файле %programdata%/ssh/administrators_authorized_keys
, то есть, обычно, в C:\ProgramData\ssh\administrators_authorized_keys
.
Что ж, для того, чтобы решить проблему, можно воспользоваться двумя путями. Первый путь - воспользоваться процедурой добавления публичного ключа, рассмотренной нами выше. Да-да, все эти шаги: копирование, добавление, предоставление прав, только применяем их не к authorized_keys
, а к administrators_authorized_keys
. Я напишу, на всякий случай, полную последовательность команд, чтобы удобно было воспользоваться, но не забудьте подставить свои значения для пользователя, домена и хоста.
scp ~/.ssh/id_rsa.pub user_name@domain_name@host_name:C:/Users/user_name/.ssh/my_public_key_file_name.pub
ssh user_name@domain_name@host_name "type C:\\Users\\user_name\\.ssh\\my_public_key_file_name.pub >> C:\\ProgramData\\ssh\\administrators_authorized_keys"
ssh user_name@domain_name@host_name "del /Q C:\\Users\\user_name\\.ssh\\my_public_key_file_name.pub"
$acl = Get-Acl C:\ProgramData\ssh\administrators_authorized_keys
$acl.SetAccessRuleProtection($true, $false)
$adminsRule = New-Object system.security.accesscontrol.filesystemaccessrule("Администраторы","FullControl","Allow")
$sysRule = New-Object system.security.accesscontrol.filesystemaccessrule("SYSTEM","FullControl","Allow")
$acl.SetAccessRule($adminsRule)
$acl.SetAccessRule($sysRule)
Set-Acl -Path C:\ProgramData\ssh\administrators_authorized_keys -AclObject $acl
Второй путь чуть более радикальный - изменить настройки SSH
сервиса. Настройки эти хранятся в файле %programdata%/ssh/sshd_config
. Как оказалось, именно там определяется, где должны храниться публичные ключи тех пользователей, которые подключаются к SSH
серверу от имени пользователей, входящих в группу администраторов. Вот, собственно, эти строки:
...
Match Group administrators
AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
...
Так вот, эти строки надо закомментировать или удалить, после чего SSH
сервер надо перезапустить.
Какой путь использовать - решать вам. Я же, пожалуй, закончу - пост получился и так слишком длинным...
На самом деле, в виде beta версий эти компоненты были доступны и раньше, но и установка и стабильность работы, были, что называется, не на высоте. ↩︎
Честно признаюсь, очень многое я подсмотрел в документации, например, как отключить наследование прав, или предоставить Администраторам полный контроль над файлом, и лишь немного адаптировал эти примеры к собственным нуждам. ↩︎