SSH (Secure Shell) は、ネットワーク越しに別のコンピュータへ安全にアクセスし、リモート操作とファイル転送を行うためのプロトコル。Telnet / rlogin など平文プロトコルが抱えていた盗聴・改ざん・なりすましを一掃した。本稿では接続の 3 ステップ、公開鍵認証、ファイル転送、ポートフォワーディング、最低限おさえたい設定までを実用ベースで整理する。
SSH の立ち位置 #
SSH は TCP 22 番ポートで動き、RFC 4253 で標準化されている。サーバ運用・GitHub への push・CI/CD のデプロイなど現代の開発に不可欠なインフラの一つ。OpenSSH (OpenBSD 由来の OSS 実装) がほぼあらゆる Linux / macOS / Windows 10 以降に同梱され、事実上の標準となっている。
Telnet はユーザ名 / パスワード / コマンド出力すべてを平文でネットワークに流す。同セグメントで tcpdump を回せば認証情報が丸見えだった。SSH は暗号化 + ホスト認証 + ユーザ認証を 1 つのプロトコルに統合し、この問題を完全に解いた。
接続の 3 ステップ #
SSH の接続シーケンスは次の順で進む。この骨格を掴めば仕組みの理解は終わったも同然。
~/.ssh/known_hosts に保存。ChaCha20-Poly1305 や AES-GCM で暗号化。自分で動かして確かめる — TCP 接続から鍵交換・ホスト認証・ユーザ認証を経て暗号化シェルが確立するまでを 1 ステップずつ追える。
ホスト認証 — TOFU モデル #
初回接続時、クライアントには未知のホスト鍵フィンガープリントが提示される。これを known_hosts に保存し、2 回目以降は一致を検証する。これを TOFU (Trust On First Use) モデルと呼ぶ。
The authenticity of host 'example.com' can't be established.
ED25519 key fingerprint is SHA256:abcd1234...
Are you sure you want to continue connecting (yes/no/[fingerprint])?TOFU の盲点は「最初の 1 回」。厳密な運用ではサーバ管理者が事前にフィンガープリントを別経路(社内 Wiki / 認証アプリ)で公開しておき、初回接続でその値と一致するかを目視確認する。
ユーザ認証 — 2 方式 #
| 方式 | 仕組み | 推奨度 |
|---|---|---|
| パスワード認証 | ユーザ名 + パスワードを暗号化チャネル上で送信 | △ ブルートフォースの的 |
| 公開鍵認証 | クライアントが秘密鍵で署名、サーバが公開鍵で検証 | ◎ 本番運用の定石 |
本番ではパスワード認証を無効化し、公開鍵認証だけを許可するのが標準的な構え。
公開鍵認証の仕組み #
公開鍵認証では、対 (ペア) の鍵をクライアント側で作る。
- 秘密鍵 — 自分の手元から絶対に出さない
- 公開鍵 — サーバへ事前にコピーしておく
$ ssh-keygen -t ed25519 -C "your@email"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/user/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Your identification has been saved in /home/user/.ssh/id_ed25519
Your public key has been saved in /home/user/.ssh/id_ed25519.pub
# 秘密鍵: ~/.ssh/id_ed25519 (絶対に外に出さない)
# 公開鍵: ~/.ssh/id_ed25519.pub (サーバへコピー)鍵長が短く、強度が高く、生成・検証も速い。互換性で困らない限り今ならまず Ed25519 を選んでよい。古い OpenSSH (7.0 未満) でしか接続できない場合のみ RSA-4096 にフォールバック。
サーバへ公開鍵を登録 #
$ ssh-copy-id user@example.com
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/user/.ssh/id_ed25519.pub"
Number of key(s) added: 1
# サーバ側の ~/.ssh/authorized_keys に追記される (パーミッション 600 も自動セット)チャレンジ・レスポンスの流れ #
authorized_keys の公開鍵で署名を検証。一致すれば認証成功。署名計算はクライアント側のみで実行される。秘密鍵本体は線の上を一度も走らない。これがパスワード認証より圧倒的に強い理由。さらに毎回のチャレンジが乱数なのでリプレイ攻撃にも耐性がある。
基本コマンド #
# 標準接続
$ ssh user@example.com
# ポート指定
$ ssh -p 2222 user@example.com
# 鍵ファイル指定
$ ssh -i ~/.ssh/special_key user@host
# 単発コマンド実行 (シェルを起こさない)
$ ssh user@host 'uptime'
# 詳細ログ (トラブル切り分け時)
$ ssh -vvv user@host# 新規鍵作成
$ ssh-keygen -t ed25519
# パスフレーズ変更
$ ssh-keygen -p -f ~/.ssh/id_ed25519
# 公開鍵のフィンガープリント確認
$ ssh-keygen -l -f ~/.ssh/id_ed25519.pub
# 鍵更新時に known_hosts から旧鍵を削除
$ ssh-keygen -R example.com秘密鍵にパスフレーズを付けると毎回の打ち込みが面倒。ssh-agent を起動し ssh-add ~/.ssh/id_ed25519 で 1 度だけ復号しておけば、セッション中は再入力不要。パスフレーズなしの鍵は使わないのが鉄則。
ファイル転送 #
SSH の暗号化チャネル上で動くファイル転送方式は 3 つ。用途で使い分ける。
# scp — 単発コピー (シンプル、小規模向け)
$ scp local.txt user@host:/path/
$ scp -r local-dir/ user@host:/path/
# sftp — 対話的なファイル操作 (ls / cd / get / put)
$ sftp user@host
sftp> get remote.txt
sftp> put local.txt
# rsync over SSH — 差分転送 (大量ファイル / バックアップに最適)
$ rsync -avz -e ssh src/ user@host:/dst/ポートフォワーディング #
SSH 接続の暗号化チャネルに別のアプリの通信を相乗りさせる機能。3 パターンある。
| パターン | フラグ | 用途の典型例 |
|---|---|---|
| ローカルフォワード | -L |
手元から踏み台越しのリモート DB に直接接続 |
| リモートフォワード | -R |
手元のアプリを一時的に外部サーバへ公開 (ngrok 代替) |
| ダイナミック | -D |
SOCKS プロキシ。ブラウザを SSH 経由で出口接続 |
# bastion に接続しつつ、ローカル 5432 を bastion の見える 5432 に転送
$ ssh -L 5432:localhost:5432 user@bastion.example.com
# 別ターミナルで localhost に対して psql を叩くだけ
$ psql -h localhost
psql (16.0)
postgres=#多段踏み台 — ProxyJump #
# 1 段 — bastion 経由で internal へ
$ ssh -J user@bastion user@internal-server
# 多段 — b1 → b2 → target
$ ssh -J user@b1,user@b2 user@target
# 古い ProxyCommand 記法 (今は -J で済むので非推奨)最低限おさえたいサーバ設定 #
/etc/ssh/sshd_config で次の 3 行は必ず効かせる。
# /etc/ssh/sshd_config
PermitRootLogin no # root 直接ログイン禁止
PasswordAuthentication no # パスワード認証無効 (公開鍵のみ)
PubkeyAuthentication yes # 公開鍵認証を有効化
# 反映前に必ず構文チェック
$ sudo sshd -t
$ sudo systemctl reload sshd設定変更後は今のセッションを閉じない。別ターミナルで再接続テストして、新セッションが確立したのを確認してから古いセッションを切る。PasswordAuthentication no を入れたつもりで打ち間違え、再ログイン不能になった事故は無数にある。
~/.ssh/config の便利設定 #
接続先ごとに別名を切ると ssh internal と打つだけで済む。チームでも個人でも、ある程度サーバが増えたら必須。
# 踏み台
Host bastion
HostName bastion.example.com
User admin
Port 2222
IdentityFile ~/.ssh/id_ed25519_admin
# 内部サーバ (ProxyJump で踏み台経由)
Host internal
HostName 10.0.0.5
User deploy
IdentityFile ~/.ssh/id_ed25519_deploy
ProxyJump bastion
# 以後は ssh internal だけで内部サーバに入れる参考 #
- 『図解入門 TCP/IP 第 2 版 ── 仕組み・動作が見てわかる』 6-5-2 SSH (管理アクセスプロトコル)
- OpenSSH 公式ドキュメント
- RFC 4253 — The Secure Shell (SSH) Transport Layer Protocol