本文へ移動
購読
GUIDE#security更新 2026.10.02

ssh-keygenでSSH鍵を作る:ed25519・パスフレーズ・ssh config・エージェントの使い方

ssh-keygenでed25519の鍵を作り、パスフレーズ・ssh config・ssh-agentまで整える手順。指紋による鍵の棚卸しと定番エラーの直し方も実行例付き。

level
初級
time
約20分
stack
OpenSSH 9.6p1(Ubuntu 24.04)/ Windows 11のOpenSSHクライアント / macOS
author
@ryoma_t
// 前提条件
ターミナル(またはPowerShell)の基本操作 / 接続先サーバーに公開鍵を登録できること
ED25519鍵のパーミッションと指紋を確認し、ssh -Gで~/.ssh/configの接続先設定が効いているかを確かめたターミナル
画像:nagoya.dev(実際の画面・実行結果をもとに作成)

ssh-keygenとは、SSHの公開鍵認証に使う鍵ペアの作成・パスフレーズの変更・指紋の表示などを行う、OpenSSH付属のコマンドです。鍵は1回作れば終わりではなく、どの端末のどの鍵がどのサーバーに登録されているかを後から説明できる状態で運用して、初めて安全になります。

このガイドは手元のPC側の作業に絞っています。ed25519での鍵の作成、パスフレーズ、~/.ssh/config の書き方、ssh-agent、指紋を使った棚卸しまでを、Ubuntu 24.04のOpenSSH 9.6p1で実行した結果とともに示します。サーバー側でパスワード認証を止める設定は、Linuxサーバーの基本ハードニングで扱っています。

この記事でわかること

  • ed25519で鍵を作るコマンドと、-a・-C・-f を指定する理由
  • パスフレーズの変更方法と、ssh-agentで入力回数を減らす設定(Linux・macOS・Windows)
  • ssh configの書き方:Hostごとの鍵、IdentitiesOnly、ProxyJump と、ssh -G での確認
  • 指紋(fingerprint)で「どの鍵がどこに登録されているか」を突き合わせる方法
  • 「Too many authentication failures」など、定番エラーの原因と直し方

鍵の種類はed25519を選ぶ

新しく作る鍵はed25519にします。鍵長を選ぶ余地がなく(公開鍵は常に256ビット)、署名が速く、公開鍵の文字列も短いので、authorized_keysやGitHubの設定画面で扱いやすいからです。OpenSSH 9.5からは、-t を省略したときの既定もed25519になりました。Ubuntu 24.04(OpenSSH 9.6p1)で ssh-keygen を引数なしで実行すると、実際に ssh-ed25519 の鍵ができます。

種類作成時の指定使う場面注意点
ed25519-t ed25519新規に作る鍵のすべてOpenSSH 6.5より古いサーバーや、一部の古いネットワーク機器は非対応
RSA-t rsa -b 4096ed25519に対応しない相手に接続するときだけ鍵長を省略すると3072ビット。2048ビット未満は作らない
ECDSA-t ecdsa -b 256機器側がECDSAしか受け付けない場合ed25519が使えるなら選ぶ理由はない
ed25519-sk-t ed25519-sk管理者用など、FIDO2のセキュリティキーに鍵を縛りたい場合OpenSSH 8.2以降。キーを挿して触らないと認証できない
DSA-t dsa使わないOpenSSH 10.0で削除済み。9.6ではまだ作れてしまう

-sk の鍵は、秘密鍵ファイルの中身が「セキュリティキーを呼び出すための手がかり」だけになり、ファイルが盗まれてもキー本体がなければ使えません。検証用のコンテナのようにキーが接続されていない環境で作ろうとすると、Key enrollment failed: device not found で失敗します。

SSH鍵を作成する:ssh-keygenの基本

用途ごとに鍵を分け、ファイル名で区別できるようにしておきます。業務サーバー用と個人のGitHub用を同じ鍵にすると、片方が漏れたときに両方を作り直すことになるからです。以下の例に出てくる taro(ユーザー名)、work-laptop(端末名)、203.0.113.10(サーバーのアドレス)は例なので、自分の値に置き換えてください。

