Paramiko:"不是有效的RSA私钥文件"

19

我正在尝试使用以下代码连接到服务器

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

ip = ['x.x.x.x']
key_file = "/Users/user/.ssh/id_rsa"

key = paramiko.RSAKey.from_private_key_file(key_file)
ssh.load_system_host_keys()
ssh.connect(ips, port=22, username='XYZ', pkey=key, timeout=11)

但是我遇到了一个错误:

不是有效的RSA私钥文件

6个回答

36

我遇到了类似的情况,使用ssh-keygen来解决。你需要复制id_rsa并使用ssh-keygen将其转换为RSA类型。

"BEGIN OPENSSH PRIVATE KEY"转换为"BEGIN RSA PRIVATE KEY"

ssh-keygen -p -m PEM -f ~/.ssh/id_rsa

3
Paramiko现在支持新的OpenSSH格式,不再需要进行转换。请参见我的回答 - Martin Prikryl

18

最近版本的OpenSSH(7.8及以上)默认生成新的OpenSSH格式密钥,其格式如下:

-----BEGIN OPENSSH PRIVATE KEY-----

2019年12月09日发布的版本2.7.1起,Paramiko已完全支持该格式。


如果你使用的是较旧版本的Paramiko,你可以使用ssh-keygen将密钥转换为classic OpenSSH格式。
ssh-keygen -p -f file -m pem -P passphrase -N passphrase

(如果密钥未使用密码短语进行加密,请使用""替代passphrase
对于Windows用户:请注意,ssh-keygen.exe现在已内置于Windows 10中,并且可以从Microsoft Win32-OpenSSH项目下载以供旧版本的Windows使用。
在Windows系统上,你也可以使用PuTTY软件包中的PuTTYgen:
  • 启动PuTTYgen
  • 加载密钥
  • 进入转换 > 导出OpenSSH密钥
    对于RSA密钥,它将使用经典格式。

如果你正在使用ssh-keygen创建新的密钥,只需添加-m PEM即可生成经典格式的新密钥。
ssh-keygen -m PEM

请注意,即使您尝试使用完全不同的密钥格式(如ssh.com或PuTTY .ppk),也可能会出现错误。那么您无论如何都需要转换密钥。
对于ssh.com格式,请参见Paramiko:“不是有效的DSA私钥文件”
对于PuTTY .ppk格式,请使用上面显示的PuTTYgen。

4

paramiko.RSAKey.from_private_key_file方法要求私钥文件采用“PEM”格式。检查您要读取的文件,并查看是否以以下行开始:

-----BEGIN RSA PRIVATE KEY-----

如果它没有那一行,那么它不是PEM格式。
如果不是PEM格式,您将需要找到某种方法来创建私钥的PEM版本。(编辑:原帖作者使用了PuTTY的puttygen工具将私钥导出为PEM格式文件。)
确保新文件具有与原始id_rsa文件相同的所有权和有限访问权限,以便通过读取文件来防止任何人窃取密钥。然后,显然,修改您的paramiko调用以从新的PEM格式文件中读取密钥。

1
你分享的命令只生成了公钥,没有私钥RSA。我使用了其他Linux ssh-keygen教程,但它不起作用,唯一能用的是Windows上的putty keygen。只需使用GUI导出私钥并使用即可。 - Owais Ahmad
那太奇怪了。我会从我的答案中删掉整个翻译部分,以防误导其他人。重要的是你必须最终获得PEM格式的私钥。我很高兴你能通过使用PuTTY达到这个目的。 - ottomeister
Paramiko现在支持新的OpenSSH格式,不再需要进行转换。请参见我的回答 - Martin Prikryl

0

我在连接到Ubuntu虚拟机时遇到了同样的错误。 在我的终端中,SSH_AUTH_SOCK环境变量未定义,paramiko抛出了not a valid RSA private key file错误。 然而,如果我在同一台机器上连接到图形会话,则图形终端已经定义了SSH_AUTH_SOCK,Paramiko也能正常工作。 作为解决方法,我将SSH_AUTH_SOCK的内容复制到我的SSH终端中,这样它就可以更好地工作了。


但这意味着Paramiko使用来自身份验证代理的密钥,而不是文件中的密钥。因此,您的代码可能不会执行您想要的操作。 - Martin Prikryl
你是对的,paramiko默认从认证代理获取密钥。如果无法获取,则默认使用~/.ssh/id.rsa,但该文件不是PEM格式,@ahirapara的答案解决了这个问题。 - Kiruahxh
或者您可以(应该)升级 Paramiko 到最新版本,它支持 OPENSSH 格式,正如我的回答所述。 - Martin Prikryl
这是正确的,但我目前使用的是Ubuntu系统版本的Python,据我所知,我无法升级paramiko版本。 - Kiruahxh
它可以通过apt install python3-paramiko进行安装。过去我曾经使用pip安装了一些Python包的最新版本,结果破坏了我的Linux发行版。当然,我可以使用pyenv或其他工具... - Kiruahxh

0

我检查了一下,路径和权限没有问题(只有RSA文件的读取权限可以使用),所以问题出在Paramiko版本上。 我使用了下面的命令更新它,这解决了我的问题。

pip3 install paramiko update

0
以下解决方案适用于我:
  • 安装putty软件包:
brew install putty
  • 将 .ppk 转换成 .pem:
puttygen <filename>.ppk -O private-openssh -o <filename>.pem
  • 通过Python Paramiko再试一次:
import paramiko

username, hostname, port = ('username', 'domain.com', 22,)
transport = paramiko.Transport(hostname, port)
private_key = paramiko.RSAKey.from_private_key(open(pem_file_path))
params = {"username": username, "pkey": private_key}
# if there is a password, add it to the previous dict
transport.connect(**params)
conn = paramiko.SFTPClient.from_transport(transport)

一些好的参考资料:

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接