Я использую кластер из примерно 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 очень ржавые.
Разъяснения:
Я не хочу удалять весь файл и заново его заполнять; он содержит более ста проверенных ключей, которые я предпочитаю не подтверждать повторно.
Сохраняю ли я одну мастер-копию или несколько реплик, проблема очистки большой группы устаревших ключей хоста остается.
Ответ
Вот скрипт 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