Сегодня я хочу обсудить тему, которая, собственно, и вынесена в заголовок. На самом деле, по ней довольно много информации и то, как все правильно сделать - давно известно. Зачем же тогда затрагивать ее еще раз? Все очень просто: если вы такой же новичок в Linux, как и я, то вы много чего еще не знаете. Как следствие, вам (как и мне), вероятнее всего, приходится многие вещи делать впервые и, как водится, не всегда правильно. Когда же вы обращаетесь за помощью, не важно, будь то к живому человеку, или к какому-то другому источнику информации, например, в интернете, довольно часто возникает вопрос: а на каком языке они с вами общаются? Оно и понятно, ведь уровни владения предметом слишком разные. Поговорите-ка с физиком или биологом на профессиональные для них темы - уверяю вас, ощущения будут примерно такими же.

Но вернемся к проблеме. В чем, собственно, она заключается и проявляется? Мне, например, каждый раз при подключении к удаленному хосту с помощью протокола SSH приходилось вводить пароль того пользователя, от имени которого я собирался работать на том самом хосте. И ладно, если подключаться надо было пару раз за месяц - можно потерпеть! А если чаще? А если значительно чаще? Про какие-то другие возможности (кроме ввода пароля) мне в то время вообще ничего не было известно и, следовательно, правильно задать вопрос (а, народная мудрость утверждает, что в правильно заданном вопросе уже содержится 80% ответа) я, увы, не мог. И я думаю, что в таком же положении оказывается множество начинающих пользователей, если, конечно, они случайно не наткнулись на какую-нибудь нужную и понятную им информацию в интернете или же целенаправленно не изучали интересующий их предмет (в нашем случае, Linux, SSH или еще что-нибудь). Но, к сожалению, целенаправленно и обстоятельно в современном мире мало кто что-либо делает 😞. А по поводу "наткнулись", то тут действует довольно простое правило: чем больше будет информации по теме, тем быстрее она вам попадется на глаза. Так что, не обессудьте.

Итак, мне приходилось вводить пароли при подключении с использованием протокола SSH по много раз за день, особенно тогда, когда надо было что-нибудь скопировать на мои сетевые накопители MyBookLive и MyBookLiveDuo. И не важно, как я копировал - с помощью ли команды scp или в MidnightCommander-е, используя Shell-соединение, реализованное с на основе специализированного протокола Fish - и тот и другой метод опираются все на тот же SSH.

Если честно, я терпел очень долго, но, рано или поздно, любому терпению приходит конец. И когда такой момент наступил, я с головой окунулся в интернет в поисках решения (или решений). И надо сказать, что я нашел довольно много информации и разнообразных примеров. Многие из них мне даже удалось опробовать, а некоторые - прочно закрепились в моем арсенале приемов и методов работы в Linux, правда, немного для других целей. Но то - отдельные истории и когда-нибудь я их тоже расскажу.

Сейчас же относительно того, как можно избежать постоянного ввода пароля при подключении к удаленному хосту по протоколу SSH. Как это не удивительно, но к тому решению, которое мною используется сейчас, я пришел не сразу. Хотя Google выводит его в топе. А все потому, что основано оно на использовании криптографии, с которой мне (в то время) было, если честно, страшновато работать. И я, просто с каким-то маниакальным упорством, пытался найти и применить другие подходы, которые, в принципе, и можно было бы принять в качестве решения озвученной задачи, но, по большому счету, предназначались они все-таки для чего-то другого. Тем не менее, я этому своему иррациональному страху использования криптографии в какой-то мере даже признателен, так как благодаря ему узнал довольно много интересных и полезных вещей (хорошим примером может служить использование файловой системы SSHFS).

