今月のAWS re:Inforce 2023で、EC2 Instance Connect Endpoint(EICE)が正式にリリースされました。これにより、Public IPアドレスを持たないEC2インスタンスへの接続がより簡単になりました。
Public IPアドレスを持たないEC2インスタンスに接続する方法は、以下があります。
- プライベート接続(VPN、DirectConnect)で接続する
- 踏み台(Bastion)サーバを立てる
- SSM(System Managers)のSession Managerを利用する
- 【今月から】EC2 Instance Connect Endpoint(EICE)を利用する
VPNや踏み台は手順が煩雑で余計にコストがかかるのですが、今までのSession Manager機能は今回のEICEと何が違うのでしょうか?どのように使い分けすれば良いでしょうか?
仕組みの比較
まずは、それぞれの接続方式の仕組みを見てみましょう。
SSM Session Managerの場合、EC2インスタンスにインストールされているSSM Agentが、SSMのEndpointと接続を確立した後、リモート接続要求をユーザから受け付ける仕組みとなります。以下の①~③までは、シェルに接続する際の流れを示しており、ポートフォワーディングの場合は更に、④のようにSSM Agentがローカルに接続を確立する形となります(例えばSSHの場合、$SSH_CLIENTを確認すると127.0.0.1になります)。
SSM Endpointから、EC2インスタンスに接続しに行くことは絶対にないのが特徴です(つまり①の方向は必ずEC2インスタンスからSSM Endpointへとなります)。
一方、EICE経由の接続は非常に自然な流れとなります。EC2 Instance Connect Endpoint(EICE)は、踏み台のような役割を果たしています。SSHの場合、$SSH_CLIENTを確認すると、EICEのENIのPrivate IPアドレスであることが分かります(EICEは、インターフェース型のVPC Endpointと同様に、Private SubnetのIPアドレスを占有します)。
詳細な情報については、AWSの公式ドキュメントを参照していただくことをお勧めします。ここでは、これら2つの接続方法の比較についてご紹介します。
SSM Session Manager | EICE | |
---|---|---|
トラフィックの方向 | インスタンス→Endpoint | Endpoint→インスタンス |
コスト | 3種類のPrivateLink型のVPC Endpoint (ssm, ssmmessages, ec2messages)が必要なので、 最低限でも毎月30 USD | 無償。PrivateLinkを利用していない |
EC2に必要なエージェント | SSM Agent | ec2-instance-connect |
EC2に必要な権限 | SSM関連の権限(AmazonSSMManagedInstanceCore で最低限の権限を定義) | 不要 |
EC2に開放が必要なインバウンドポート | なし | 22番(SSHの場合)、3389番(RDPの場合)など |
可用性 | 複数サブネットでインターフェースを作成可能 | 1 VPCにつき1個のみ作成可能のため、AZ障害に弱い |
アクセス制御の方法 | 接続元のIdentity Policy、VPC Endpoint Policy | 接続元のIdentity Policy |
ネットワーク制御の方法 | Security Group | Security Group (ただし、通常全開のOutboundを絞る必要がある) |
ログ出力 | APIコール:CloudTrail コマンド:CloudWatch Logs、S3(ただし、logs/s3の VPC Endpointが必要。またPort Forwarding時に非対応) | APIコール:CloudTrail |
DNS要件 | Interface型のVPC Endpointは、DNSの書き換えを 行うため、VPCの「DNS解決を有効化」と 「DNSホスト名を有効化」をONにする必要がある | DNSの書き換えをしない。VPCのDNS設定は不要 |
接続対象 | EC2インスタンス オンプレミスサーバ | EC2インスタンス、RDS、VPC内のプライベートIPを 持っているすべてのもの |
上記のDNS要件について具体的に言うと、例えばSSMのEndpointの場合、作成前と作成後の、EC2インスタンスから見たIPアドレスが異なります。VPC Endpointを作成することによって、Internetにアクセスできない環境でもAWSサービスにアクセスできるようになります。
(VPC Endpoint作成前)
$ dig ssm.ap-northeast-1.amazonaws.com +short
99.77.60.93
(VPC Endpoint作成後)
$ dig ssm.ap-northeast-1.amazonaws.com +short
10.0.142.185
一方、EICEはEndpointがプライベート化になりません。
(VPC Endpoint作成前も作成後も)
$ dig ec2-instance-connect.ap-northeast-1.amazonaws.com +short
52.119.222.137
それぞれの利用シーン
EICEを利用するシーンは、
- テスト用途など、コストや手軽さを最優先に考えるとき
- EC2インスタンスだけでなく、プライベートなRDSなどに接続するとき
簡単でコストがかからないため、できるだけEICEを使いたいです。しかし、特にエンタープライズ環境において、SSM Session Managerの利用を推奨するシーンが多く存在します。
- SSMの他の機能も利用しているとき
- 接続の冗長性が必要なとき(EICEはVPCごとに1個のENIしか持たない)
- ユーザが入力したコマンドをログに記録する必要があるとき(EICEはコマンド内容まで記録できない)
- Internet経由ではなく、完全閉域のとき(接続元も接続先も閉域環境)
- きめ細かなアクセス制御
操作ログの記録
SSM Session Managerのログ機能は、ユーザがセッション中に入力したコマンドやその実行結果を含めて記録することができます。以下の例では、「ls /etc/systemd」というコマンドがユーザによって入力され、その結果としてファイルの一覧が表示されています。
{
"eventVersion": "1.0",
"eventTime": "2023-06-24T16:30:58Z",
"awsRegion": "ap-northeast-1",
"target": {
"id": "i-0683ba2d85e2a13aa"
},
"userIdentity": {
"arn": "arn:aws:iam::123456789012:user/apiuser"
},
"runAsUser": "ssm-user",
"sessionId": "apiuser-0a08b31c9539055ea",
"sessionData": [
"sh-5.2$ ls /etc/systemd",
"coredump.conf journald.conf network oomd.conf resolved.conf system system.conf.d user",
"homed.conf logind.conf networkd.conf pstore.conf sleep.conf system.conf timesyncd.conf user.conf"
]
}
完全閉域環境
「Internet経由ではなく、完全閉域のとき」になぜSSM Session Managerが必要かというと、EICEは、接続元がInternetから接続することを想定しています。例えば、aws cliを使って、EICE経由でEC2インスタンスに接続する際に以下のコマンドを使用します:
C:\>aws ec2-instance-connect ssh --instance-id i-02de068d44a67322b
この場合、接続元のWindows PCは「ec2-instance-connect.ap-northeast-1.amazonaws.com」というエンドポイントURLに接続しようとします。しかし、接続元のWindows PCがInternetに接続されていない環境にある場合、上記コマンドはエラーが発生し失敗します。
レアケースかもしれませんが、2つのAWSアカウントがあり、それぞれのAWSアカウントに1つのEC2インスタンスがPrivate Subnetに存在するとします。VPC PeeringやTransit Gatewayの設定がない場合、これらの2つのEC2インスタンス間でSSHセッションを確立するには、SSM Session Managerを使用することができますが、EICEではできません。
きめ細かなアクセス制御
EICEでもアクセス制御は可能ですが、記述方法はSSM Session Managerと異なります。EICEのIAM Policyを記述する際に、Resourceに記述するのはECIEのIDであり、EC2インスタンスのIDではありません。例えば以下のようなIAM Policyを作成します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:DescribeInstanceConnectEndpoints",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "ec2-instance-connect:OpenTunnel",
"Resource": "arn:aws:ec2:ap-northeast-1:123456789012:instance-connect-endpoint/eice-05106b3f84bb0c112"
}
]
}
これはaws cliで、EICEのopen-tunnelサブコマンドを利用するのに必要最小限の権限です。この権限をユーザに付与し、そのユーザでaws cliで接続してみますと
C:\>aws ec2-instance-connect open-tunnel --instance-connect-endpoint-id eice-05106b3f84bb0c112 --private-ip-address 172.10.20.100 --remote-port 22 --local-port 50022
Listening for connections on port 50022.
[1] Accepted new tcp connection, opening websocket tunnel.
(このメッセージが表示された後、TeraTermなどのSSHクライアントでローカルの50022番ポートに問題なく接続できました)
このように問題なく接続できます。
アクセスできるEC2インスタンスを制御したい場合、Conditionを使います。例えば特定のタグを持っているEC2インスタンスにのみアクセスできるようにするには、以下のようにIAM Policyを変更します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:DescribeInstanceConnectEndpoints",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "ec2-instance-connect:OpenTunnel",
"Resource": "arn:aws:ec2:ap-northeast-1:123456789012:instance-connect-endpoint/eice-05106b3f84bb0c112",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/Division": "Finance"
}
}
}
]
}
再度aws cliでトンネルを開いて、Division=Financeタグが付与されていないEC2インスタンスに、TeraTermなどで接続してみるとエラーが発生しました。
C:\>aws ec2-instance-connect open-tunnel --instance-connect-endpoint-id eice-05106b3f84bb0c112 --private-ip-address 172.10.20.100 --remote-port 22 --local-port 50022
Listening for connections on port 50022.
[1] Accepted new tcp connection, opening websocket tunnel.
2023-06-25 13:29:40,260 - awscli.customizations.ec2instanceconnect.websocket - ERROR - {"ErrorCode":"AccessDeniedException","Message":"User: arn:aws:iam::123456789012:user/testuser is not authorized to perform: ec2-instance-connect:OpenTunnel on resource: arn:aws:ec2:ap-northeast-1:123456789012:instance-connect-endpoint/eice-05106b3f84bb0c112 because no identity-based policy allows the ec2-instance-connect:OpenTunnel action"}
AWS_ERROR_HTTP_WEBSOCKET_UPGRADE_FAILURE: Failed to upgrade HTTP connection to Websocket.
このように、EICEでも接続先の制御は可能です。ただし、現時点ではサポートされているアクセス先制御用のConditionキーは、タグやプライベートIPアドレスのみです。インスタンスIDなどでの指定はできません。将来的には追加される可能性もあるため、公式ドキュメントの更新に注目する必要があります。
EICEと比較して、SSM Session Managerのほうはより細かなアクセス制御が可能です。詳細については公式ドキュメントを参照してください。ただし、個人的にはほとんどの場合、EICEのアクセス制御でも十分ではないかと考えています。セキュリティ要件を考慮して選択することがおすすめです。