【问题标题】:How can I write a program (script) to remove obsolete host keys from ~/.ssh/known_hosts?如何编写程序(脚本)以从 ~/.ssh/known_hosts 中删除过时的主机密钥?
【发布时间】:2010-12-28 09:05:50
【问题描述】:

我使用了一个由大约 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 地址的不同投诉,这需要手动删除 another 行,我不想重复此练习 29 次.我想写一个程序来做到这一点。不幸的是,.ssh 文件中的行不再像在早期版本中那样以明文形式包含主机名和 IP 地址。

这是我的问题:

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

如果我能恢复这些信息,我想我可以自己做剩下的事情。


脚注:我更喜欢用 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

【问题讨论】:

  • 你不能删除整个文件吗?
  • 创建一个“主版本”并将其推送到所有机器?我将 $HOME 保存在 NFS 上,所以它在任何地方都是同一个文件......
  • 这并不能解决您的问题,但如果您或其他任何人希望将来禁用这种烦人的行为,请在您的 ssh_config 中将 HashKnownHosts 设置为“no”。

标签: ssh openssh


【解决方案1】:

如果我想知道主机的条目位于哪一行,

ssh-keygen -F hostname

同样的技巧也适用于 IP 地址。

【讨论】:

    【解决方案2】:
    ssh-keygen -R hostname
    ssh-keygen -R ipaddress
    

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

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

    【讨论】:

      【解决方案3】:

      触摸并编辑“clearkey.sh”或任何让您开心的名字。

      #! /bin/bash
      # $1 is the first argument supplied after calling the script
      
      sed -i "$1d" ~/.ssh/known_hosts
      echo "Deleted line $1 from known_hosts file"
      

      应该可以执行“clearkey.sh 3”,它会删除违规行!

      【讨论】:

        【解决方案4】:

        我通常在 bash 脚本checkssh 中执行以下操作以自动删除该行:

        #!/bin/bash
        
        # Path to "known_hosts" file
        KH=~/.ssh/known_hosts
        # Find the host in the file, showing line number
        L=`grep -i -n $1 $KH`
        # If line is not found, exit
        [[ $? -ne 0 ]] && exit
        # Isolate line number
        L=`echo $L | cut -f 1 -d :`
        sed -i "${L}d" $KH
        

        如果您的 ssh 配置为这样做,您可以在末尾添加 ssh $1 exit 以自动在文件中重新创建一个条目。

        将其称为checkssh <hostname>

        【讨论】:

          【解决方案5】:

          您可能想在编写脚本时尝试以下操作:

          declare CHANGED_HOST_NAME="host.yourpublic.work";
          declare CHANGED_HOST_IP=$(dig +short ${CHANGED_HOST_NAME});
          
          # Remove old IP address if found
          [ -z ${CHANGED_HOST_IP} ] || ssh-keygen -R ${CHANGED_HOST_IP};
          
          # Remove old host key
          ssh-keygen -R ${CHANGED_HOST_NAME};
          
          # Add new host key
          ssh-keyscan ${CHANGED_HOST_NAME} >> $HOME/.ssh/known_hosts;
          
          
          

          非常感谢@Storm Knight (@289844)

          【讨论】:

            猜你喜欢
            • 2010-12-11
            • 2017-02-01
            • 2011-09-20
            • 2014-07-07
            • 2014-10-17
            • 2017-03-21
            • 2010-11-26
            • 1970-01-01
            • 2011-05-08
            相关资源
            最近更新 更多