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




osx-mountain-lion private-key (2)

Я пытаюсь использовать 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 ?


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

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

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

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


Следующий подход, кажется, работает хорошо (на 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 простым способом, должно быть достаточно.





private-key