按文件名从 ssh-agent 中选择身份

leo*_*luk 12 ssh ssh-keys ssh-agent

问题:我有大约 20-30 个ssh-agent身份。大多数服务器拒绝使用 进行身份验证Too many failed authentications,因为 SSH 通常不会让我尝试使用 20 个不同的密钥来登录。

目前,我正在手动为每台主机指定身份文件,使用IdentityFileIdentitiesOnly指令,以便 SSH 只会尝试一个有效的密钥文件。

不幸的是,一旦原始密钥不再可用,这就会停止工作。ssh-add -l向我显示每个密钥文件的正确路径,它们与 中的路径匹配.ssh/config,但它不起作用。显然,SSH 是通过公钥签名而不是文件名来选择身份的,这意味着原始文件必须可用,以便 SSH 可以提取公钥。

这有两个问题:

  • 一旦我拔下拿着钥匙的闪存驱动器,它就会停止工作
  • 它使代理转发无用,因为远程主机上没有密钥文件

当然,我可以从我的身份文件中提取公钥并将它们存储在我的计算机上,以及我通常登录的每台远程计算机上。不过,这看起来不是一个理想的解决方案。

我需要的是可以通过文件名从 ssh-agent 中选择一个身份,以便我可以轻松地使用.ssh/config或传递来选择正确的密钥-i /path/to/original/key,即使是在我通过 SSH 连接的远程主机上。如果我可以“昵称”这些键,这样我什至不必指定完整路径,那就更好了。

leo*_*luk 9

猜猜我必须回答我自己的问题,因为似乎没有任何方法可以通过文件名请求身份。

我编写了一个快速而肮脏的 Python 脚本,它.ssh/fingerprints为代理持有的每个密钥创建一个公钥文件。然后我可以指定这个文件,它不包含密钥,使用IdentityFileSSH 将从 SSH 代理中选择正确的身份。工作得很好,并允许我将代理用于我希望的任意数量的私钥。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Dumps all public keys held by ssh-agent and stores them in ~/.ssh/fingerprints/, so that
they can be identified using the IdentityFile directive.

"""

import sys, os
import stat
import re
import envoy

RE_MATCH_FILENAME = re.compile(r'([^\\/:*?"<>|\r\n]+)\.\w{2,}$', re.IGNORECASE)

if os.getuid() == 0:
    USERNAME = os.environ['SUDO_USER']
else:
    USERNAME = os.environ['USER']

def error(message):
    print "Error:", message
    sys.exit(1)

def main():
    keylist = envoy.run('ssh-add -L').std_out.strip('\n').split('\n')

    if len(keylist) < 1:
        error("SSH-Agent holds no indentities")

    for key in keylist:
        crypto, ckey, name = key.split(' ')
        filename = os.path.join(os.environ['HOME'], '.ssh/fingerprints',
                  RE_MATCH_FILENAME.search(name).group(1)+'.pub')

        with open(filename, 'w') as f:
            print "Writing %s ..." % filename
            f.write(key)

        envoy.run('chmod 600 %s' % filename)
        envoy.run('chown %s %s' % (USERNAME, filename))


if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)