EC2 Instance Connect Endpointを複数アカウント間で使う際に気を付けるべきこと

2023.06.19

しばたです。

弊社平井によりEC2 Instance Connect EndpointをVPC Peering経由で使う記事が公開されています。

こちらの記事では「複数アカウントまたがる環境では期待した動作にならない」旨の内容が記載されていますが、本記事ではこのへんの制約や回避策を語りたいと思います。

EC2 Instance Connectの機能をおさらい

以前の記事でも解説しましたが、EC2 Instance Connectは今回新規に増えたEC2 Instance Connect Endpointを介したEC2インスタンスへの接続だけでなく、従来からあるIAMロールベースのEC2への接続制御と合わせて2つの機能があります。

従来の機能

従来の機能はSSH鍵の自動交換をベースにIAMロールによる接続制御を行っています。
具体的な実装としては、

  1. クライアントでSSH鍵(秘密鍵、公開鍵)を生成
  2. 生成した公開鍵をAWSのec2-instance-connect:SendSSHPublicKeyAPIを使いEC2インスタンスへ送信
    • この操作の可否=EC2への接続可否となる
  3. EC2インスタンス側はインストール済みのEC2 Instance Connectプログラムがインスタンスメタデータ経由で公開鍵を受け取り鍵認証に使う
    • この操作のために専用プログラムの事前導入が必要
  4. 生成したSSH鍵で認証しログイン

という手順を踏んでいます。
ここで大事な点は、この機能を使うには接続インスタンスに対するec2-instance-connect:SendSSHPublicKeyAPIの許可が必要なところです。

EC2 Instance Connect Endpoint

次に、今回追加されたEC2 Instance Connect EndpointはVPC Endpointの形で外部ネットワークからの接続点を設け、WebSocketトンネルを張りクライアントからプライベートサブネットにあるEC2インスタンスへの接続を実現します。

VPC Endpointの情報を取得するために新しくec2:DescribeInstanceConnectEndpointsAPIが増えており、加えてWebSocketトンネルを張るためにec2-instance-connect:OpenTunnelアクションに対する許可が必要となります。 *1

そしてWebSocketトンネルを張るために必要な情報は

  • EC2 Instance Connect EndpointのIDとPublic DNS名
    • 値さえわかれば良いためec2:DescribeInstanceConnectEndpointsAPIの利用は必須ではない
  • 接続先のPrivate IPアドレス
    • 多くの場合ec2:DescribeInstancesAPIを使いIPアドレスを取得するが、APIの利用は必須ではない
  • 接続先のポート番号

となります。

EC2 Instance Connect Endpointを使う際の注意点

次にEC2 Instance Connect Endpointを使う際に注意すべきポイントを

  • 通信経路
  • AWSリソースに対するアクセス権

の二面から解説します。

1. 通信経路

はじめに通信経路に関してですが、こちらは基本的に「VPC Enpopintから宛先Private IPに対する疎通」だけ考えておけば大丈夫です。
VPC Peering経由する・しないに関わらずとにかく疎通さえできれば構わないと考えて良いでしょう。

AWSの設定上注意すべき点としては

  • VPC Endpoint ⇔ 接続対象インスタンスのルーティング
  • VPC Endpointと紐づくセキュリティグループのアウトバウンド許可
  • 接続対象インスタンスと紐づくセキュリティグループのインバウンド許可

あたりかと思います。

これ以外には接続元としてクライアントのIPを使う「Preserve Client IP」機能がAWS Transit Gateway経由の通信ではサポートされない点に注意すると良いでしょう。

2. AWSリソースに対するアクセス権

EC2 Instance Connectは機能により必要となるアクセス権が結構変わります。
さらに複数アカウントにまたがる環境になると「どのアカウントのどの権限が必要か?」まで考える必要がありかなり厄介です。

前節の説明と重複する点もありますが、ざっくり下図の様な感じで機能別で必要な権限が別れています。

2-1. ec2-instance-connect:OpenTunnel

WebSocketトンネルを張るために必要な権限です。
VPC Endpointが存在するアカウントでの許可が必要です。

2-2. ec2:DescribeInstanceConnectEndpoints

VPC Endpointの情報を取得するために必要な権限です。
VPC Endpointが存在するアカウントでの許可が必要です。

ただ、予めEndpoint IDとPublic DNS名がわかっているのであれば権限が無くても大丈夫な場合があります。

2-3. ec2-instance-connect:SendSSHPublicKey

クライアントからSSH公開鍵をEC2に送るために必要な権限です。
EC2が存在するアカウントでの許可が必要です。

2-4. ec2:DescribeInstances

