クラウドMacのSSHホスト鍵検証と安全なローテーション

クラウドMacのSSHホスト鍵検証と安全なローテーション

開発者がクラウドMacへ初めて接続すると、通常は未知のホストを信頼するかどうかをターミナルで確認されます。手作業なら yes と入力するだけで済み、CIでは StrictHostKeyChecking=no を設定するほうがさらに簡単です。しかし、どちらも接続先の本人性確認を回避しています。DNS、アドレス設定、または通信経路が誤った接続先へ向けられた場合、認証情報やビルド成果物が別のマシンへ送信されるおそれがあります。正しい方法は、信頼できる経路からホスト鍵のフィンガープリントを事前に取得し、開発端末と自動化ジョブがその鍵だけを受け入れるようにすることです。

独立した信頼基準を先に確立する

ホスト鍵は「現在接続している相手が想定どおりのMacであること」を証明するもので、ユーザー認証に使用する秘密鍵とは異なります。Ed25519ホスト鍵の場合は、XcodeVMコンソールで提供されるWeb VNCから対象マシンのローカルターミナルを開き、公開鍵のフィンガープリントを確認します。

sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub -E sha256

完全な SHA256: の値に加え、インスタンス識別子、接続先アドレス、確認方法も記録します。検証対象のSSH経路だけを使ってこの値を取得してはいけません。それでは検証が循環してしまいます。

続いて、開発端末からリモートホストが現在提示している公開鍵を取得します。

mkdir -p ~/.ssh
chmod 700 ~/.ssh
ssh-keyscan -T 5 -t ed25519 "$MAC_HOST" > ~/.ssh/xcodevm_known_hosts.new
ssh-keygen -lf ~/.ssh/xcodevm_known_hosts.new -E sha256

両方のフィンガープリントを1文字ずつ比較します。一致を確認してからファイルを配置します。

install -m 600 ~/.ssh/xcodevm_known_hosts.new ~/.ssh/xcodevm_known_hosts
rm -f ~/.ssh/xcodevm_known_hosts.new

ssh-keyscan が行うのは「公開鍵の取得」であり、「その公開鍵が信頼できることの証明」ではありません。独立して取得したフィンガープリントを基準にできない場合、スキャン結果をそのまま本番用の信頼ファイルへ追加してはいけません。

known_hostsをプロジェクトごとに分離する

グローバルな ~/.ssh/known_hosts は日常的な対話操作には適していますが、チームプロジェクトでは専用ファイルを使用するのが望ましい運用です。変更内容を明確にレビューできるほか、個人が記録を整理したことで自動化ジョブに影響が及ぶのを防げます。

~/.ssh/config にエイリアスを定義します。

Host xcodevm-build
    HostName 192.0.2.10
    User builder
    IdentityFile ~/.ssh/xcodevm_build_ed25519
    IdentitiesOnly yes
    UserKnownHostsFile ~/.ssh/xcodevm_known_hosts
    StrictHostKeyChecking yes
    HashKnownHosts yes
    ServerAliveInterval 30
    ServerAliveCountMax 3

IdentitiesOnly yes を指定すると、クライアントが多数の認証鍵を順番に試すのを防げます。StrictHostKeyChecking yes により、未知の鍵や変更された鍵が提示された時点で接続を失敗させられます。接続前に展開後の設定を確認し、別のルールによってエイリアスが上書きされていないことを確かめます。

ssh -G xcodevm-build |
  grep -E '^(hostname|user|identityfile|userknownhostsfile|stricthostkeychecking) '

同じプロジェクトで複数のマシンを使用する場合は、マシンごとに個別のエントリを保存し、インスタンス識別子を社内の変更記録に残します。不規則に変わるアドレスを、範囲の広い1つのエイリアスで参照してはいけません。

CIでフィンガープリントを固定する

CIが特定の開発者の個人的な信頼ファイルを恒久的に引き継ぐ運用は避けるべきです。より安全なのは、想定するSHA256フィンガープリントを保護された変数として保存し、ジョブごとに鍵をスキャンして照合したうえで、一時的な known_hosts を作成する方法です。

set -euo pipefail

: "${MAC_HOST:?MAC_HOST is required}"
: "${EXPECTED_ED25519_SHA256:?fingerprint is required}"

scan_file="$(mktemp)"
known_hosts_file="$(mktemp)"
trap 'rm -f "$scan_file" "$known_hosts_file"' EXIT

ssh-keyscan -T 5 -t ed25519 "$MAC_HOST" > "$scan_file" 2>/dev/null
actual="$(ssh-keygen -lf "$scan_file" -E sha256 | awk '{print $2}')"

if [ "$actual" != "$EXPECTED_ED25519_SHA256" ]; then
  printf '%s
' "SSH host key verification failed" >&2
  exit 1
fi

