
【EC2 Instance Connect × SSM】 EC2 に公開鍵を保管しない VS Code Remote - SSH 接続を作ってみた(通常のキーペア方式と比較)
はじめに
こんにちは!コンサルティング部のヒスです。
プライベートサブネットの EC2 に VS Code の Remote - SSH で接続するとき、SSH ポートを開けずに SSM Session Manager 経由でトンネルを張る構成がよく使われます。この構成で、手元で鍵ペアを作り、公開鍵を EC2 の authorized_keys に登録しておく方法(以下「通常のキーペア方式」。Remote - SSH と同じ構成です)は手軽ですが、次のような悩みが出てきます。
- 開発者が増えると、公開鍵の登録作業が EC2 ごと・開発者ごとに発生する
- 開発者の入れ替わり時に、EC2 側の
authorized_keysから鍵を消す運用が必要になる - EC2 に開発者の鍵が残るため、AMI やスナップショットにも鍵が含まれる
そこで、通信経路は同じ SSM のまま、EC2 Instance Connect で接続のたびに公開鍵を一時登録する方式を試しました。EC2 側には公開鍵が永続的に保管されません。
この記事では、設定手順と、通常のキーペア方式と比較したメリット・デメリットを紹介します。比較するのは「EC2 に公開鍵を保管するかどうか」の違いです。(SSH ポートを開けて直接接続する構成との違いは、比較の節の最後に補足します。)

前提条件・検証環境
| 項目 | 内容 |
|---|---|
| 接続元 | Windows 端末(VS Code、PowerShell) |
| 接続先 | Amazon Linux 2023 の EC2(プライベートサブネット、パブリック IP なし) |
| 認証 | IAM Identity Center(AWS CLI の SSO プロファイル)。固定のアクセスキーは使わない |
| 接続元に必要なもの | AWS CLI v2、Session Manager Plugin、VS Code + Remote - SSH 拡張、OpenSSH クライアント |
| EC2 側 | SSM Agent と EC2 Instance Connect が動作していること(Amazon Linux 2023 は標準で導入済み)、SSM で管理できるネットワーク経路があること |
| セキュリティグループ | インバウンドは開放しない |
💡 Toolkit の「Connect VS Code to EC2 instance」も一時鍵を使いますが、Windows ではそのままでは使えません。経緯はこちらの記事で紹介しています。この記事は、それを自分で組み立てるイメージです。
仕組み
接続のたびに、次の3つが順に行われます。
| 順序 | 処理 | 内容 |
|---|---|---|
| 1 | 接続先の特定 | Name タグから、起動中の EC2 のインスタンス ID と AZ を取得する |
| 2 | 公開鍵の一時登録 | EC2 Instance Connect の send-ssh-public-key で、手元の公開鍵を EC2 に登録する。登録した鍵は約 60 秒で無効になる |
| 3 | 通信経路の確立 | SSM Session Manager の AWS-StartSSHSession で、EC2 の SSH ポートまでのトンネルを開く |
Remote - SSH は、SSH 設定の ProxyCommand からこの処理を呼び出すだけです。
重要なのは、鍵ペアは手元で1回だけ作り、EC2 には接続のたびに公開鍵が一時的に載るだけという点です。接続のたびに鍵ペアを作り直す Toolkit の方式とは異なります。

やってみた
1. IAM Identity Center の SSO プロファイルを登録する(初回のみ)
aws configure sso --profile my-profile
対話形式で、SSO start URL、リージョン、アカウント、許可セットを選びます。作業開始時にサインインします。
aws sso login --profile my-profile
aws sts get-caller-identity --profile my-profile


