📶

EC2 Instance Connectを使用してプライベートなEC2へ接続する

2023/06/24に公開

はじめに

こちらをご覧ください。
https://aws.amazon.com/jp/about-aws/whats-new/2023/06/amazon-ec2-instance-connect-ssh-rdp-public-ip-address/

今回はこちらに記載のEC2 Instance Connectという機能で、プライベートなEC2への接続を試してみました。

EC2 Instance Connectとは

SSHでEC2に容易に接続できる機能です。
接続にはEC2にパブリックIPが備わっている必要があったのですが、6月半ばのアップデートによりプライベートIPのみでも接続が可能になりました。
ドキュメントに記載されている以下の図がたいへんわかりやすいです。

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Connect-using-EC2-Instance-Connect-Endpoint.html

特徴

  • EC2へのエージェント等のインストールが不要
    • SSMと大きく異なる点です
  • EC2 Instance Connect Endpointを使用することで、プライベートなEC2へのアクセスが可能。
    • 無料で使用可能です。おおきなメリット
  • EC2コンソール、awscliコマンドから接続可能

環境

awscli 2.12.2

前提

検証

インスタンス作成

ポイントは

  • パブリックIPを無効化
  • SSH鍵接続のためのキーペアなし

です。

セキュリティグループ作成

セキュリティグループを作成します。
EC2 Instance Connect用とインスタンス用の2つ作成します。

EC2 Instance Connect用

  • インバウンド:なし
  • アウトバウンド:接続対象
    • セキュリティグループ、VPCCidrの値を推奨

対象がEC2の場合そのセキュリティグループをアウトバウンドで指定すればよいです。

EC2用

  • インバウンド:
    • EC2 Instance Connectのセキュリティグループ
    • クライアントのIP
      • EC2 Instance ConnectでpreserveClientIp=trueと設定した場合
    • その他AWSネットワークからの通信
  • アウトバウンド:
    • EC2 Instance Connectへのアウトバウンドが許可されていれば、それ以外は状況に応じて

双方こちらに記載があるため参考にします。
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/eice-security-groups.html

ドキュメントにはこのように最高にわかりやすい図があります。

VPCエンドポイント作成

  • EC2 Instance Connectの選択肢がコンソールで確認できます、選択しましょう。(前からありましたたっけ?)
  • クライアントのIPを保持するか選択する
    • 今回は保持しません
  • 予め作成したSGを選択し、プライベートサブネットに配置する


接続(コンソールから)

EC2コンソールの「接続」から接続可能です。
EC2 Instance Connectの選択肢が確認でき、先程作成したエンドポイントを指定すればOK

便利!

接続(awscliからSSH)

使うコマンドはこちらです。
https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2-instance-connect/ssh.html

$ aws ec2-instance-connect ssh --instance-id $ID --os-user ubuntu

OKですね。
--os-userは指定しないとec2-userになってしまうようです。
ubuntuだったので明示的に指定しました。

接続(トンネル経由でHTTP)

websocketトンネルを貼る

websocketトンネル経由で通信できる機能もあるので試してみます。
https://dev.classmethod.jp/articles/how-to-connect-rds-instance-via-eic-endpoint/

まずは接続対象サーバの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で取得できます。
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/log-ec2-instance-connect-endpoint-using-cloudtrail.html#ec2-instance-connect-endpoint-audit-users-cloudtrail

eventNameOpenTunnelで検索するとよいらしいです。
この通り

フォーマットはこんな感じです

{
     "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ロールをアタッチ不要

という点が大きいと考えています。
安価に踏み台サーバを減らせるとしたら、有力な選択肢になりそうです。

参考

https://dev.classmethod.jp/articles/ec2-instance-connect-endpoint-private-access/
https://zenn.dev/yuta28/articles/ec2-connect-ssh
https://zenn.dev/techno_tanoc/articles/3f714f91da5168

Discussion