こんにちは、おうどんです🍜
新人さん「サーバーに鍵でログインできるように、鍵を作って送っておきました!」
おうどん「お、えらい。どっちを送ったの?」
新人さん「両方です。念のため、秘密鍵も」
おうどん「……念のため、の使い方が逆」
(会話は説明用の架空の場面です)
うどん屋さんで言うと、常連さんの登録に来て、自分の筆跡見本と一緒に、自分の右手も置いて帰ったようなものです。
大将「右手はけっこうです」
……そりゃそうです。
SSH(ネットワーク越しにサーバーへ安全にログインするための仕組み)で鍵を使うとき、必ず出てくるのが公開鍵と秘密鍵。
名前は聞いたことがあるけど、どっちを誰に渡すのか、なぜ鍵でログインできるのかは、意外とあいまいなままになりがちです。
今回は基礎講座として、公開鍵と秘密鍵の役割を、Git for Windows に入っている ssh-keygen を実際に動かしながら整理します。
最初に、初心者向けのチェックリストです。
- 相手(サーバー)に渡すのは、末尾が
.pubのファイル(公開鍵)だけ .pubが付いていないほう(秘密鍵)は、誰にも送らない。チャットにも貼らない- 同じ鍵かどうかは、
ssh-keygen -l -f ファイル名の指紋で確かめる
前回の応用編「SSHでRSA鍵なのに接続できない原因と対処」は、この記事の知識を前提にしています。実践編としてあわせてどうぞ。
公開鍵は「筆跡見本」、秘密鍵は「自分の手」
先に結論を言うと、秘密鍵はサインを書くための手、公開鍵はそのサインが本物か照らし合わせるための見本です。
まず用語です。
- 鍵ペア:公開鍵と秘密鍵の2つで1組。片方だけ作ることはなく、必ずセットで生まれる
- 秘密鍵:自分だけが持つほう。これを使って署名(「本人です」という証拠)を作る
- 公開鍵:相手に渡すほう。署名が、対になる秘密鍵で作られたものかを確かめるのに使う
- 署名:秘密鍵を使って、あるデータに対して作る「本人が書いた」証拠。紙のサインと同じ発想
ssh のマニュアルには、公開鍵認証の考え方が次のように書かれています。
- 各ユーザーが、認証のための公開鍵と秘密鍵のペアを作る
- サーバーは公開鍵を知っていて、秘密鍵はユーザーだけが知っている
- クライアントは、秘密鍵を持っていることを証明する
- ログインを許す公開鍵の一覧は、サーバー側の
~/.ssh/authorized_keysに書く
新人さん「じゃあ、秘密鍵を見せれば一番早く証明できますね」
おうどん「それは、サインの代わりに右手を切って提出するやつ」
……証明はできても、二度とサインできません。
見せるのは手ではなく、その手で書いたサイン。ここが公開鍵認証のいちばん大事なところです。
大将「常連さん、お名前を書いてください。見本と照らし合わせますので」
おうどん「(さらさら)」
大将「はい、本人ですね。手は見せなくて大丈夫です」
……手を見せずに本人だと分かる。これが鍵ペアのいいところなんです。
どっちを渡す? 「.pub」が付いているほうだけ
迷ったら、ファイル名の最後に .pub(public=公開)が付いているほうだけを渡す、と覚えておけば間違えません。
今回の検証環境(Git for Windows の OpenSSH_9.7p1、bash 5.2.26)で鍵ペアを作ってみます。
ssh -V ssh-keygen -q -N "" -C udon-key -f ./udon_key ls -1
OpenSSH_9.7p1, OpenSSL 3.2.1 30 Jan 2024
udon_key
udon_key.pub
(1行目が ssh -V、2〜3行目が ls -1 の結果です。ssh-keygen は -q で静かにしているので何も表示しません)
オプションの意味はこうです(ssh-keygen のマニュアルより)。
| オプション | 意味 |
|---|---|
-f | 鍵のファイル名。公開鍵は同じ名前に .pub を付けたファイルになる |
-C | コメント(どの鍵か見分けるためのメモ) |
-N | パスフレーズ。"" は「なし」(今回は検証用なのでなし) |
-q | 静かモード |
-t | 鍵の種類。今回は付けていない |
新人さん「
-N ""って、パスフレーズが空っぽってことですか」
おうどん「検証用の鍵だからね。本番の鍵で真似しない」
……空っぽの金庫は、金庫の形をした箱です。
-t を付けなかったので、何の鍵ができたか見てみます。
cat udon_key.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAMtrLHW1uJUlZ7aGl7bW/114Lf7zFbewY66Hn/Rads+ udon-key
(鍵の中身は作るたびに変わります)
公開鍵ファイルは1行で、スペース区切りの3つの部分でできています。
| 部分 | 中身 |
|---|---|
ssh-ed25519 | 鍵の種類 |
AAAAC3Nza... | 鍵の本体(Base64 という、データを英数字と記号で表す書き方) |
udon-key | コメント(-C で付けたメモ) |
今回の検証環境では、-t なしで Ed25519 の鍵ができました。ssh-keygen のマニュアル(OpenBSD 版の最新)にも、引数なしで実行すると Ed25519 の鍵を作る、と書かれています。古い版では既定が違うことがあるので、種類を決めたいときは -t ed25519 のように明示しましょう。
新人さん「Ed25519 って、なんだか型番みたいですね」
おうどん「うどんで言えば、麺の種類の名前」
新人さん「じゃあ RSA は?」
おうどん「……昔からある太麺、くらいにしておこう」
……雑なたとえは、ここで止めておきます。鍵の種類の違いは後半の上級者向けで少しだけ触れます。
次に、秘密鍵のほうの最初と最後の行を見ます。
head -n 1 udon_key tail -n 1 udon_key
-----BEGIN OPENSSH PRIVATE KEY-----
-----END OPENSSH PRIVATE KEY-----
PRIVATE KEY(秘密鍵)と、自分で名乗っています。
送る前にファイルを開いてこの行が見えたら、それは送ってはいけないほうです。
新人さん「ファイルが自分で『秘密です』って書いてあるの、親切ですね」
おうどん「封筒に『極秘』って大きく書いてあるのと同じでね」
……親切だけど、見つかったら一番目立つ。だから置き場所と権限が大事なんです(後半で触れます)。
鍵でログインできる仕組み:サインを見せて、手は見せない
ひとことで済ませると怒られそうなので、大将のお店で説明します。
サーバーはお題を出し、クライアントはそのお題に秘密鍵でサインして返す。サーバーは公開鍵(見本)で照らし合わせる。これだけです。
SSH の公開鍵認証を定めた RFC 4252(RFC はインターネットの技術の決まりごとを書いた文書)の7章によると、
- クライアントは、ユーザー名・公開鍵・署名などを入れた認証のリクエストを送る
- 署名は、秘密鍵を持っていることを示すためのもの
- サーバーは、その公開鍵がそのユーザーの認証に使ってよいものか、署名が正しいかを確かめ、両方満たせば成功にする
と書かれています。送られるものとして挙がっているのは、公開鍵と署名です。秘密鍵そのものは、リストに入っていません。
ログインそのものは今回の検証環境では試せないので、同じ「秘密鍵で署名して、公開鍵で確かめる」流れを、ssh-keygen のファイル署名機能(-Y sign と -Y verify)で体験してみます。
(-Y sign はファイルに署名する機能で、SSH のログインそのものではありません。秘密鍵で署名し、公開鍵で確かめる、という考え方が同じなので、体験用に使っています)
まず、注文書に秘密鍵でサインします。
printf 'うどん3玉、注文します\n' > order.txt ssh-keygen -Y sign -f udon_key -n file order.txt
Signing file order.txt
Write signature to order.txt.sig
-n file は、署名の用途(名前空間)を表すラベルです。ssh-keygen のマニュアルによると、別の用途に署名が使い回されるのを防ぐためのものです。
新人さん「名前空間って、宇宙の話ですか」
おうどん「伝票の『用途』欄。出前用か、店内用か」
……宇宙までは、出前していません。
次に、確かめる側の準備。「この人の見本はこれ」という一覧(allowed_signers)を作ります。中身は「名前 + 公開鍵」です。
echo "oudon@example $(cut -d' ' -f1,2 udon_key.pub)" > allowed_signers cat allowed_signers
oudon@example ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAMtrLHW1uJUlZ7aGl7bW/114Lf7zFbewY66Hn/Rads+
公開鍵で確かめます。
ssh-keygen -Y verify -f allowed_signers -I oudon@example -n file -s order.txt.sig < order.txt
Good "file" signature for oudon@example with ED25519 key SHA256:HLBgYeWydciiUrIsrKn1WntRLQvt2mj4GXEMUj2fY2E
(終了コードは 0)
Good、本物です。
では、注文書を書き換えてみます。3玉を30玉に。
printf 'うどん30玉、注文します\n' > order_fake.txt ssh-keygen -Y verify -f allowed_signers -I oudon@example -n file -s order.txt.sig < order_fake.txt
Signature verification failed: incorrect signature
Could not verify signature.
(終了コードは 255。ここまでのコマンドは、今回の検証環境で bash スクリプトの中から順に実行し、標準出力と標準エラーをまとめて記録しました)
1文字(0)を足しただけで、サインが合わなくなりました。
新人さん「30玉なら、大将も喜ぶと思ったんですけど」
大将「喜ぶ前に、お代を払う人が見つからない」
……サインの付いていない30玉は、誰も払ってくれません。
新人さん「じゃあ、サインごと30玉用に書き直せば?」
おうどん「それができるのは、秘密鍵を持っている人だけ」
……だから、秘密鍵は自分の手から離しちゃいけないんです。
🔰 ここまで読めば今日から困らない
- 鍵ペアは、公開鍵(
.pub、相手に渡す見本)と秘密鍵(自分だけの手)の2つで1組 - サーバーに渡すのは
.pubだけ。中身が-----BEGIN OPENSSH PRIVATE KEY-----で始まるファイルは送らない - ログインのとき、秘密鍵そのものは送られない。秘密鍵で作った署名を、サーバーが公開鍵で確かめる
- 鍵の種類を決めたいときは
ssh-keygen -t ed25519 -C "メモ"のように-tを明示する
新人さん「4行なら覚えられます。秘密鍵のファイルにメモしておきますね」
おうどん「メモの置き場所に、一番大事な金庫を選ばない」
……開けるたびに中身が見えて危ないです。
大将「その4行、見本帳の表紙に貼っておきますね」
新人さん「大将のほうが、先に覚えそう」
……お客さんより詳しいうどん屋。
ここから先は中級者向け。読み飛ばしてもOKです。
サーバーに登録する:authorized_keysの書き方と権限
公開鍵は、サーバーのログインしたいユーザーの ~/.ssh/authorized_keys に1行ずつ書きます。大将の「常連さんの見本帳」です。
sshd のマニュアルによると、
AuthorizedKeysFileを指定していなければ、既定は~/.ssh/authorized_keys(と~/.ssh/authorized_keys2)- 1行に1つの鍵。空行と
#で始まる行はコメントとして無視される - 1行は、オプション・鍵の種類・Base64 の鍵本体・コメントをスペースで区切ったもの(オプションは省略できる)
- コメントは何にも使われない(どの鍵か見分ける目印になるだけ)
.pub の1行をそのまま追記すれば、形式どおりになります。
サーバーにすでにパスワードなどでログインできる状態なら、手元から次のように登録できます(opsuser と 192.0.2.10 は説明用の例です)。
cat ~/.ssh/id_ed25519.pub | ssh opsuser@192.0.2.10 'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'
(未実行の例です。今回の検証環境には接続先のサーバーがないため、実際の登録は試していません)
ポイントは >>(追記)。> にすると、ファイルが上書きされて、ほかの人や別の端末の鍵が消えます。
新人さん「
>と>>、1文字しか違わないのに」
おうどん「見本帳に1枚足すのと、見本帳を燃やして1枚だけ置くのの違い」
……常連さんが全員、初めましてになります。
権限もよくハマるところです。sshd のマニュアルには、authorized_keys は本人だけが読み書きでき、ほかの人からはアクセスできない権限がすすめられていること、そして このファイル・~/.ssh ディレクトリ・ホームディレクトリのどれかがほかのユーザーから書き込める状態だと、StrictModes が no でない限り sshd はこのファイルを使わない、と書かれています。
| 対象 | 例 | 理由 |
|---|---|---|
~/.ssh | chmod 700 ~/.ssh | ほかのユーザーが書き込めないようにする |
~/.ssh/authorized_keys | chmod 600 ~/.ssh/authorized_keys | 本人だけ読み書き |
| ホームディレクトリ | ほかのユーザーが書き込めないこと | 書き込めると authorized_keys が使われない |
(上の chmod は、マニュアルの条件を満たす設定の一例です)
新人さん「鍵を登録したのに、パスワードを聞かれます」
おうどん「見本帳の棚に、誰でも書き込めるようになってない?」
……他人が見本を差し替えられる棚の見本は、大将も信用しません。
手元の秘密鍵にも同じ考え方があります。ssh のマニュアルには、~/.ssh/id_ed25519 などの秘密鍵ファイルは本人だけが読めるようにすべきで、ほかの人がアクセスできる状態だと ssh はその秘密鍵ファイルを単に無視する、と書かれています。
指紋で「同じ鍵か」を確かめる
鍵の本体は長いので、目で見比べるのは大変です。そこで使うのが指紋(フィンガープリント。鍵の中身から計算した短い要約)です。
ssh-keygen -l -f udon_key.pub ssh-keygen -l -f udon_key
256 SHA256:HLBgYeWydciiUrIsrKn1WntRLQvt2mj4GXEMUj2fY2E udon-key (ED25519)
256 SHA256:HLBgYeWydciiUrIsrKn1WntRLQvt2mj4GXEMUj2fY2E udon-key (ED25519)
(1行目が公開鍵、2行目が秘密鍵のファイルを指定した結果です)
公開鍵のファイルを指定しても、秘密鍵のファイルを指定しても、同じ指紋が出ました。同じペアだからです。
並びは、鍵の大きさ(ビット数)・指紋・コメント・鍵の種類です。
使いどころは、たとえばこんなときです。
- サーバーの
authorized_keysに並んだ鍵のうち、どれが自分の鍵か調べる(今回の検証では、公開鍵を2行並べたファイルにssh-keygen -l -fを使うと、1行ずつ指紋が出ました) - 手元に
id_ed25519が何本もあって、どれを登録したか分からなくなった
新人さん「指紋が同じなら、同じ鍵。じゃあ、うどんの指紋も……」
おうどん「麺には指紋がない。粉のロット番号ならある」
……ロット番号で常連さんは見分けられません。
指紋の表し方は、既定が SHA256(ssh-keygen のマニュアルより)。古いシステムや資料では MD5 の形(コロン区切り)で書かれていることがあるので、そのときは -E md5 で合わせます。
ssh-keygen -l -E md5 -f udon_key.pub
256 MD5:c0:d5:47:4e:11:a7:a6:40:00:21:7e:92:68:bd:f3:2b udon-key (ED25519)
同じ鍵でも、表し方が違うと見た目はまるで別物です。
見比べるときは、SHA256 同士、MD5 同士で。
新人さん「SHA256 と MD5 で一致しないから、別の鍵だと思ってました」
おうどん「同じ人の、身長を cm と尺で測って『違う人だ』って言ってるやつ」
……単位をそろえてから、別人かどうかを決めましょう。
秘密鍵にパスフレーズを付ける・変える
パスフレーズは、秘密鍵ファイルそのものにかける鍵です。ファイルが盗まれても、パスフレーズが分からなければ使えないようにするためのものです。
ここまでの検証用の鍵はパスフレーズなし(-N "")でした。コピーした鍵にパスフレーズを付けてみます(-P は今のパスフレーズ、-N は新しいパスフレーズ)。
cp udon_key pp_key ssh-keygen -p -P "" -N "kitsune-udon" -f pp_key
Key has comment 'udon-key'
Your identification has been saved with the new passphrase.
間違ったパスフレーズで、秘密鍵から公開鍵を取り出そうとすると(-y は秘密鍵を読んで公開鍵を表示するオプション)、
ssh-keygen -y -P "tanuki-soba" -f pp_key
Load key "pp_key": incorrect passphrase supplied to decrypt private key
(終了コードは 255)
断られました。正しいパスフレーズなら、公開鍵が出てきます。
ssh-keygen -y -P "kitsune-udon" -f pp_key
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAMtrLHW1uJUlZ7aGl7bW/114Lf7zFbewY66Hn/Rads+ udon-key
新人さん「きつねとたぬき、間違えただけなのに」
pp_key「おあげが入っていないので、開けられません」
……うどんとそばの違いまで厳しい。
注意点が2つあります。
- 上の例はパスフレーズをコマンドに直接書いていますが、これは検証のためです。実際の作業では
ssh-keygen -p -f ~/.ssh/id_ed25519とだけ打って、聞かれたときに入力しましょう(コマンドに書くと、履歴に残ることがあります) - ssh-keygen のマニュアルには、忘れたパスフレーズを取り戻す方法はない、と書かれています。忘れたら、新しい鍵を作り、公開鍵を登録し直すことになります
新人さん「じゃあ、パスフレーズは公開鍵のファイルにメモしておけば……」
おうどん「公開鍵は、配って歩くほうだよ」
……メモが全サーバーに配られます。
毎回入力するのが面倒なら、ssh-agent(秘密鍵を覚えておいてくれる常駐プログラム)を使う方法があります。ssh のマニュアルにも、公開鍵認証のいちばん便利な使い方は認証エージェントを使うことかもしれない、とあります。
よくある勘違いチェックリスト
最後に、中級者がやりがちな勘違いを並べておきます。
| よくある勘違い | 実際 |
|---|---|
| 鍵ペアは片方を失くしても作り直せる | 公開鍵は秘密鍵から取り出せる(ssh-keygen -y)。秘密鍵は公開鍵からは作れない。秘密鍵を失くしたら作り直し |
| ログインのとき秘密鍵がサーバーに送られる | RFC 4252 で送るとされているのは、公開鍵と署名など。秘密鍵そのものは入っていない |
| authorized_keys のコメントで鍵を区別している | sshd はコメントを何にも使わない。区別したいなら指紋で |
| 鍵を登録したのにパスワードを聞かれる=鍵が壊れた | まず ~/.ssh・authorized_keys・ホームの権限を疑う |
| 指紋が違う=別の鍵 | SHA256 と MD5 の表し方の違いかも。そろえてから比べる |
| 1つの秘密鍵をみんなで共有すればラク | どの人・どの端末の鍵か区別できなくなり、1人やめるときも全員の鍵を替えることになる。1人(1端末)1ペアにして、公開鍵を必要なサーバーに登録する |
新人さん「6つ全部やったことがあります」
おうどん「全部やった人は、もう中級者だよ」
……失敗の数だけ、見本帳はきれいになります。
大将「お客さん、見本帳に同じ名前が12人いるんですが」
おうどん「全部、別の端末の私です」
……コメントに端末名を書いておくと、大将も助かります。
ここから先は上級者向け。読み飛ばしてもOKです。
秘密鍵ファイルの中には、公開鍵も入っている
パスフレーズの章で、ちょっと気になることがありました。
パスフレーズ付きの秘密鍵でも、指紋は出るのか。.pub を消して、秘密鍵だけで試してみます。
rm -f pp_key.pub ssh-keygen -l -f pp_key
256 SHA256:HLBgYeWydciiUrIsrKn1WntRLQvt2mj4GXEMUj2fY2E no comment (ED25519)
(pp_key.pub は、検証のために udon_key.pub をコピーして置いていたものです。それを消してから実行しました)
パスフレーズを聞かれずに、指紋が出ました。しかも、コメントは no comment。
理由は、OpenSSH の秘密鍵ファイルの形式を書いた PROTOCOL.key にあります。この形式は、
- 先頭の目印(
openssh-key-v1)、暗号の方式、鍵から暗号の鍵を作る方式(KDF)とその設定 - 鍵の数
- 公開鍵(暗号化されていない)
- 暗号化された秘密鍵の一覧(秘密鍵とコメントの組)
の順に並んでいます。公開鍵は暗号化されずに入っていて、コメントは秘密鍵と一緒に暗号化される側にいる。だから、パスフレーズなしで指紋は計算できても、コメントは読めなかったわけです。
pp_key「顔写真は表に貼ってあります。名前は金庫の中です」
大将「名札は、表に付けておいてほしかった」
……「no comment」が、記者会見みたいになっている。
秘密鍵ファイルからは、公開鍵を取り出すこともできます(ssh-keygen -y)。今回の検証では、パスフレーズなしの 3072 ビットの RSA 鍵でも取り出せました。ただし、パスフレーズの章で見たとおり、パスフレーズ付きの鍵では -y は正しいパスフレーズを求めました。-l とは扱いが違うので、指紋を見たいだけなら -l が手軽です。
ssh-keygen -q -t rsa -b 3072 -N "" -C rsa-key -f ./rsa_key ssh-keygen -y -f rsa_key | cut -c1-48
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDJbnkI7SUd
(-y の出力は1行が長いので、cut で先頭48文字だけ表示しています)
逆向き(公開鍵だけで署名する)は、もちろんできません。公開鍵 udon_key.pub と注文書だけを入れたフォルダで試しました。
ssh-keygen -Y sign -f udon_key.pub -n file order.txt
No private key found for public key "udon_key.pub"
(ssh-agent を使わない状態で実行。終了コードは 255 でした)
ssh-keygen のマニュアルでは、-Y sign の -f には秘密鍵か、秘密鍵の半分が ssh-agent にある公開鍵を指定する、とされています。なお、今回の検証では、同じフォルダに秘密鍵 udon_key も置いてある状態で -f udon_key.pub を指定すると、署名ができました。中でどう秘密鍵を探しているかは確かめていないので、ここでは「公開鍵だけでは署名できなかった」という結果にとどめます。
新人さん「見本だけ持っていっても、サインは書けないんですね」
おうどん「なぞり書きで通るなら、見本帳の意味がない」
……なぞり書きでも、本人の手じゃないと通りません。
署名は「そのセッション専用」:RFC 4252の中身
もう一歩だけ、ログインの中身に入ります。
サーバーへのサインは、その接続ごとのお題に対して書く。だから、サインはその接続に結びつく、という作りです。
RFC 4252 の7章では、署名の対象は次のものだと決められています。
- セッション識別子(その接続ごとに決まる値)
- 認証のリクエストの中身(ユーザー名、サービス名、publickey という方式名、公開鍵の方式名、公開鍵など)
セッション識別子は接続ごとに決まるので、署名もその接続に結びつきます。
悪い人「昨日のサイン、写真に撮っておきました」
大将「それは昨日のお題へのサインですね。今日のお題は違います」
……合言葉が毎日変わる店で、昨日の合言葉は通じません。
もう1つ、RFC 4252 には署名なしの問い合わせも書かれています。クライアントは、署名の欄を空にして「この公開鍵なら受け付けてもらえますか」と先に聞ける。サーバーは、受け付けるなら SSH_MSG_USERAUTH_PK_OK、だめなら SSH_MSG_USERAUTH_FAILURE で返します。RFC には、パスフレーズの入力や署名の計算という手間をかける前に、鍵が使えるか確かめられる、という目的も書かれています。問い合わせを飛ばして、いきなり署名を送ってもかまいません。
おうどん「大将、この見本、見本帳に載ってます?」
大将「載ってますよ。じゃあ、サインをどうぞ」
……載っていない人に、わざわざ書かせない。お互いにやさしい手順です。
そして、サーバー側の判定は2つです。
- その公開鍵が、そのユーザーの認証に使ってよい鍵か(OpenSSH の sshd なら、主に authorized_keys に載っているか)
- 署名が正しいか
両方満たせば、この方式は成功。RFC には、サーバーがさらに別の認証を求めてもよい、とも書かれています(多要素認証のように)。
ここで、さっきの「他人の鍵でサインした注文書」の検証結果を見てください。今回の検証では、別の鍵ペア other_key で同じ内容の注文書に署名し、2つの方法で確かめました。
ssh-keygen -Y verify -f allowed_signers -I oudon@example -n file -s order2.txt.sig < order2.txt ssh-keygen -Y check-novalidate -n file -s order2.txt.sig < order2.txt
Could not verify signature.
Good "file" signature with ED25519 key SHA256:gZzmzJffo2mGwMEamsYjZdbkphylu72N7kGk6AW+Td4
(1行目が1つ目のコマンド(終了コード 255)、2行目が2つ目のコマンド(終了コード 0)の結果です)
check-novalidate は、ssh-keygen のマニュアルによると、署名の形が正しいかだけを確かめ、署名した人が許可されているかは確かめないモードです。
つまり、署名そのものは正しい(Good)けれど、見本帳(allowed_signers)に載っていない人のサインだった。
他人「サインは、ちゃんと書けてますよね?」
大将「上手です。でも、見本帳に載っていない方です」
……字がきれいでも、常連さんではない。
SSH のログインも同じ構造で、サーバーは「署名が正しいか」と「その鍵が許可されているか」の両方を見ます。authorized_keys は、その「許可されているか」の部分を担う見本帳なんです。
ついでに、名前空間(-n)を変えて確かめた結果も載せておきます。
ssh-keygen -Y verify -f allowed_signers -I oudon@example -n email -s order.txt.sig < order.txt
Couldn't verify signature: namespace does not match
Could not verify signature.
(終了コードは 255)
file 用に書いたサインは、email 用としては通りません。用途ごとにお題の欄を分けておく、という仕組みです。
Ed25519とRSA:大きさの違い
最後に、鍵の種類の話を少しだけ。
今回の検証環境で、Ed25519 の鍵と、3072 ビットの RSA の鍵を並べてみました。
awk '{print $1, length($2)}' udon_key.pub rsa_key.pub
wc -c udon_key rsa_key
ssh-ed25519 68
ssh-rsa 544
399 udon_key
2590 rsa_key
2989 total
(1〜2行目が公開鍵の本体(Base64 部分)の文字数、3〜5行目が秘密鍵ファイルのバイト数です)
公開鍵の本体は、Ed25519 が 68 文字、RSA(3072 ビット)が 544 文字。8倍くらい違います。
authorized_keys に並べたとき、チャットで共有したとき、短いほうが見やすいのは確かです。
RSA「長いのは、歴史の重みです」
Ed25519「短いのは、ただの効率です」
……どっちも正しいことを言っているのに、なぜかケンカに聞こえる。
どちらを選ぶかは、接続先が対応しているかで決まることもあります。古い機器が Ed25519 に対応していないなら RSA を使う、という判断もありえます。
迷ったら、まず接続先の対応を確認し、対応していれば -t ed25519 を明示して作る、が手堅い順番です。
新人さん「じゃあ両方作って、両方登録しておけば……」
おうどん「見本帳に、同じ人の見本が2枚。管理する鍵が2本に増える」
……使わない鍵は、見本帳から外すところまでが鍵の管理です。
まとめ:見本は配る、手は離さない
冒頭の新人さんは、秘密鍵も念のため送っていました。
新人さん「送っちゃった秘密鍵、どうしましょう」
おうどん「その鍵ペアはもう使わない。新しく作って、新しい公開鍵を登録し直して、古い公開鍵は authorized_keys から外す」
新人さん「右手、生え変わるんですね」
おうどん「鍵はね。本物の右手は大事にして」
……鍵の世界は、手を作り直せるのが救いです。
今回のポイントを並べると、
- 鍵ペアは、公開鍵(
.pub)と秘密鍵の2つで1組。渡すのは.pubだけ - ログインでは、秘密鍵で書いた署名を、サーバーが公開鍵で確かめる。秘密鍵そのものは送らない
- サインは、その接続のお題(セッション識別子)に対して書くので、その接続に結びつく
- サーバーは「署名が正しいか」と「その鍵が authorized_keys に載っているか」の両方を見る
- authorized_keys は
>>で追記。~/.ssh・authorized_keys・ホームの権限がゆるいと使われない - 同じ鍵かは指紋で確かめる。SHA256 と MD5 は表し方が違うだけ
- 秘密鍵ファイルには公開鍵も暗号化されずに入っている。だからパスフレーズ付きでも指紋は出る。公開鍵だけでは署名できない
- パスフレーズは忘れたら取り戻せない
新人さん「8行は、さすがに右手に書ききれません」
おうどん「書かなくていい。右手は鍵を守るので忙しい」
……右手、今日いちばんの働き者です。
公開鍵は見本として配り、秘密鍵は自分の手として離さない。
まずは自分のパソコンで ssh-keygen -l -f ~/.ssh/id_ed25519.pub(RSA なら id_rsa.pub)を1回だけ打って、自分の鍵の指紋を眺めてみてください。
自分の筆跡を知っておくと、見本帳の前で迷わずにすみます🍜
参考資料
- ssh(1) — 公開鍵認証の考え方(ユーザーが鍵ペアを作る、サーバーは公開鍵を知り秘密鍵はユーザーだけが知る、クライアントは秘密鍵を持っていることを証明する)、authorized_keys、秘密鍵ファイルの権限と他人がアクセスできると無視されること、認証エージェント
- sshd(8) — authorized_keys の既定の場所と1行の形式、コメントは使われないこと、推奨の権限、ファイル・~/.ssh・ホームが他人から書き込めると StrictModes で使われないこと
- ssh-keygen(1) — 引数なしで Ed25519 を作ること、公開鍵は同じ名前に .pub を付けたファイル、-C・-f・-N・-p・-y・-l・-E(既定は SHA256)、-Y sign・-Y verify・-Y check-novalidate・-n、忘れたパスフレーズは取り戻せないこと(OpenBSD 版の最新のマニュアル)
- RFC 4252:The Secure Shell (SSH) Authentication Protocol — 7章の公開鍵認証(送る項目、署名の対象にセッション識別子が入ること、署名なしの問い合わせと SSH_MSG_USERAUTH_PK_OK、サーバーの判定)
- PROTOCOL.key(OpenSSH portable) — OpenSSH の秘密鍵ファイルの形式。公開鍵が暗号化されずに入り、秘密鍵とコメントが暗号化されること
確認日:2026-10-12。

コメント