В общем, в какой-то момент мне удалось побороть страх и неуверенность и попробовать-таки использовать ключи при работе по SSH. Но прежде, чем последовать моему примеру, следует убедиться, что выполняется ряд предварительных требований, без которых предлагаемое решение работать просто не будет. На самом деле, на результате может сказаться не только то, какая компания (или автор) является производителем используемого вами ПО (стандарт - стандартом, но свои маленькие скелетики в шкафах есть практически у любого разработчика), но даже версия этого самого программного обеспечения - решение, работающее в одних условиях, может оказаться нежизнеспособным при других. В любом случае, я хотя бы попробую задать направление, в котором можно будет копать, если что-то пойдет не так. И для начала - предварительные требования:

  • на удаленном хосте должен быть установлен сервер SSH. Про то, что на вашем компьютере должно быть установлено клиентское ПО SSH, напоминать, наверное, не надо 😉?
  • вы должны иметь доступ к удаленному хосту. Не важно, что это будет: физический ли доступ с возможностью локального входа; удаленный доступ, опять же, с возможностью подконнектиться под нужным пользователем; бородатый администратор, который сможет выполнить за вас все необходимые действия - главное, чтобы был доступ.

Если эти несложные требования выполняются, то можно переходить к реализации самого решения. Суть предлагаемого подхода заключается в том, что нужно сгенерировать для линуксового пользователя, под которым вы работаете на своем компьютере, пару ключей. Я использую для этого следующую команду:

ssh-keygen -t rsa

Что надо знать про генерацию ключей? А вот что: не важно, к какому количеству хостов вы будете подключаться с помощью SSH - к одному или к десятку - вам нужен только один ключ, вернее, только одна пара ключей. Поэтому генерировать ее надо только один (первый) раз, все остальное время вы просто пользуетесь ранее сгенерированной парой ключей.

Предположим, что сейчас и есть тот самый первый раз (в противном случае, просто переходите к следующему шагу). Итак, при выполнении команды, приведенной выше, программа запросит у вас имя для файлов, в которых будут сохранены сгенерированные ключи - да, одно имя для двух файлов: имена будут одинаковыми, расширения - разными. И хотя соблазн задать имя, не совпадающее с используемым по умолчанию, может быть довольно силен, я рекомендую так не делать: впоследствии, вы сможете использовать при работе меньше дополнительных опций командной строки и/или настроек каких-либо сервисов. Если вы прислушаетесь ко мне, и оставите название, предлагаемое по умолчанию (просто нажмете Enter или Return), то в подкаталоге ~/.ssh для приватного ключа будет создан файл id_rsa (без расширения), а для публичного ключа - файл id_rsa.pub (то, что надо генерировать именно rsa ключи, было указано при помощь опции командной строки -t rsa, которую довольно часто можно просто опустить).

Второй вопрос, который задаст вам программа - указать пароль для защиты генерируемого приватного ключа. Если вы решите задать пароль, то следует помнить, что он должен содержать как минимум пять символов. Если же вы не захотите использовать пароль - просто нажмите Enter или Return.

Считается, что задание пароля позволит повысить безопасность: при установке соединения с удаленным хостом, прежде, чем использовать защищенный ключ, у вас попросят ввести пароль. Будет или нет установлено соединение зависит от того, введете ли вы правильный пароль в ответ на этот вопрос. Если же при генерации ключей вы откажетесь от определения пароля, то при установке соединения никаких вопросов задано не будет, вы просто тихо-мирно подключитесь к нужному удаленному хосту. Этот вариант удобен и именно из-за него я и затеял весь этот сыр-бор. Но он небезопасен: если кто-то получит доступ к вашей учетке на локальном компьютере, то он сможет также без проблем подключиться к любому удаленному хосту, с которым у вас настроено использование ключей для SSH соединения. Если честно, я выбрал удобство. Но это решение довольно серьезное и каждый должен принять его самостоятельно - только после оценки возможных рисков.

Итак, ключи сгенерены. Теперь требуется установить на удаленный хост публичный ключ. Я делаю это при помощи следующей команды:

ssh-copy-id -i id_rsa.pub user-name@server_name_or_ip

