SSH の世界に最初に触れたユーザーが、ほぼ確実にぶつかる壁があります。
WARNING: UNPROTECTED PRIVATE KEY FILE!
Permissions 0644 for '/Users/.../id_rsa.pem' are too open.
This private key will be ignored.
「鍵を ~/.ssh/ に置いた」「アプリの SSH 設定欄に鍵パスを入れた」までは順調にやってきたのに、いざ接続するとこれ。chmod 600 ~/.ssh/id_rsa.pem を一度実行すれば直る、という解は SSH に慣れた人には自明ですが、ターミナルを使い慣れていない人にとっては最大のつまずきポイントです。
今回は、これを アプリ側で診断 → 同意確認 → 自動修正する設計判断と、Phase 分けの話を書き残しておきます。
OpenSSH の厳格モード — なぜ 600 を要求するか
OpenSSH(paramiko も内部で同じ判定を踏襲)は、秘密鍵のパーミッションがファイル所有者の読み書きだけ(0600)になっていないと、ロードを拒否します。
理由はシンプルで、秘密鍵が他のユーザーから読める状態は、その時点で漏洩リスクがあるため。鍵ファイルへの read アクセスは、そのまま「鍵ペアの片割れを手に入れた」状態と等価で、ssh-add で別ホストに鍵を持ち出されれば、対応する公開鍵が登録されている全サーバーに侵入される可能性がある。
OpenSSH 側で「うっかり緩いパーミッションのまま運用される」のを防ぐための安全装置です。鍵を作ったり受け取ったりした時点ではデフォルトで 0644(他ユーザーから read 可能)になっていることが多いのが落とし穴です。
解決の素直な経路 — chmod 600
ターミナルで 1 行:
chmod 600 ~/.ssh/id_rsa.pem
これで OpenSSH の厳格モードは満足し、接続できるようになります。SSH 経験者にはお馴染みのスニペット。
ただ、ユーザー層には agency や IT 担当者でも「ターミナルを開いたことがない」人が一定いる。Mac の場合は「Spotlight で『ターミナル』と入力して、起動して、コマンドを打つ」というフローが心理的に重く、サポート問い合わせの引き金になっていました。
アプリ側で診断 → 同意確認 → 自動修正
そこで、ファイルパスを指定した時点でアプリが内側からパーミッションをチェックし、緩い場合は「修正していいですか?」のダイアログを出して、ユーザーがボタンを押したら chmod 600 相当の処理を裏で実行する設計にしました。
def diagnose_ssh_key(path: str) -> dict:
"""
{
"permission_ok": bool,
"current_mode": "0644",
"target_mode": "0600",
"platform": "macOS" | "Windows" | "Linux",
"fix_safe": bool, # 共有領域・他ユーザー所有等で False
}
"""
...
Windows は OpenSSH の厳格モードが「現在のユーザーのみ ACL を持つ」ことを要求するので、Mac/Linux の chmod 600 とは別のロジック(icacls で他 ACL を全部 remove)になります。これも platform で分岐して透過的に処理しました。
Phase 1(事後)と Phase 2(予防)のハイブリッド
実装にあたって、修正を発火させるタイミングを 2 つ用意しました。
Phase 1 — 接続失敗時の事後リカバリ
– 「接続テスト」ボタンを押す → SSH 接続が permission_error で失敗 → エラーメッセージに「🔧 修正して再試行」ボタンを動的追加 → クリックで chmod 600 + 再接続
Phase 2 — 接続テスト前の予防診断
– 「接続テスト」ボタンを押した時点で /api/diagnose_ssh_key を呼ぶ → パーミッションが緩い場合は警告ダイアログ + 「🔧 修正してから接続」「そのまま接続」ボタン
Phase 1 だけだと「初回の失敗体験」が残るので、Phase 2 で先回りする。Phase 2 だけだと診断と接続テストが分離して UX が冗長になるので、Phase 1 で取り逃しを拾う。両方走らせるのが結果的に最もスムーズなフローでした。
Phase 3(起動時自動修正)は不採用 — セキュリティ上の判断
「いっそアプリ起動時に検出して自動修正してしまえばいいのでは」という Phase 3 案もありましたが、採用しませんでした。
理由は、共有鍵や意図的に緩いパーミッションの鍵を、誤検知で書き換えるリスク。SSH の世界には「複数ユーザーが同じ秘密鍵を共有する」運用も少数ながら存在し、その場合は意図的にグループ read 可(0640 等)に設定されていることがあります。
アプリが起動時に勝手に 0600 に書き換えると、他のユーザーが鍵を使えなくなる事故を引き起こしかねない。修正は必ず ユーザーの明示的なボタン操作をトリガーにする、という設計原則を守りました。
「自動」と「同意」のバランスは、UX 改善とセキュリティの線引きで悩ましいところですが、書き換え系の処理は常に人間の合意を待つ、というのが現時点での結論です。
まとめ — UX の壁は「内側から解ける」ことが多い
「ターミナルでコマンドを打てば直る」というのは、エンジニアにとっては自明な経路ですが、ターミナルを使わない層にとっては最大の心理的障壁です。アプリ側で「何が問題で、何をすれば直るか」を診断して、ユーザー同意の下で実行してしまえる UX は、SSH まわりのサポート問い合わせを減らす方向に寄与しました。
似たパターンは他にもあって、SSH 鍵形式の互換ローダー(7 形式の SSH 秘密鍵を受け入れる話)も「アプリ側で吸収して、ユーザーは何もしなくていい」設計の同類例です。
書き換え系は同意を取りつつ、診断と提案までは積極的にやる — このバランスが、ターミナルに馴染みのないユーザーまで含めた SSH UX の落としどころだと感じています。