今時のバージョンのOpenSSHではknown_hostsがハッシュ化されてて手動管理がしにくいし、スマートに決めたいのでコマンドでやってみる。
コマンド
結論から書くと↓こんな感じでOK。(target-hostname
のホストキーが変わった場合の例)
host="target-hostname"
ssh-keygen -R $host
ssh-keyscan -H $host >> ~/.ssh/known_hosts
-
ssh-keygen -R hostname
は~/.ssh/known_hosts
から対象ホストのホストキーを削除してくれる。- 複数あれば全部消してくれるしハッシュ化されてるのもされてないのも全部消してくれるので便利。
- known_hostsファイルをエディタで開いてエラーメッセージで指摘された行数まで移動して手で削除するのなんかより100倍楽。
-
ssh-keyscan
は対象ホストのホストキー一覧を取得するコマンド。- 無言で実行できるから一旦手動でssh試みてプロンプトでyesとかするより使い勝手が良い。
-
-H
オプションを付けるとホスト名がハッシュ化される、無しなら昔ながらに生のホスト名で出力される。今時はハッシュ化しとけば良いと思う。
-
注意点! 追記する為の
>>
を間違えて>
て書くと既存のキーが全部消えるので気をつけること!
ちょっと進化系
HashKnownHosts yes
な環境だとbash-completionのホスト名補完が効かなくなるので~/.ssh/config内で明示的にno
にしてる人もいそうな気がする。そういう人はssh-keyscanに勝手にハッシュオプション付けられるのは嫌がるだろうから環境チェックしてからオプションの出し入れするように修正してみた。
#!/bin/bash
# ssh設定値の取得関数
sshconf() {
local key=$1 targethost=$2
local value inhost f k v m
[[ -z $key ]] && { echo "Usage: $FUNCNAME key [hostname]"; return 1; }
for f in ~/.ssh/config /etc/ssh_config; do
[[ -r $f ]] || continue
inhost=1
while read k v; do
if [[ $k == Host ]]; then
inhost=
for m in $v; do
[[ $m =~ ^# ]] && break # skip comment
m=${m//./\\.}; m=${m//\*/.*}; m=${m//\?/.}; m="^$m$" # wildcard -> regexp
if [[ $targethost =~ $m ]]; then
inhost=1
break
fi
done
continue
fi
[[ -z $inhost ]] && continue # 不一致Host内の設定は無視
if [[ $k == $key ]]; then
value=$v
fi
if [[ -n $value ]]; then
break # 最初に見つけた設定優先なのでbreak
fi
done < <(cat $f | grep -v '^$' | egrep -v '^\s*#')
if [[ -n $value ]]; then
break # 最初のファイル優先なのでbreak
fi
done
[[ -z $value ]] && return 1
printf "%s\n" "$value"
}
# main
[[ -z $1 ]] && { echo "Usage: $0 hostname [hostname...]"; exit 1; }
hashopt=
if [[ $(sshconf HashKnownHosts) == yes ]]; then
hashopt=-H
fi
for h in "$@"; do
ssh-keygen -R "$h"
ssh-keyscan $hashopt "$h" >> ~/.ssh/known_hosts
done
現在の環境上でのsshの設定値を取得するコマンドってありそうでないのね…。お陰でHashKnownHosts
の値が知りたかっただけなのに長大な関数を書いてしまった(^^;
上記 sshconf
関数は結構まじめに書いたつもりなので単に指定のホストに対する設定値を取得するコマンドとして独立していても便利に使えそう。→独立したsshconf.shってファイルに分けといた。
ssh -G があったw
ssh -G ホスト名
でそのホスト名にマッチする最終的な ssh_cofig 値が取れるんじゃん!てことに上の関数を作ってから1年以上経過して気がついた…。