terminal(手元のPC)
$ ssh-keygen -t ed25519 -a 100 -C "taro@work-laptop" -f ~/.ssh/id_ed25519_work
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/taro/.ssh/id_ed25519_work
Your public key has been saved in /home/taro/.ssh/id_ed25519_work.pub
The key fingerprint is:
SHA256:u5M/R6M6jMxzwA/GDIBoNaEXr42jXmto/bvKwHWwybI taro@work-laptop
The key's randomart image is:
+--[ED25519 256]--+
|...=.            |
|o.o +            |
|.. + .           |
|  o O            |
| . O B  S        |
|. = o B  .  o    |
| Eo. + *.. o .   |
|.o+o. = B.o .    |
|...+o+ooo=.o     |
+----[SHA256]-----+
  • -t ed25519:鍵の種類。
  • -a 100:秘密鍵ファイルをパスフレーズで暗号化するときの鍵導出(bcrypt_pbkdf)の繰り返し回数。既定は16です。検証環境で復号にかかる時間を測ると、16で約0.2秒、100で約1秒、200で約1.7秒でした。盗まれたファイルへの総当たりはこの倍率で遅くなり、正規の利用者は1日数回の入力で1秒待つだけなので、100前後が落としどころです。
  • -C:公開鍵の末尾に付くコメント。認証には使われない単なるラベルですが、サーバーのauthorized_keysを見たときに「誰のどの端末の鍵か」を判別する唯一の手がかりになります。省略すると ユーザー名@ホスト名 が入ります。
  • -f:保存先。省略すると ~/.ssh/id_ed25519 になり、2本目を作るときに上書きの確認が出ます。

できあがったファイルのパーミッションも確認します。秘密鍵が -rw-------(600)、公開鍵が -rw-r--r--(644)、~/.ssh ディレクトリが700になっていれば正常です。秘密鍵の先頭行は -----BEGIN OPENSSH PRIVATE KEY----- で、パスフレーズを付けても付けなくても見た目は同じなので、暗号化されているかどうかは次の章の方法で確かめます。

標準でOpenSSHクライアントが入っているWindows 10・11でも、PowerShellで同じコマンドがそのまま使えます。~ は C:\Users\ユーザー名 を指し、鍵は C:\Users\ユーザー名\.ssh\ に保存されます。

パスフレーズを付ける理由と、変更・確認の方法

パスフレーズはサーバーへ送られるものではなく、手元の秘密鍵ファイルを暗号化するための合言葉です。ノートPCの盗難、バックアップからの流出、同期フォルダへの誤コピーなど、ファイルそのものが第三者の手に渡ったときに、すぐには使わせないための最後の防壁になります。空にしてよいのは、次の章で説明する接続先を限定した自動処理用の鍵だけです。

terminal(手元のPC)
# パスフレーズを変更する(付いていない鍵に後から付けるのも同じ操作)
$ ssh-keygen -p -f ~/.ssh/id_ed25519_work
Enter old passphrase:
Key has comment 'taro@work-laptop'
Enter new passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved with the new passphrase.

# パスフレーズが合っているか確かめる(正しければ公開鍵が表示される)
$ ssh-keygen -y -f ~/.ssh/id_ed25519_work

# コメントだけを書き換える
$ ssh-keygen -c -C "taro@work-laptop-2026" -f ~/.ssh/id_ed25519_work

-y は秘密鍵から公開鍵を作り直すオプションで、パスフレーズが付いていれば入力を求められます。求められずに公開鍵が出てきたら、その鍵は暗号化されていません。間違ったパスフレーズを入れると incorrect passphrase supplied to decrypt private key と表示されます。パスフレーズを忘れた鍵を復旧する手段はないので、新しい鍵を作り、登録先の公開鍵を差し替えます。

公開鍵をサーバーとGitHubに登録する