В этом случае я указываю файл публичного ключа, при помощи опции командной строки -i id_rsa.pub, имя пользователя (user-name), под которым должно быть произведено соединение и имя или IP адрес удаленного хоста (server_name_or_ip). Вообще, id-rsa.pub это имя файла публичного ключа, используемое по умолчанию, поэтому, в принципе, его можно опустить, в частности, если вы прислушались к моему совету не оригинальничать при генерации ключей и оставить значение имени, предлагаемое по умолчанию. Тогда команда будет выглядеть так:

ssh-copy-id user-name@server_name_or_ip

Но я должен честно предупредить - у меня, по какой-то причине, в таком виде команда иногда (на некоторых устройствах) не работала, выдавая сообщение об ошибке:

ERROR: No identities found

Я не стал разбираться, почему (пишут, что это может зависеть от установленной версии SSH), и просто стал всегда явно указывать имя файла публичного ключа.

Еще хочу отметить, что, в некоторых случаях, команда ssh-copy-id работать не будет. Такая незадача может быть связана с особенностями сервера, вернее, с особенностями учетной записи пользователя на удаленном хосте. Например, если в качестве оболочки "по умолчанию" для удаленного пользователя установлено ПО, основанное не на bash или sh, то проблемы весьма и весьма вероятны. В таких случаях можно сделать все тоже самое, только вручную:

  • копируем файл публичного ключа на удаленный сервер в домашний каталог пользователя, под которым собираемся работать на этом сервере:

    scp ~/.ssh/id_rsa.pub user_name@server_name_or_ip:
    

    вместо user_name надо подставить имя нужного пользователя (на удаленном сервере), а вместо server_name_or_ip - имя сервера или его IP адрес (символ ':' это не опечaтка, он там должен быть). У вас, конечно, спросят пароль, но тут проблем быть не должно, не правда ли? 😉

  • соедиеяемся с сервером:

    ssh user_name@server_name_or_ip
    

    вместо user_name надо подставить имя нужного пользователя (опять же, на удаленном сервере), а вместо server_name_or_ip - имя сервера или его IP адрес, и да, от запроса и ввода пароля мы пока еще не избавились.

  • создаем подкаталог .ssh и файл authorized_keys:

    mkdir -p ~/.ssh
    touch ~/.ssh/authorized_keys
    

    Если нужные объекты уже существуют, приведенные команды им не навредят. И еще. Если вы решите создать эти объекты каким-то другим способом - пожалуйста, нет никаких проблем. Важно лишь помнить, что владельцем этих объектов должен быть пользователь, под которым вы собираетесь работать на удаленном хосте, и этот пользователь должен иметь права на чтение/запись в этот файл (речь про authorized_keys).

  • записываем публичный ключ в файл authorized_keys:

    cat ~/id_rsa.pub >> ~/.ssh/authorized_keys
    

    Чтобы проверить, что все прошло нормально, и файл authorized_keys теперь содержит нужный ключ, можно воспользоваться командой:

    more ~/.ssh/authorized_keys
    

Собственно, уже с этого момента можно подключаться к серверу по протоколу SSH с использованием ключей, то есть без пароля. Но мы выполним еще пару шагов - для порядка.

  • можно удалить на сервере публичный ключ:

    rm ~/id_rsa.pub
    

    или же переместить его в подкаталог .ssh:

    mv ~/id_rsa.pub ~/.ssh/
    
  • еще можно попробовать защитить файл authorized_keys:

    chmod 600 ~/.ssh/authorized_keys
    

    Эта команда изменяет права доступа для файла authorized_keys таким образом, чтобы чтение/запись мог производить только владелец, то есть, мы. На самом деле, можно и дальше пытаться защитить этот файл (и каталог), например:

    chmod 400 ~/.ssh/authorized_keys
    chattr +i ~/.ssh/authorized_keys
    chattr +i ~/.ssh
    

    Нужно это делать, или нет - решать вам (приведенные выше команды устанавливают режим доступа к файлу только на чтение и взводят защитный бит (immutable) и для файла и для каталога). Но если вы все-таки решите идти по пути повышения безопасности, помните, что, в случае необходимости, для полноценной работы с этим файлом (и каталогом) придется откатывать все произведенные изменения, возвращая ранее отобранные права и возможности.

