SSM Session Managerを使ってポートフォワードする

AWS SSM Session Managerを利用することで、ポートフォワーディングが可能になります。 EC2インスタンスに対してローカルからアクセスしたいポートは多岐にわたります(SSH,FTP,HTTP,rsync,DB...)。 ポートフォワーディングを行うことでセキュリティグループの変更なしに、EC2インスタンスのポートへアクセスが可能となります。
2022.03.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Session Managerについて

Session ManagerはAWS Systems Manager(SSM)の機能の一つです。

Session ManagerはEC2インスタンスなどのエージェントがインストールされたマシンとクライアントの間にセッションを作成してくれます。

特徴としてはホスト側がプル式でセッションを作成するため、セキュリティグループによるポートの開放が不要になります。

不必要にポートを解放する必要がなくなり、セキュリティが向上します。

また、Session Mnagerを利用して通信を行うとアクティビティのログが保存可能で、コンプライアンスの観点からも便利です。

今回は、Session Managerの機能をつかってEC2インスタンスのポートをローカルにポートフォワードしてみたいと思います。

こうすることで、セキュリティグループでポートを解放せずともEC2インスタンスのポートにアクセス可能となります。

準備

EC2インスタンスを用意します。 Session Managerを利用するためには以下の3つの条件が揃っている必要があります。

  • SSMのエンドポイントへのアクセスが可能
  • SSM Agentがインストールされている
  • 適切なIAMロールがインスタンスプロファイルに割り当てられている

今回は以下のようなインスタンスを作成しました。

  • Public IPが割り当てられインターネットへのアクセスが可能(SSMのエンドポイントへのアクセスが可能)
  • マシンイメージはAmazon Linux 2 (SSM Agentはデフォルトでインストール済み)
  • AmazonSSMManagedInstanceCoreをインスタンスプロファイルに割り当て済み(インスタンスがSSMにアクセスするのに必要な権限が含まれている)
  • セキュリティグループのインバウンドは全て拒否、アウトバウンドは全て許可

接続してみる

EC2インスタンスに対してポートフォワードを行ってみます。

セッションの作成

$ aws ssm start-session --target i-0123456789ABCDEFG \
                       --document-name AWS-StartPortForwardingSession \
                       --parameters '{"portNumber":["22"],"localPortNumber":["10022"]}'
Starting session with SessionId: XXXXXXX
Port 10022 opened for sessionId XXXXXXX.
Waiting for connections...

# SSHなどで通信が開始すると以下のメッセージが表示される。
Connection accepted for session [XXXXXXX]

今回は、EC2インスタンスの22番ポートをローカルの10022番にポートフォワードしています。

つまりは、ローカルの10022番を利用して通信を行う場合はすべてEC2インスタンスの22番に転送されます。

試しに、SSHで接続してみます。

SSHで接続する

$ ssh ec2-user@localhost -p 10022 -i XXXXXXX.pem 
Last login: Tue Mar 29 06:52:33 2022 from localhost

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/

ローカルホストの10022番に対してアクセスしましたが、EC2インスタンスにつながりました。 無事ポートフォワードが機能していることが確認できました。

このとき注意点として、SSHで接続する場合はEC2に公開鍵が設定されている必要があります。

セッションを作成するまではSSMが行ってくれるので認証情報は必要ありませんが、セッション作成後は単純にSSHでの接続となるので認証情報が必要となります。

今回はsshコマンドの-iオプションで認証情報のファイルを指定しています。

SSH Configファイルに設定するともっと便利に

SSHで接続するたびに毎回AWS CLIでコマンドを叩くのは冗長かもしれません。

SSHのConfigファイルに以下の内容を記述すればもう少し簡単にアクセスできます。

~/.ssh/config

host i-* mi-*
    ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"

この設定があれば以下のように接続することができます。

SSHで接続

$ ssh ec2-user@i-0123456789ABCDEFG -i ./XXXXXXX.pem 
Last login: Tue Mar 29 17:15:48 2022 from localhost

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/

おまけ

ポートフォワードで通信を行なっているため、ある程度自由にポートを転送することができます。

いろいろなアプリケーションで接続してみます。

SFTP

先ほどと同様にEC2インスタンスの22番ポートをローカルの10022番にポートフォワードすればSFTPも利用可能です。

SFTPで接続

$ sftp -oPort=10022 -i XXXXXXX.pem ec2-user@localhost
Connected to localhost.
sftp> put ./dummy.txt 
Uploading ./dummy.txt to /home/ec2-user/dummy.txt
./dummy.txt         100%   14     0.5KB/s   00:00    
sftp> quit

HTTP

次は別のポートで試してみます。 EC2インスタンスにNginxをインストールし80番ポートをローカルの10080番にポートフォワードします。

HTTP

$ aws ssm start-session --target i-0123456789ABCDEFG \
                       --document-name AWS-StartPortForwardingSession \
                       --parameters '{"portNumber":["80"],"localPortNumber":["10080"]}'

先ほどと違うのはポート番号だけです。

cURLを用いて、ローカルの10080番にアクセスしてみます。

cURLでアクセスする

$ curl -I http://localhost:10080
HTTP/1.1 200 OK
Server: nginx/1.20.0
Date: Tue, 29 Mar 2022 07:19:52 GMT
Content-Type: text/html
Content-Length: 3520
Last-Modified: Thu, 15 Jul 2021 21:46:50 GMT
Connection: keep-alive
ETag: "60f0acca-dc0"
Accept-Ranges: bytes

無事にNginxからリクエストが返ってきました。

参考