Подтвердить что ты не робот

Paramiko - использование зашифрованного файла закрытого ключа в OS X

Я пытаюсь использовать Paramiko для подключения к SSH-серверу с Python. Это то, что я пробовал до сих пор:

>>> import paramiko
>>> import os
>>> privatekeyfile = os.path.expanduser('~/.ssh/id_rsa')
>>> mykey = paramiko.RSAKey.from_private_key_file(privatekeyfile)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/paramiko/pkey.py", line 198, in from_private_key_file
    key = cls(filename=filename, password=password)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/paramiko/rsakey.py", line 51, in __init__
    self._from_private_key_file(filename, password)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/paramiko/rsakey.py", line 163, in _from_private_key_file
    data = self._read_private_key_file('RSA', filename, password)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/paramiko/pkey.py", line 280, in _read_private_key_file
    data = self._read_private_key(tag, f, password)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/paramiko/pkey.py", line 323, in _read_private_key
    raise PasswordRequiredException('Private key file is encrypted')
paramiko.PasswordRequiredException: Private key file is encrypted

Как вы можете видеть, он не работает, потому что мой закрытый ключ зашифрован. Тем не менее, пароль хранится в моей логической цепочке для входа в OS X, и когда я набираю ssh host, он не будет запрашивать его (скорее, он запрашивает только один раз, а затем запоминает его до следующей перезагрузки). Есть ли способ сделать paramiko использовать пароль/извлечь его из цепочки ключей, например ssh?

4b9b3361

Ответ 1

RSAKey.from_private_key_file() наследуется от PKey(); необязательным параметром этого метода является пароль. Цитировать:

Если секретный ключ зашифрован, а пароль не является None, данный пароль будет использоваться для дешифрования ключа (в противном случае PasswordRequiredException выбрано).

Поскольку вы не передаете пароль, а ваш ключ зашифрован, это исключение всегда будет выбрано. Там только один путь вокруг этой проблемы, чтобы фактически дать метод пароль. Вам, следовательно, нужен способ получить пароль из OSXKeychain.

Для этого вы можете использовать кросс-платформенный Keyring.

Ответ 2

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

import paramiko

ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.connect(HOST, username=USER, look_for_keys=False)
...
ssh.close()

Кажется, что look_for_keys=False не является абсолютно необходимым. Однако, если вы его используете, вы получите гораздо лучшие сообщения об ошибках в случае сбоя аутентификации ( "AuthenticationException" вместо "PasswordRequiredException" ).


Если вы действительно хотите напрямую использовать секретные ключи, вы можете сделать следующее:

import os
import paramiko
import keyring

keyfile = os.path.expanduser('~/.ssh/id_rsa')
password = keyring.get_password('SSH', keyfile)
key = paramiko.RSAKey.from_private_key_file(keyfile, password=password)

Однако, основываясь на моем тестировании, это не требуется. Вышеупомянутое решение, использующее ssh.connect простым способом, должно быть достаточным.

Ответ 3

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

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

Кстати, я не мог найти преимущества использования paramiko. Агент SSH кажется более развитым и более общим инструментом. Например, невозможно переслать SSH-агент в paramiko, для этого нужно прибегнуть к подпроцессу. Также обратите внимание на этот выпуск 2014 года, "Обработка ключей - terribad" (открыть):

SSHClient._auth использует стратегию множественного выхода в сочетании с сохранением единственного исключения, которое должно быть вызвано в конце процесса. Это часто означает, что возбужденное исключение во время аутентификации совершенно неверно относительно истинной причины невозможности аутентификации.

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

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