サーバーには ssh-copy-id -i ~/.ssh/id_ed25519_work.pub ユーザー名@サーバーのアドレス で、~/.ssh/authorized_keys に公開鍵を1行追記します。GitHubやGitLabには、.pub ファイルの中身(ssh-ed25519 AAAA… コメント の1行)を設定画面に貼り付けます。.pub の付かない秘密鍵のほうを貼る事故は、ファイル名を補完したときに起こりがちなので、貼る前に先頭が ssh-ed25519 で始まることを目で確認してください。

バックアップの転送など、パスフレーズなしで動かす必要がある鍵は、authorized_keys側でできることを絞ります。行の先頭にオプションを付けると、その鍵では指定したコマンドしか実行できず、指定した送信元からしか使えなくなります。

~/.ssh/authorized_keys(バックアップ受け側サーバー)
restrict,from="192.0.2.50",command="/usr/local/bin/backup-receive" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...(略) backup@nas01-2026

restrict はポート転送・エージェント転送・端末割り当てなどをまとめて禁止する指定です。この鍵が漏れても、攻撃者にできるのは192.0.2.50からバックアップ受信用のスクリプトを起動することだけになります。検証環境で同じ形の行を登録し、この鍵で id を実行させようとしたところ、id は実行されずに backup-receive が起動し、要求したコマンドは環境変数 SSH_ORIGINAL_COMMAND に入って渡されました。

ssh configの書き方

~/.ssh/config は、接続先ごとの設定をまとめるファイルです。仕組みで押さえるべきことは1つで、上から順に読まれ、各項目は「最初に見つかった値」が使われます。したがって個別のHostを上に、全体の既定値(Host *)を一番下に書きます。Host * を先頭に書いて User admin を入れると、下に書いた個別の User(次の例では taro)は無視されます。