В заключении, хочу все-таки посвятить пару абзацев некоторому подобию теории и своему отношению ко всей этой истории (хотя, кого это интересует? 🤔). Например, почему считается, что соединение с использованием ключей является более безопасным? Ответ прост и кроется он в механизме аутентификации (проверке того, что вы - это вы). При соединении с использованием пароля, введенный вами пароль отсылается на удаленный хост и там проверяется. Это первое потенциально слабое место - теоретически, пересылаемый пароль можно перехватить; он, конечно, зашифрован и все такое, но... Второе слабое место - это возможность осуществить подбор пароля - попробовали один - не подошел, попробовали другой, и так далее. Конечно, это тоже та еще задачка, но, тем не менее.

При аутентификации с использованием ключей таких опасностей нет. Во-первых, никакой пароль никуда не пересылается. Сама схема аутентификации немного другая. Получив запрос на соединение, сервер, при помощи установленного на нем публичного ключа пользователя, запросившего соединение, зашифровывает некое послание (так называемый вызов) и отправляет его на хост, запросивший соединение. Это послание можно расшифровать только используя приватный ключ, который хранится в файле (например, ~/.ssh/id_rsa) у вызывающего пользователя. Если расшифровка произошла успешно, то вызывающий хост отправляет специальный ответ, получив который сервер понимает, что все в порядке и можно разрешить соединение. Все это происходит совершенно незаметно для пользователя, запросившего соединение.

Считается, что если вы задали пароль при генерации ключей, то такая схема более безопасна. На самом деле, я довольно скептически отношусь ко всем этим категориям "более-менее". На мой взгляд, схема соединения с удаленным хостом по SSH с использованием пароля (без ключей) ничуть не хуже, если пароль достаточно сложный. У этой схемы (с паролем), с моей точки зрения, самый большой недостаток - неудобство постоянного ввода пароля, тем более , если он сложный. При этом, если в схеме с ключами при генерации оных, вы указали пароль, то безопасность, вроде, усиливается, по сравнению с ситуацией, когда вы не захотели защищать ключи паролем - если пароля нет, то попав на ваш компьютер можно отправиться на любой другой. Все это, конечно, верно, но, по сути, какая разница, для чего подбирать пароль - для защищенного приватного ключа (понятно, что сначала потребуется попасть на ваше устройство под вашей учетной записью), или для входа под пользователем на другом компьютере? При этом (имеется в виду защита приватного ключа паролем) удобство использования, с моей точки зрения, ухудшается. Конечно, чаще всего все устроено таким образом, чтобы пароль к ключу надо было вводить один раз за сеанс - он кешируется специальным ПО, которое затем от вашего имени и предоставляет его по требованию. Но такое кеширование, в свою очередь, в какой-то степени снижает уровень безопасности - если вы отлучились (не завершив сеанс) и к вашему компьютеру получил физический доступ злоумышленник, а пароль закеширован, то под угрозой все удаленные хосты. И так далее, и тому подобное.

Исходя из всех этих размышлений и рассуждений, приведенных выше, я для себя принял такую схему - если я редко подсоединяюсь к какому-то серверу, то я использую схему доступа с паролем, если же постоянный ввод пароля начинает утомлять, я устанавливаю на удаленном сервере свой публичный ключ (приватный сгенерирован без использования защиты паролем) и наслаждаюсь удобством.

И уж совсем под занавес: если хочется узнать чуть подробней про то, как работает аутентификация при использовании SSH, можно почитать материал по этой ссылке. На этом, пожалуй, все.