install -m 600 "$scan_file" "$known_hosts_file"

ssh \
  -o UserKnownHostsFile="$known_hosts_file" \
  -o StrictHostKeyChecking=yes \
  -o IdentitiesOnly=yes \
  "$MAC_USER@$MAC_HOST" \
  'uname -m && sw_vers -productVersion'

秘密鍵、想定フィンガープリント、ホストアドレスはそれぞれ分けて管理します。トラブルシューティング用に実際のフィンガープリントをログへ出力することはできますが、秘密鍵の内容、接続パスワード、マスキングされていない環境変数を出力してはいけません。

ホスト鍵の変更を正しく処理する

ホスト鍵が変わる原因には、システムのリセット、ホスト鍵の再生成、接続先アドレスの再利用などがあります。また、通信が誤った接続先へ誘導されている可能性もあります。REMOTE HOST IDENTIFICATION HAS CHANGED が表示された場合は、まず自動化ジョブを停止してください。既存の記録を削除して、そのまま再接続してはいけません。

安全なローテーションは次の順序で実施します。

  1. コンソールで、インスタンス識別子、接続先アドレス、直近の操作が想定どおりであることを確認します。
  2. Web VNCのローカルターミナルから、Ed25519公開鍵のフィンガープリントを再取得します。
  3. 別のメンテナーが新旧のフィンガープリントと変更理由を確認します。
  4. リモートの公開鍵をスキャンして新しいフィンガープリントを検証し、新しい信頼ファイルを作成します。
  5. 先にテストジョブを更新し、読み取り専用の接続と環境確認を1回実行します。
  6. その後で本番ジョブを更新し、古いフィンガープリントを失効させます。

ハッシュ化された記録を使用している場合は、最初に古いエントリを特定します。

ssh-keygen -F "$MAC_HOST" -f ~/.ssh/xcodevm_known_hosts
ssh-keygen -R "$MAC_HOST" -f ~/.ssh/xcodevm_known_hosts

2番目のコマンドは、新しいフィンガープリントを独立した手段で確認した後にのみ実行します。古い記録の削除はローテーション作業の一部であり、検証作業ではありません。

チェックリストで受け入れ確認を完了する

本番運用を開始する前に、少なくとも次の項目を確認します。

確認項目 合格条件
フィンガープリントの取得元 対象マシンのローカルターミナルから取得している
鍵アルゴリズム Ed25519を明示的に固定し、任意のアルゴリズムを受け入れない
ファイル権限 .ssh が700、信頼ファイルが600
クライアントポリシー StrictHostKeyChecking=yes
CIの分離 ジョブごとに個別の一時ファイルを使用する
変更時の対応 ジョブを停止し、検証してから置き換える
ログの内容 フィンガープリントと失敗した段階を残し、認証情報は公開しない

さらに、ネガティブテストも1回実行します。想定フィンガープリントを一時的に誤った値へ変更し、実際のリモートコマンドが実行される前にジョブが終了することを確認してください。その後、正しい値へ戻し、読み取り専用コマンド、リポジトリアクセス、ビルドのエントリーポイントを検証します。これにより、保護機能が設定ファイルに存在するだけでなく、実際の処理に組み込まれていることを確認できます。

SSHの信頼チェーンに複雑なシステムは必要ありません。重要なのは、「初回接続時の承認」と「鍵変更後の再接続」を、その場の判断によるクリック操作から、レビュー可能なプロセスへ移行することです。信頼できるターミナルから基準値を取得し、プロジェクト専用ファイルに固定した対応関係を保存し、CIが接続のたびに検証します。変更があれば、必ず処理を止めて確認します。これらの手順を整えることで、リモート開発と自動ビルドに共通する、明確なホスト識別の境界を確立できます。

よくある質問

ssh-keyscanで取得したホスト鍵はそのまま信頼できますか?

信頼できません。ssh-keyscanは接続先が現在提示している鍵を読むだけです。別の信頼できる経路で取得したSHA256フィンガープリントと一致することを確認する必要があります。

警告が出たらknown_hostsの記録を削除して再接続してよいですか?

削除だけでは検証になりません。接続先アドレスとシステム状態を確認し、信頼できる端末から新しい指紋を取得して、一致した場合だけ古い記録を置き換えます。

CIで開発者個人のknown_hostsを共有してもよいですか?

推奨しません。CIジョブごとに権限600の専用ファイルを作り、StrictHostKeyCheckingを明示的に有効化し、終了時に一時ファイルを削除します。

XcodeVM クラウドMac

現在のワークロードに適した専有物理マシンを選択

メモリ、ストレージ、ノード、課金期間を確認してから注文設定に進みます。すべてのノードは365日継続稼働しています。実際の可用性はコンソールのリアルタイム表示をご確認ください。

プランを選んでレンタルする