Paramiko - 在OS X上使用加密的私钥文件

时间:2013-03-22 20:14:53

标签: ssh osx-mountain-lion paramiko private-key

我正在尝试使用Paramiko从Python连接到SSH服务器。这是我到目前为止所尝试的:

>>> 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那样?

3 个答案:

答案 0 :(得分:12)

以下方法似乎工作正常(在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的解决方案应该足够了。

答案 1 :(得分:7)

RSAKey.from_private_key_file()继承自PKey();此方法的可选参数是密码。引用:

  

如果私钥被加密且密码不是None,则给定   密码将用于解密密钥(否则   抛出PasswordRequiredException)。

由于您没有传递密码而您的密钥已加密,因此将始终抛出此异常。这个问题只有一种方法,实际上给方法一个密码。因此,您需要一种从OSXKeychain中获取密码的方法。

您可以使用跨平台Keyring模块执行此操作。

答案 2 :(得分:0)

无法在Paramiko中使用加密的私钥,因为ssh-agent doesn't give private key(无内存转储)。

解决方案是使用subprocess并从中调用ssh命令(与任何常规命令一样)。我不是要解密私钥(它使用ssh代理,您可以使用ssh -vvv找到它)。

顺便说一句,我找不到使用paramiko的好处。 SSH代理似乎更发达,更通用。例如,它是paramiko中的not possible to forward SSH agent,为此必须诉诸子流程。还要注意this issue(来自2014年),“密钥处理非常糟糕”(打开):

  

SSHClient._auth使用多重退出策略,并结合存储单个异常以在流程结束时引发。这通常意味着在身份验证时引发的异常对于无法身份验证的真正原因完全是错误的。

此线程中链接了许多paramiko错误。现在看来它已经很活跃了,我希望paramiko能够解决这个问题,但是我的建议是:不要依赖单个库,它可能无法满足您的需求。

是的,有可能为加密密钥提供密码,但这违背了此目的。您要么自己输入密码(然后就不需要ssh密钥),要么将密码存储在磁盘上(当然不在版本控制中),那么就不需要对私钥进行加密(这样的想法)是如果有人拿到了您的HDD,则不会以纯文本的形式得到您的私钥。