2. SSH 鍵ペアを作成する(手元の端末で1回だけ)
New-Item -ItemType Directory -Force "$env:USERPROFILE\.ssh" | Out-Null
cmd /c 'ssh-keygen -t ed25519 -f "%USERPROFILE%\.ssh\my-key" -N ""'
my-key(秘密鍵)と my-key.pub(公開鍵)ができます。通常のキーペア方式と違い、この公開鍵を EC2 の作成時や authorized_keys に登録する必要はありません。
3. 接続スクリプトを配置する(初回のみ)
次のコマンドで %USERPROFILE%\.ssh\my-connect.ps1 を VS Code で開き、下記のスクリプトを貼り付けて保存します。
code "$env:USERPROFILE\.ssh\my-connect.ps1"
このスクリプトは、PowerShell のコンソールに貼り付けて実行するものではありません。ファイルとして保存してください。SSH 設定(手順 4)の
ProxyCommandから、接続のたびに自動で呼び出されるため、手動で実行する必要はありません。また、スクリプト内の$ProfileNameは、手順 1 で登録した実際のプロファイル名に合わせてください。
param(
[Parameter(Mandatory = $true)][string]$Name,
[string]$Port = "22"
)
$ErrorActionPreference = "Stop"
$ProfileName = "my-profile"
$Region = "ap-northeast-1"
$PubKeyPath = Join-Path $env:USERPROFILE ".ssh\my-key.pub"
# Get the instance ID and AZ of the running EC2 from the Name tag
$info = aws ec2 describe-instances --profile $ProfileName --region $Region `
--filters "Name=tag:Name,Values=$Name" "Name=instance-state-name,Values=running" `
--query "Reservations[0].Instances[0].[InstanceId,Placement.AvailabilityZone]" --output text
if (-not $info -or $info -match "None") {
[Console]::Error.WriteLine("EC2 '$Name' was not found or is not running.")
exit 1
}
$InstanceId, $Az = $info -split "\s+"
# Register the public key temporarily (valid for about 60 seconds)
aws ec2-instance-connect send-ssh-public-key --profile $ProfileName --region $Region `
--instance-id $InstanceId --availability-zone $Az --instance-os-user ec2-user `
--ssh-public-key "file://$PubKeyPath" | Out-Null
# Start an SSH tunnel through SSM Session Manager
aws ssm start-session --profile $ProfileName --region $Region --target $InstanceId `
--document-name AWS-StartSSHSession --parameters "portNumber=$Port"
💡 スクリプト内のコメントを英語にしているのは、Windows PowerShell 5.1 が BOM なし UTF-8 の日本語を文字化けさせることがあるためです。
4. SSH 設定(config)に追記する(初回のみ)
次のコマンドで %USERPROFILE%\.ssh\config(無い場合は新規作成)を VS Code で開き、追記します。
code "$env:USERPROFILE\.ssh\config"
Host 名は EC2 の Name タグと一致させます(%h としてスクリプトに渡されるため)。
Host my-ec2-xx-01
User ec2-user
IdentityFile C:/Users/<ユーザー名>/.ssh/my-key
IdentitiesOnly yes
StrictHostKeyChecking accept-new
ServerAliveInterval 60
ProxyCommand powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:/Users/<ユーザー名>/.ssh/my-connect.ps1" %h %p
5. VS Code から接続する(毎回)
aws sso login --profile my-profileでサインインする(有効期限内ならスキップ可)- EC2 が停止している場合は起動し、SSM で接続できるようになるまで数分待つ
- F1 → 「Remote-SSH: Connect to Host...」 →
my-ec2-xx-01を選択する - 新しいウィンドウが開いたら、ターミナルで次を実行する
hostname
whoami
ip-10-xx-xx-xx.ap-northeast-1.compute.internal と ec2-user が表示されれば、EC2 側に入れています。



通常のキーペア方式との比較
ここでの「通常のキーペア方式」は、Toolkit の記事で紹介した Remote - SSH と同じ構成です。つまり、次のとおりです。
- 手元で鍵ペアを作り、公開鍵を EC2 の
authorized_keys(または EC2 作成時のキーペア)に事前に登録しておく - 通信は、SSM Session Manager 経由で行う(ポート開放なし)
どちらの方式も SSM を使うため、ポート開放が不要な点は同じです。違いは、「EC2 に公開鍵を保管するかどうか」と、それに伴う運用です。
比較表
| 観点 | 通常のキーペア方式(SSM 経由) | EC2 Instance Connect + SSM 方式 |
|---|---|---|
| EC2 側の公開鍵 | authorized_keys に永続的に保管される |
保管しない(接続のたびに約 60 秒だけ登録) |
| 認可の仕組み | 秘密鍵を持っていれば SSH 認証は通る(SSM 接続の権限は別途必要) | 秘密鍵に加えて、SendSSHPublicKey の IAM 権限が必要 |
| 監査(誰が入ったか) | SSM のセッション記録は残るが、SSH の鍵と人の対応は取りにくい | SendSSHPublicKey と StartSession の両方が IAM のユーザー情報つきで CloudTrail に記録される |
| 開発者の入れ替わり | EC2 側から公開鍵を削除する作業が必要 | EC2 側の作業は不要。IAM 側の許可を外し、本人の鍵ペアを作り直す |
| 鍵の登録作業 | 開発者ごと・EC2 ごとに公開鍵を登録する必要がある | 不要 |
| SSH ポートの開放 | 不要(SSM 経由) | 不要(SSM 経由) |
| 初期構築の手間 | 中(鍵登録、SSH 設定) | 多い(スクリプト、SSH 設定、IAM 権限) |
| 接続時の速度 | 速い | 公開鍵の送信(API 呼び出し)の分だけ遅い(数秒) |
| 手元に必要なツール | AWS CLI、Session Manager Plugin | 同じ |
| 認証切れの影響 | SSO セッションが切れると SSM に接続できない | 同じ |
| 停止中の EC2 | 起動後、SSM の準備が整うまで待つ | 同じ |
| トラブル時の切り分け | SSO、SSM、SSH の 3 層 | SSO、IAM(鍵送信)、SSM、SSH の 4 層 |
| 手元の秘密鍵 | 必要(漏えい対策が必要) | 必要(漏えい対策が必要) |
補足:SSH ポートを開けて直接接続する場合
SSM を使わず、SSH ポートを開けて(または踏み台サーバーを経由して)直接接続する構成と比べると、次の点が加わります。
| 観点 | 直接 SSH(参考) | SSM 経由(上の 2 方式) |
|---|---|---|
| SSH ポートの開放 | 必要(22 番、または踏み台経由) | 不要 |
| 手元に必要なツール | ssh のみ | AWS CLI、Session Manager Plugin も必要 |
| 認証切れの影響 | なし | SSO セッションが切れると接続できない |
| 接続の認可 | 秘密鍵だけで接続できる | IAM(SSM の権限)も必要 |
直接 SSH は手軽ですが、ポート開放や踏み台の管理が必要です。プライベートサブネットで運用する場合は、SSM 経由にするのが一般的です。この記事では、SSM を使う 2 方式の違い(公開鍵を保管するかどうか)に絞って比較しました。
メリット
- EC2 に公開鍵が残らない: 接続のたびに公開鍵が一時登録され、約 60 秒で無効になります。AMI やスナップショットを作っても、開発者の鍵が混入しません。
- 入れ替わりの運用が軽い: EC2 側で鍵を探して消す作業が不要です。IAM 側の許可を外せば、新しい接続ができなくなります。
- 認可を IAM に一本化できる: 「誰がどの EC2 に入れるか」を、許可セットのポリシーで制御できます。タグ条件や OS ユーザーの条件で絞ることもできます。
- 監査しやすい: 誰がいつどの EC2 に公開鍵を送り、セッションを開始したかが CloudTrail に残ります。
デメリット
- 構築・運用の難易度が上がる: 接続スクリプトと、
SendSSHPublicKeyを許可する IAM 権限の設計が必要です。Windows 特有の癖(PowerShell の文字コード、パス表記など)にも気を使います。 - EC2 側の前提が増える: EC2 Instance Connect が動作している必要があります(Amazon Linux 2023 は標準で導入済み)。
- 接続が少し遅い: 接続のたびに、EC2 の検索と公開鍵の送信(API 呼び出し)が加わります。
- 切り分けの層が増える: SSO、IAM(鍵送信)、SSM、SSH の 4 層を疑う必要があります。
- 「手元の秘密鍵」は残る: EC2 側には鍵が残りませんが、秘密鍵は手元に存在します。共有しない、端末を適切に管理するといった対策は、どちらの方式でも必要です。ただし、この方式では秘密鍵だけでは接続できず、IAM の権限も必要になります。
💡 AWS CLI と Session Manager Plugin の導入、SSO セッション切れの影響、停止中の EC2 には接続できない点は、SSM を使う以上、通常のキーペア方式でも同じです。
まとめ
EC2 Instance Connect と SSM Session Manager を組み合わせることで、EC2 に公開鍵を保管せずに、VS Code の Remote - SSH で接続できました!
公開鍵の登録・削除が不要になり、誰が接続したかも CloudTrail で追えるため、人数が多い環境や、入れ替わりの多い環境、監査要件のある環境に向いています。一方で、接続スクリプトや許可セットの設計といった構築の手間はかかるため、少人数であれば通常のキーペア方式でも十分かと思います!









