EC2 Instance Connectを使用してプライベートなEC2へ接続する
参考
公式
「ipv4なしで接続できる!」を説明しているドキュメントは現時点で英語版しかなさそうです
外部ブログ
- SSHできる
-
aws ec2-instance-connect open-tunnel
でトンネル貼ることでポートフォワードもできる
すごい
何よりエンドポイントなのがすごい
インスタンスを作る
ポイントは
- パブリックIPを無効化
- SSH鍵接続のためのキーペアなし
セキュリティグループを作る
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 Instance Connectの選択肢が確認出来ます。
先程作成したエンドポイントを指定すればOK
すご
awscli
使うコマンドはこれ
使用できない場合はバージョンを上げる
$ aws ec2-instance-connect ssh --instance-id $ID --os-user ubuntu
よし
--os-user
は指定しないとec2-user
になってしまうようです。
ubuntuだったので明示的に指定しました
接続元
↑の画像にログイン元は192.168.3.234
とあります
ネットワークインターフェースを確認すると、EC2 Instance Connectのものだとわかります。
クライアントのIPを保持したら、このIPが変わってきそうです
セッション複数貼れる?
2つははれました
aws ec2-instance-connect ssh
を別端末でも試しました
トンネルを試す
接続対象サーバの30000番でhttpリクエストを待ち受けるようにします
$ python3 -m http.server 30000
Serving HTTP on 0.0.0.0 port 30000 (http://0.0.0.0:30000/)
こいつにたいしてwebsocketトンネル経由でリクエストを送ってみます。
つかうのはこれ
トンネルを試す②
$ aws ec2-instance-connect open-tunnel \
> --instance-id $ID \
> --remote-port 30000 \
> --local-port 30000
Listening for connections on port 30000.
これでローカルの30000番と接続対象の30000番でトンネルを貼りました。
別ウィンドウから接続してみます。
$ 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"
}
クライアントのIP保持を無効化していますが、cloudtrailではsourceIPAddress
で問題なく取得出来ています。
安全です
SSMとの比較、選び方
クラスメソッドさんが公開している、以下記事の通りだと思います。
個人的にはIAMロールをEC2にアタッチするのを忘れたりするので、
EC2 Instance Connectのほうが手軽だと感じました。エンドポイントコストかからんし
エラー・不都合が出た際の切り分けがネットワーク側になるので、
そこはIAMより難しそうというのは思いました。
IAMは権限足りない!と言ってくれるので親切です
環境次第!ケースバイケース!(便利な魔法)