EC2 Instance Connectを使用してプライベートなEC2へ接続する
はじめに
こちらをご覧ください。
今回はこちらに記載のEC2 Instance Connect
という機能で、プライベートなEC2への接続を試してみました。
EC2 Instance Connectとは
SSHでEC2に容易に接続できる機能です。
接続にはEC2にパブリックIPが備わっている必要があったのですが、6月半ばのアップデートによりプライベートIPのみでも接続が可能になりました。
ドキュメントに記載されている以下の図がたいへんわかりやすいです。
特徴
- EC2へのエージェント等のインストールが不要
- SSMと大きく異なる点です
-
EC2 Instance Connect Endpoint
を使用することで、プライベートなEC2へのアクセスが可能。- 無料で使用可能です。おおきなメリット
- EC2コンソール、awscliコマンドから接続可能
環境
awscli 2.12.2
前提
- こちらのドキュメントを参考に進めます。
- awscliを使用します。バージョンが古いと今回使用するコマンドがないため、アップデートが必要です。
- EC2と接続するために使用するポリシーは以下となります。足りない場合は適宜追加します。
検証
インスタンス作成
ポイントは
- パブリックIPを無効化
- SSH鍵接続のためのキーペアなし
です。
セキュリティグループ作成
セキュリティグループを作成します。
EC2 Instance Connect用とインスタンス用の2つ作成します。
EC2 Instance Connect用
- インバウンド:なし
- アウトバウンド:接続対象
- セキュリティグループ、VPCCidrの値を推奨
対象がEC2の場合そのセキュリティグループをアウトバウンドで指定すればよいです。
EC2用
- インバウンド:
- EC2 Instance Connectのセキュリティグループ
- クライアントのIP
- EC2 Instance Connectで
preserveClientIp=true
と設定した場合
- EC2 Instance Connectで
- その他AWSネットワークからの通信
- アウトバウンド:
- EC2 Instance Connectへのアウトバウンドが許可されていれば、それ以外は状況に応じて
双方こちらに記載があるため参考にします。
ドキュメントにはこのように最高にわかりやすい図があります。
VPCエンドポイント作成
-
EC2 Instance Connect
の選択肢がコンソールで確認できます、選択しましょう。(前からありましたたっけ?) - クライアントのIPを保持するか選択する
- 今回は保持しません
- 予め作成したSGを選択し、プライベートサブネットに配置する
接続(コンソールから)
EC2コンソールの「接続」から接続可能です。
EC2 Instance Connectの選択肢が確認でき、先程作成したエンドポイントを指定すればOK
便利!
接続(awscliからSSH)
使うコマンドはこちらです。
$ aws ec2-instance-connect ssh --instance-id $ID --os-user ubuntu
OKですね。
--os-user
は指定しないとec2-user
になってしまうようです。
ubuntuだったので明示的に指定しました。
接続(トンネル経由でHTTP)
websocketトンネルを貼る
websocketトンネル経由で通信できる機能もあるので試してみます。
まずは接続対象サーバの30000番ポートでhttpリクエストを待ち受けるようにします。
$ python3 -m http.server 30000
Serving HTTP on 0.0.0.0 port 30000 (http://0.0.0.0:30000/)
このようにするとローカルの30000番ポートと対象サーバの30000番ポートで
websocketトンネルを貼れるようになります。
$ aws ec2-instance-connect open-tunnel \
> --instance-id $ID \
> --remote-port 30000 \
> --local-port 30000
Listening for connections on port 30000.
動作確認
curlを試すと
$ curl -I localhost:30000
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.10.6
Date: Fri, 23 Jun 2023 06:10:08 GMT
Content-type: text/html; charset=utf-8
Content-Length: 626
OKです。ブラウザで見てもこのとおり
接続すると、コネクションの様子がターミナルに出力されます。
$ aws ec2-instance-connect open-tunnel \
> --instance-id $ID \
> --remote-port 30000 \
> --local-port 30000
Listening for connections on port 30000.
[1] Accepted new tcp connection, opening websocket tunnel.
[1] Closing tcp connection.
[2] Accepted new tcp connection, opening websocket tunnel.
[3] Accepted new tcp connection, opening websocket tunnel.
[2] Closing tcp connection.
[3] Closing tcp connection.
[4] Accepted new tcp connection, opening websocket tunnel.
[4] Closing tcp connection.
// 略
接続ログ
cloudtrailで取得できます。
eventName
をOpenTunnel
で検索するとよいらしいです。
この通り
フォーマットはこんな感じです
{
"eventVersion": "1.08",
"userIdentity": {
"type": "IAMUser",
"principalId": "ABCDEFGONGNOMOOCB6XYTQEXAMPLE",
"arn": "arn:aws:iam::1234567890120:user/IAM-friendly-name",
"accountId": "123456789012",
"accessKeyId": "ABCDEFGUKZHNAW4OSN2AEXAMPLE",
"userName": "IAM-friendly-name"
},
"eventTime": "2023-04-11T23:50:40Z",
"eventSource": "ec2-instance-connect.amazonaws.com",
"eventName": "OpenTunnel",
"awsRegion": "us-east-1",
"sourceIPAddress": "1.2.3.4",
"userAgent": "aws-cli/1.15.61 Python/2.7.10 Darwin/16.7.0 botocore/1.10.60",
"requestParameters": {
"instanceConnectEndpointId": "eici-0123456789EXAMPLE",
"maxTunnelDuration": "3600",
"remotePort": "22",
"privateIpAddress": "10.0.1.1"
},
"responseElements": null,
"requestID": "98deb2c6-3b3a-437c-a680-03c4207b6650",
"eventID": "bbba272c-8777-43ad-91f6-c4ab1c7f96fd",
"readOnly": false,
"resources": [{
"accountId": "123456789012",
"type": "AWS::EC2::InstanceConnectEndpoint",
"ARN": "arn:aws:ec2:us-east-1:123456789012:instance-connect-endpoint/eici-0123456789EXAMPLE"
}],
"eventType": "AwsApiCall",
"managementEvent": true,
"recipientAccountId": "123456789012",
"eventCategory": "Data"
}
公式ドキュメントより
終わりに
とても便利な機能です。個人的には
- エンドポイントが無料
- EC2にセッションマネージャアクセス用のIAMロールをアタッチ不要
という点が大きいと考えています。
安価に踏み台サーバを減らせるとしたら、有力な選択肢になりそうです。
参考
Discussion