问题:我有 20-30 个ssh-agent
身份。大多数服务器拒绝使用 进行身份验证Too many failed authentications
,因为 SSH 通常不允许我尝试 20 个不同的密钥来登录。
目前,我正在使用IdentityFile
和指令手动为每个主机指定身份文件IdentitiesOnly
,以便 SSH 只会尝试一个有效的密钥文件。
不幸的是,一旦原始密钥不再可用,它就会停止工作。ssh-add -l
向我显示了每个密钥文件的正确路径,它们与中的路径匹配.ssh/config
,但它不起作用。显然,SSH 通过公钥签名而不是文件名来选择身份,这意味着原始文件必须可用,以便 SSH 可以提取公钥。
这有两个问题:
- 一旦我拔掉装有钥匙的闪存盘,它就会停止工作
- 由于密钥文件在远程主机上不可用,因此代理转发变得毫无用处
当然,我可以从我的身份文件中提取公钥,并将其存储在我的电脑上,以及我经常登录的每台远程电脑上。但这看起来不是一个理想的解决方案。
我需要的是能够通过文件名从 ssh-agent 中选择身份,这样我就可以通过.ssh/config
或轻松选择正确的密钥-i /path/to/original/key
,即使在我通过 SSH 进入的远程主机上也是如此。如果我可以给密钥起“昵称”,那就更好了,这样我甚至不必指定完整路径。
答案1
我想我必须回答我自己的问题,因为似乎没有任何方法可以通过文件名请求身份。
我编写了一个快速而简单的 Python 脚本,它.ssh/fingerprints
为代理持有的每个密钥创建一个公钥文件。然后我可以指定这个不包含密钥的文件,使用IdentityFile
SSH 将从 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()
答案2
跑步
ssh-add -L | gawk ' { print $2 > $3 ".pub" } '
在远程计算机上自动生成所有公钥文件(假设您的公钥.ssh/config
已命名privateKeyFileName.pub
且不涉及不一致的路径)。致电咨询chown $USER .ssh/*
您的sudo
案例。
答案3
从已接受的解决方案中挑选,并假设您只想重用用于访问初始服务器的身份,然后类似:
Host github.com
IdentitiesOnly yes
IdentityFile ~/.ssh/authorized_keys
就足够了。
答案4
python3版本的代码在leoluks优秀回答中:
#!/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 subprocess
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 = subprocess.check_output(['ssh-add','-L']).decode().strip('\n').split('\n')
if len(keylist) < 1:
error("SSH-Agent holds no indentities")
for key in keylist:
crypto, ckey, name = key.split(' ')
print('name', name)
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)
subprocess.call(['chmod', '600', filename])
subprocess.call(['chown',USERNAME, filename])
if __name__ == '__main__':
main()