如何编写程序(脚本)来从 ~/.ssh/known_hosts 中删除过时的主机密钥?
我使用大约 30 台机器组成的集群,这些机器最近都使用新的 OpenSSH 主机密钥进行了重新配置。当我尝试登录其中一个时,我收到此错误消息(为简洁起见,删除了许多行):
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
The fingerprint for the RSA key sent by the remote host is
52:bb:71:83:7e:d0:e2:66:92:0e:10:78:cf:a6:41:49.
Add correct host key in /home/nr/.ssh/known_hosts to get rid of this message.
Offending key in /home/nr/.ssh/known_hosts:50
我可以手动删除有问题的行,在这种情况下,我会收到有关 IP 地址的不同投诉,这需要删除另一个 手动进行,我不想重复这个练习 29 次。我想写一个程序来做到这一点。不幸的是,.ssh 文件中的行不再像早期版本那样包含明文形式的主机名和 IP 地址。
所以这是我的问题:
- 给定主机名和 IP 地址,我如何编写一个程序来找出我的
~/.ssh/known_hosts
的哪些行存储了 SSH 主机密钥主机或 IP 地址?
如果我可以恢复此信息,我想我可以自己完成剩下的工作。
脚注:我更喜欢用 bash/ksh/sh 或 C 或 Lua 编写代码;我的 Perl 和 Python 很生疏。
澄清:
我不想删除整个文件并重新填充它;它包含一百多个经过验证的密钥,我不想重新验证这些密钥。
无论我维护单个主副本还是多个副本,清除大量过时主机密钥的问题仍然存在。
无论我维护单个主副本还是多个副本
这
是我使用 ssh-keygen -F 编写的 Lua 脚本:
#!/usr/bin/env lua
require 'osutil'
require 'ioutil'
local known = os.getenv 'HOME' .. '/.ssh/known_hosts'
local function lines(name)
local lines = { }
for l in io.lines(name) do
table.insert(lines, l)
end
return lines
end
local function remove_line(host)
local f = io.popen('ssh-keygen -F ' .. os.quote(host))
for l in f:lines() do
local line = l:match '^# Host %S+ found: line (%d+) type %u+$'
if line then
local thelines = lines(known)
table.remove(thelines, assert(tonumber(line)))
table.insert(thelines, '')
io.set_contents(known, table.concat(thelines, '\n'))
return
end
end
io.stderr:write('Host ', host, ' not found in ', known, '\n')
end
for _, host in ipairs(arg) do
local ip = os.capture('ipaddress ' .. host)
remove_line(host)
remove_line(ip)
end
I use a cluster of about 30 machines that have all recently been reconfigured with new OpenSSH host keys. When I try to log into one, I get this error message (many lines removed for brevity):
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
The fingerprint for the RSA key sent by the remote host is
52:bb:71:83:7e:d0:e2:66:92:0e:10:78:cf:a6:41:49.
Add correct host key in /home/nr/.ssh/known_hosts to get rid of this message.
Offending key in /home/nr/.ssh/known_hosts:50
I can go remove the offending line manually, in which case I get a different complaint about the IP addresss, which requires removing another line manually, and I have no desire to repeat this exercise 29 times. I would like to write a program to do it. Unfortunately, the line in the .ssh file no longer contains the host name and IP address in clear text, as it did in earlier versions.
So here's my question:
- Given a host name and an IP address, how can I write a program to find out which lines of my
~/.ssh/known_hosts
store an SSH host key for that host or IP address?
If I can recover this info, I think I can do the rest myself.
Footnote: I would prefer to code in bash/ksh/sh or C or Lua; my Perl and Python are very rusty.
Clarifications:
I don't want to remove the whole file and repopulate it; it contains over a hundred validated keys that I prefer not to re-validate.
Whether I maintain a single master copy or multiple replicas, the problem of scrubbing away a large group of obsolete host keys remains.
Answer
Here's the Lua script I wrote using ssh-keygen -F
:
#!/usr/bin/env lua
require 'osutil'
require 'ioutil'
local known = os.getenv 'HOME' .. '/.ssh/known_hosts'
local function lines(name)
local lines = { }
for l in io.lines(name) do
table.insert(lines, l)
end
return lines
end
local function remove_line(host)
local f = io.popen('ssh-keygen -F ' .. os.quote(host))
for l in f:lines() do
local line = l:match '^# Host %S+ found: line (%d+) type %u+
if line then
local thelines = lines(known)
table.remove(thelines, assert(tonumber(line)))
table.insert(thelines, '')
io.set_contents(known, table.concat(thelines, '\n'))
return
end
end
io.stderr:write('Host ', host, ' not found in ', known, '\n')
end
for _, host in ipairs(arg) do
local ip = os.capture('ipaddress ' .. host)
remove_line(host)
remove_line(ip)
end
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我个人使用循环和 Perl 清理 IP 地址,并手动消除冲突。
personally I scrub the IP addresses with a loop and perl, and remove the conflicts by hand.
如果我想找出主机的条目位于哪一行,
同样的技巧也适用于 IP 地址。
If I want to find out on what line the entry for a host lives,
The same trick works with IP addresses.
触摸并编辑“clearkey.sh”或任何让您满意的名称。
应该能够执行“clearkey.sh 3”,它将删除有问题的行!
touch and edit "clearkey.sh" or what ever name makes you happy.
Should be able to do "clearkey.sh 3" and it will delete the offending line!
我通常在 bash 脚本
checkssh
中执行以下操作来自动删除该行:您可以在末尾添加
ssh $1 exit
来自动在文件中重新创建一个条目,如果您的 ssh 配置为这样做。像
checkssh
这样称呼它。I usually do the following in bash script
checkssh
to automatically remove the line:You can add
ssh $1 exit
at the end to automatically re-create an entry in the file, if your ssh is configured to do so.Call it like
checkssh <hostname>
.在编写脚本时,您可能想尝试以下操作:
非常感谢@Storm Knight (@289844)
You might like to try the following when script writing:
Big thanks to @Storm Knight (@289844)