~/.ssh/config
# 分割した設定を読み込むなら、どのHostよりも前に書く
Include ~/.ssh/config.d/*

Host web01
    HostName 203.0.113.10
    User taro
    IdentityFile ~/.ssh/id_ed25519_work
    IdentitiesOnly yes

# 踏み台を経由して社内のDBサーバーへ
Host bastion
    HostName 203.0.113.5
    User taro
    IdentityFile ~/.ssh/id_ed25519_work
    IdentitiesOnly yes

Host db01
    HostName 10.0.20.15
    User taro
    IdentityFile ~/.ssh/id_ed25519_work
    IdentitiesOnly yes
    ProxyJump bastion

Host github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_github
    IdentitiesOnly yes

# 全体の既定値は最後に置く
Host *
    AddKeysToAgent yes
    ServerAliveInterval 30
    StrictHostKeyChecking accept-new
  • IdentitiesOnly yes:IdentityFile で指定した鍵だけを使います。指定しないと、ssh-agentに入っている鍵を片端から提示し、サーバーの試行回数の上限に先に達して切断されます(つまずきポイントで再現しています)。
  • ProxyJump:踏み台を経由して接続します。鍵は手元から出ず、踏み台には通信の中継だけを任せます。似た目的で使われる ForwardAgent yes は、接続している間、踏み台のrootがあなたのエージェントを使えてしまうので、ProxyJumpで済む場面では使いません。
  • StrictHostKeyChecking accept-new:初めての接続先のホスト鍵は自動で記録し、記録済みの鍵が変わったときは接続を拒否します。no にすると後者の保護まで消えるので使いません。
  • ServerAliveInterval 30:30秒ごとに生存確認を送り、途中の機器にセッションを切られるのを防ぎます。

書いた設定が意図どおりに効いているかは、接続せずに ssh -G ホスト名 で確かめられます。最終的に使われる値がすべて小文字の項目名で出力されるので、必要な行だけを絞り込みます。

terminal(手元のPC)
$ ssh -G web01 | grep -E '^(hostname|user|identityfile|identitiesonly) '
user taro
hostname 203.0.113.10
identitiesonly yes
identityfile ~/.ssh/id_ed25519_work

他のユーザーが書き込める状態のconfigファイルがあると、sshは Bad owner or permissions on ~/.ssh/config で起動を拒否します。chmod 600 ~/.ssh/config で直してください。dotfilesをリポジトリで管理している場合、ここに社内サーバーのIPアドレスや踏み台の構成が載ることになるので、公開リポジトリに入れないでください。

ssh-agentでパスフレーズの入力を減らす

ssh-agentは、復号済みの秘密鍵をメモリに保持して署名を代行するプロセスです。パスフレーズの入力は最初の1回だけになり、鍵そのものはエージェントの外に出ません。Linuxでは -t で保持時間を指定し、席を離れている間も使える状態が続かないようにします。

terminal(Linux)
# エージェントが動いていなければ起動(多くのデスクトップ環境では自動で起動済み)
$ eval "$(ssh-agent -s)"

# 1時間だけ保持する
$ ssh-add -t 3600 ~/.ssh/id_ed25519_work
Enter passphrase for /home/taro/.ssh/id_ed25519_work:
Identity added: /home/taro/.ssh/id_ed25519_work (taro@work-laptop)
Lifetime set to 3600 seconds

$ ssh-add -l      # 保持している鍵の指紋一覧
$ ssh-add -D      # 全部消す(席を離れる前に)

AddKeysToAgent yes をconfigに入れておけば、ssh-add を打たなくても、最初の接続時にパスフレーズを入れた鍵がエージェントに登録されます。macOSでは ssh-add --apple-use-keychain ~/.ssh/id_ed25519_work でパスフレーズをキーチェーンに保存し、configに UseKeychain yes を書くと再起動後も入力が不要になります。この項目はmacOS以外では Bad configuration option になるので、configを複数のOSで共有するなら IgnoreUnknown UseKeychain を先に書きます。

PowerShell(管理者として実行)
# Windowsのssh-agentサービスは既定で無効になっている
Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent

# ここからは通常のPowerShellで
ssh-add $env:USERPROFILE\.ssh\id_ed25519_work

追加した鍵をユーザーのレジストリに暗号化して保存し、再起動後も保持し続けるのが、Windows同梱のssh-agent(執筆時点)の動きです。Linuxの -t のような時間切れを前提にせず、ログオンさえできれば鍵が使える状態が続くものとして扱ってください。共用PCや貸与期間の終わった端末は、ssh-add -D で消してから返却します。

指紋で鍵を棚卸しする

指紋(fingerprint)は公開鍵から計算した短い値で、鍵の同一性を人間が照合するために使います。手元の鍵、サーバーのauthorized_keys、sshdのログの3か所で同じ形式の指紋が出るので、「どの鍵がどこで使われたか」をたどれます。

terminal
# 手元の鍵の指紋
$ ssh-keygen -l -f ~/.ssh/id_ed25519_work.pub
256 SHA256:u5M/R6M6jMxzwA/GDIBoNaEXr42jXmto/bvKwHWwybI taro@work-laptop (ED25519)

# サーバー側:登録されている鍵を1行ずつ指紋にする
$ ssh-keygen -l -f ~/.ssh/authorized_keys
256 SHA256:u5M/R6M6jMxzwA/GDIBoNaEXr42jXmto/bvKwHWwybI taro@work-laptop (ED25519)
256 SHA256:/dKdsgqZeJ4VepgZiJGbSpYIJISYbOS0zak78vCE4aw old-laptop-2023 (ED25519)
256 SHA256:H494sDORfhgI9IhKNle4yGtwIP7CN2zJga4WH59fZbA backup@nas01-2026 (ED25519)

# サーバー側:ログインに使われた鍵はsshdのログに指紋で残る
$ sudo journalctl -u ssh -g 'Accepted publickey'
# 出力(検証環境。日時・ホスト名・プロセス番号は省略)
Accepted publickey for taro from 127.0.0.1 port 35398 ssh2: ED25519 SHA256:H494sDORfhgI9IhKNle4yGtwIP7CN2zJga4WH59fZbA
Accepted publickey for taro from 127.0.0.1 port 35400 ssh2: ED25519 SHA256:u5M/R6M6jMxzwA/GDIBoNaEXr42jXmto/bvKwHWwybI

この例では、手元の鍵とauthorized_keysの1行目の指紋が一致し、ログからは1行目と3行目の鍵が使われたことがわかります。2行目(コメント old-laptop-2023)が保存期間中のログに一度も現れていなければ、誰の鍵か確認したうえで削除する候補です。古い管理画面が MD5: で始まる形式の指紋しか表示しない場合は、-E md5 を付けると同じ形式で出せます。Ubuntuのsshdのユニット名は ssh、RHEL系では sshd です。

鍵の入れ替えは、止まらない順番で行います。新しい鍵をコメントに年を入れて作る、新しい公開鍵をauthorized_keysに追記する、ssh -i ~/.ssh/新しい鍵 -o IdentitiesOnly=yes で入れることを確認する、指紋で古い行を特定して削除する、configの IdentityFile を書き換える、の順です。端末の紛失や退職のときは同じ作業をその日のうちに行い、GitHubなどのサービス側に登録した公開鍵も忘れずに消します。

接続先のホスト鍵は ~/.ssh/known_hosts に記録されます。サーバーを再構築してホスト鍵が変わったときは、サーバーのコンソールで ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub を実行して新しい指紋を確認し、手元の古い記録を ssh-keygen -R 203.0.113.10 で消してから接続し直します。-F を使えば、特定のホストが記録されているかを検索できます。

SSH鍵で署名する(ssh-keygen -Y)

ssh-keygenは、ファイルやGitのコミットへの署名にも使えます。GPG鍵を別に管理しなくても、既に配っているSSH鍵で「誰が作ったファイルか」を検証できるのが利点です。-n は署名の用途を示す名前空間で、署名時と検証時に同じ値を指定します。

terminal
# 署名(memo.txt.sig ができる)
$ ssh-keygen -Y sign -f ~/.ssh/id_ed25519_work -n file memo.txt
Enter passphrase:
Signing file memo.txt
Write signature to memo.txt.sig

# 検証する側は「誰の公開鍵か」を allowed_signers に書いておく
$ echo "[email protected] $(cut -d' ' -f1,2 ~/.ssh/id_ed25519_work.pub)" > allowed_signers
$ ssh-keygen -Y verify -f allowed_signers -I [email protected] -n file -s memo.txt.sig < memo.txt
Good "file" signature for [email protected] with ED25519 key SHA256:u5M/R6M6jMxzwA/GDIBoNaEXr42jXmto/bvKwHWwybI

# memo.txt が1文字でも書き換えられていれば失敗する
Signature verification failed: incorrect signature
Could not verify signature.

# Git(2.34以降)のコミット署名に使う
$ git config --global gpg.format ssh
$ git config --global user.signingkey ~/.ssh/id_ed25519_github.pub
$ git config --global commit.gpgsign true

動作確認

鍵とconfigを整えたら、次の3つを確認します。1つ目でファイルとパーミッション、2つ目で鍵の種類とコメント、3つ目で接続時に使われる設定がわかります。

terminal(手元のPC)
ls -l ~/.ssh
# 秘密鍵と config が -rw-------、公開鍵が -rw-r--r-- になっていること

ssh-keygen -lv -f ~/.ssh/id_ed25519_work.pub
# 256 SHA256:... taro@work-laptop (ED25519) と、randomart が表示される

ssh -G web01 | grep -E '^(hostname|user|identityfile|identitiesonly) '
# user / hostname / identitiesonly yes / identityfile が意図どおりであること

実際に接続できるかは ssh -v 接続名 true(接続名はconfigの Host に書いた名前。例では web01)で確かめます。詳細ログのうち、Offering public key: …id_ed25519_work ED25519 SHA256:… explicit、Server accepts key、Authenticated to … using "publickey". の3行が順に出れば、configで指定した鍵で公開鍵認証が成功しています。explicit は「configやコマンドラインで明示された鍵」という意味で、エージェントから拾った鍵ではないことを示します。

つまずきポイント

「Received disconnect from … : Too many authentication failures」

ssh-agentに鍵が何本も入っていると、sshは正しい鍵より先に他の鍵を順に提示します。サーバーの MaxAuthTries(既定6)に達すると、正しい鍵を試す前に切断されます。検証環境で上限を3にし、エージェントに無関係な鍵を4本入れたところ、IdentitiesOnly なしのHostではこのエラーで切断され、IdentitiesOnly yes を書いたHostでは問題なく入れました。該当Hostに IdentityFile と IdentitiesOnly yes を書けば解決します。

「WARNING: UNPROTECTED PRIVATE KEY FILE!」「Permissions 0644 … are too open.」

秘密鍵が他のユーザーから読める状態だと、sshはその鍵を無視し、結果として Permission denied (publickey) になります。Linux・macOSでは chmod 600 ~/.ssh/id_ed25519_work で直ります。継承したアクセス権が原因になりやすいWindowsでは、PowerShellで icacls $env:USERPROFILE\.ssh\id_ed25519_work /inheritance:r を実行して継承を外し、続けて icacls $env:USERPROFILE\.ssh\id_ed25519_work /grant:r "$($env:USERNAME):(F)" で自分だけに権限を付け直します。

「WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!」

known_hostsに記録したホスト鍵と、接続先が提示した鍵が一致しません。サーバーの再構築やIPアドレスの使い回しが原因のことがほとんどですが、通信の乗っ取りでも同じ表示になります。前の章の手順どおり、コンソールなど別経路で新しい指紋を確認してから ssh-keygen -R で古い記録を消します。確認せずに消すことだけは避けてください。

鍵を作り直したのに古い鍵が使われる

エージェントに古い鍵が残っているか、configの IdentityFile が古いファイル名のままです。ssh-add -l で指紋を確認して ssh-add -d ~/.ssh/古い鍵 で外し、ssh -G ホスト名 | grep identityfile で参照先を確かめます。エージェントが再起動後も鍵を保持するWindowsでは、この症状が特に起きやすくなります。

よくある質問

ssh-keygenのパスフレーズとは何ですか?必要ですか?

手元の秘密鍵ファイルを暗号化するための合言葉で、サーバーには送られません。ファイルが盗まれてもすぐには使えないようにするためのもので、人が使う鍵には必ず付けます。入力の手間はssh-agentで1日数回に減らせます。忘れた場合は復旧できないため、鍵を作り直して登録先を差し替えます。

ssh-keygenの -C オプションとは?

公開鍵の末尾に付けるコメントを指定するオプションです。認証には使われませんが、サーバーのauthorized_keysやGitHubの一覧で「誰のどの端末の鍵か」を見分ける手がかりになります。利用者名・端末名・作成年を入れておくと、棚卸しや退職時の削除で迷いません。後から変えるときは -c と組み合わせます。

ssh-keygenのed25519とはどういう意味ですか?

Curve25519という楕円曲線を使った署名方式「EdDSA」の一種で、SSHの鍵の種類の1つです。鍵長が256ビットに固定され、RSAより鍵も署名も短く高速です。OpenSSH 9.5以降は、種類を指定せずにssh-keygenを実行したときの既定にもなっています。

作ったSSH鍵を削除するには?

削除用のコマンドはなく、秘密鍵と .pub のファイルを消します。先にサーバーのauthorized_keysやGitHubから公開鍵を外し、エージェントからも ssh-add -d で外してください。ssh-keygen -R は自分の鍵ではなく、known_hostsに記録した接続先のホスト鍵を消すオプションです。

まとめ

鍵はed25519で用途ごとに分け、-a 100 とパスフレーズで盗難に備え、コメントには利用者・端末・年を入れます。configは個別のHostを上、Host * を下に書き、IdentitiesOnly yes で提示する鍵を固定すると、接続トラブルの大半が消えます。そして指紋で手元・authorized_keys・ログを突き合わせられるようにしておけば、退職や紛失の日に「どの鍵を消せばよいか」を即答できます。

次に読む

$ subscribe --weekly
毎週月曜、企業ITとホームラボの要点を5分で。