如何编写程序(脚本)以从 ~/.ssh/known_hosts 中删除过时的主机密钥?

Nor*_*sey 0 ssh openssh

我使用了一个由大约 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
Run Code Online (Sandbox Code Playgroud)

我可以手动删除违规行,在这种情况下,我会收到有关 IP 地址的不同抱怨,这需要手动删除另一行,而且我不想重复这个练习 29 次。我想写一个程序来做到这一点。不幸的是,.ssh 文件中的这一行不再像早期版本那样包含明文形式的主机名和 IP 地址。

所以这是我的问题:

  • 给定主机名和 IP 地址,我如何编写程序来找出我~/.ssh/known_hosts商店的哪些行是该主机或 IP 地址的 SSH 主机密钥?

如果我可以恢复这些信息,我想我可以自己完成其余的工作。


脚注:我更喜欢用 bash/ksh/sh 或 C 或 Lua 编码;我的 Perl 和 Python 非常生疏。


说明:

  • 我不想删除整个文件并重新填充它;它包含一百多个经过验证的密钥,我不想重新验证这些密钥。

  • 无论我维护一个主副本还是多个副本,清除大量过时的主机密钥的问题仍然存在。

回答

这是我使用的 Lua 脚本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
Run Code Online (Sandbox Code Playgroud)

小智 5

ssh-keygen -R hostname
ssh-keygen -R ipaddress
Run Code Online (Sandbox Code Playgroud)

我个人使用循环和 perl 清理 IP 地址,并手动删除冲突。

$!/usr/bin/perl
for (1..30){
     `ssh keygen -R 192.168.0.$_`; #note: backticks arent apostrophies
}
Run Code Online (Sandbox Code Playgroud)