EC2の情報(特にPrivate IPアドレス)を取得する際に必要な権限です。
EC2が存在するアカウントでの許可が必要です。

ただ、予めPrivate IPおよびVPC Endpoint IDとPublic DNS名がわかっているのであれば権限が無くても大丈夫な場合があります。

EC2 Instance Connect Endpointを複数アカウント間で使う際に気を付けるべきこと

だいぶ前置きが長くなりましたが、ここまでの説明でEC2 Instance Connect Endpointを複数アカウント間で使う場合は要求される権限に気を付ける必要があることがご理解いただけたと思います。

ここからは複数アカウントにまたがる環境における制限や回避策を解説していきます。

1. マネジメントコンソールでの操作

複数アカウントにまたがる環境ではマネジメントコンソールでの操作は絶望的です。

たとえば前掲の図のアカウントB(222222222222)にあるEC2インスタンスに接続する場合であれば下図の様になりますが、

この場合

  • アカウントBの
    • ec2:DescribeInstances
    • ec2-instance-connect:SendSSHPublicKey
  • アカウントAの
    • ec2:DescribeInstanceConnectEndpoints
    • ec2-instance-connect:OpenTunnel

が必要になるためどうすることもできません。

2. AWS CLI (aws ec2-instance-connect open-tunnel) による操作

対してAWS CLIからの操作であれば条件付きで回避策があります。

2つのアカウントにまたがる操作をすることが問題であるため、どうにかしてアカウントA(111111111111)だけに対する操作にしてやれば問題を回避可能です。

そのために以下の条件を付けてやります。

  • SSH鍵の交換機能は使わない → これでec2-instance-connect:SendSSHPublicKeyが不要に
  • 接続先Private IPアドレスを事前に取得しておく → これでec2:DescribeInstancesが不要に

この条件であれば必要となるのはアカウントAの権限だけです。

AWS CLIのaws ec2-instance-connect open-tunnelコマンドを

# アカウント跨ぎでも可能なコマンド指定
aws ec2-instance-connect open-tunnel --instance-connect-endpoint-id "アカウントAのEIC Endpont ID" --private-ip-address "EC2インスタンスのPrivate IP" --local-port "任意の空きポート" --remote-port 22

の様に指定しやれば条件を満たすことができるため、複数アカウントにまたがる環境でもWebSocketトンネルを張ることができます。

実行例はこんな感じになります。

# 実行例 : アカウントBのPrivate IP 10.10.21.244 へ接続する例
PS C:\> aws ec2-instance-connect open-tunnel --instance-connect-endpoint-id "eice-111111111111" --private-ip-address 10.10.21.244 --local-port 10022 --remote-port 22

そしてこのコマンドはSSHのProxyCommandにも使えますので、以下の様にすればsshコマンド一発でEC2インスタンスに接続することができます。

# ProxyCommandに aws ec2-instance-connect open-tunnel を設定
ssh -i "キーペア秘密鍵のパス" ec2-user@"接続先Private IP" `
    -o ProxyCommand='aws ec2-instance-connect open-tunnel --instance-connect-endpoint-id "アカウントAのEIC Endpont ID" --private-ip-address "接続先Private IP"

3. AWS CLI (aws ec2-instance-connect ssh) による操作

AWS CLIにはaws ec2-instance-connect sshコマンドも存在しますが残念ながらこのコマンドは使えませんでした。

というのもこのコマンドでは--instance-idパラメーターが必須であり、代替の--instance-ipパラメーターを指定した場合でも対象インスタンスの情報を取得しようとするためです。
--instance-idにダミーのIDを設定して回避できないか試してみましたが、当然「インスタンスIDが不正」「そんなEC2インスタンスは存在しない」旨のエラーになり失敗しました。

4. その他

マネジメントコンソールやAWS CLIを使った操作は上記の通りですが、例えば自作プログラムで複数アカウントの操作をうまいこと切り替え(またはスイッチロールして)やれば条件を付けなくても期待した接続を実現することは出来るでしょう。

ただ、そこまでするくらいならアカウント毎にEC2 Instance Connect Endpointを用意する方が現実的かと思います。

最後に

以上となります。

通信経路だけ考えるとAWSアカウント関係なく簡単に疎通できそうに見えてしまいますが、実際にはAWSのAPI呼び出しも発生するため複数アカウントにまたがる場合は利用に制約が発生します。
EC2 Instance Connect Endpointを利用する際はご注意ください。

脚注

  1. 細かい補足ですが現状ec2-instance-connect:OpenTunnelというAPIは公開されていません。WebSocketトンネルを張る行為自体がこのアクションとして扱われています