AWS System Managerセッションマネージャーでポートフォワードする

AWS System Managerセッションマネージャーでポートフォワードする

2019.09.22

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

AWS System Managerセッションマネージャーを利用し、SSM エージェントのインストール先インスタンスからローカルに対してポートフォワードする手順を紹介します。

ユースケース

リモートの Windows サーバーにリモートデスクトップ(RDP)でアクセスするケースを考えます。

本機能を利用することで、以下のようなメリットがあります。

  • リモート VPC のセキュリティグループで RDP ポートを開けなくてよい
  • RDP ポート(3389)のアウトバウンド通信が許可されていなくても、セッションマネージャーが利用するHTTPS(443) ポートだけで RDP 可能
  • プライベートサブネットのサーバーに対して、踏み台を経由せずに直接 RDP 可能
  • リモートサーバーに SSH をインストールしなくてよい

注意点として、ポートフォワード出来るのは、リモートサーバー内で LISTEN しているポートのみです(SSH ポートフォワードで言うところの$ ssh -L 9999:localhost:80 user@SERVER)。

リモートサーバーからアクセス可能な別サーバーのポートはフォワードできないことにご注意ください(SSH ポートフォワードで言うところの $ ssh -L 9999:MySQL:3306 user@SERVER)。例えば、EC2を踏み台にして、RDS に接続することはできません。

そのようなケースに対応するには SSH 版 Systems Manager セッションマネージャーの利用を検討ください。

AWS Systems Manager セッションマネージャーでSSH・SCPできるようになりました

コマンド体系

端的に言えば、AWS System Managerセッションマネージャー接続時と同じコマンド体系です。

違いは、ポートフォワード用ドキュメント(AWS-StartPortForwardingSession)を指定し、リモート・ローカルのポートを指定する引数が増えただけだけです。

System Managerセッションマネージャー接続コマンド

$ aws ssm start-session --target i-123 

System Managerセッションマネージャーポートフォワードコマンド

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

セッションマネージャーの利用環境が整っていない場合、まずは次のドキュメントを元に環境を整えてください。

Getting Started with Session Manager - AWS Systems Manager

やってみた

リモートサーバーの 80 番ポートで起動する nginx にポートフォワードしてみます。

1. System Managerエージェントのアップデート

本機能を利用するには、System Managerエージェントのバージョンが 2.3.672.0 以上である必要があります。 これよりも古い場合は、エージェントを最新版にアップデートしてください。

SSM を利用し、ドキュメント AWS-UpdateSSMAgent を RunCommand すればアップデートされます。

2. Session Managerプラグインのアップデート

本機能を利用するには、Session Managerプラグインのバージョンが 1.1.26.0 以上である必要があります。

これよりも古い場合は、プラグインを最新版にアップデートしてください。

# アップデート $ curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/mac/sessionmanager-bundle.zip" -o "sessionmanager-bundle.zip" $ unzip sessionmanager-bundle.zip $ sudo ./sessionmanager-bundle/install \ -i /usr/local/sessionmanagerplugin \ -b /usr/local/bin/session-manager-plugin # バージョンチェック $ session-manager-plugin --version 1.1.31.0 

3. ポートフォワード

セッションマネージャーでポートフォワードするには

ポートフォワード用ドキュメント(AWS-StartPortForwardingSession)を指定し、リモート・ローカルのポートを指定するだけです。

$ aws ssm start-session --target $INSTANCE_ID \ --document-name AWS-StartPortForwardingSession \ --parameters '{"portNumber":["80"],"localPortNumber":["8000"]}' Starting session with SessionId: botocore-session-1569008417-05521c0a55edb2d55 Port 8000 opened for sessionId botocore-session-1569008417-05521c0a55edb2d55. 

localPortNumber を省略すると、自動で空いているポートが割り振られます。

$ aws ssm start-session --target $INSTANCE_ID \ --document-name AWS-StartPortForwardingSession \ --parameters '{"portNumber":["80"]}' Starting session with SessionId: botocore-session-1569064990-098c3a6376b82743c Port 51959 opened for sessionId botocore-session-1569064990-098c3a6376b82743c. 

このケースだと51959 です。

リモートのポート番号(portNumber)を省略すると、80番ポートが利用されます。

4. 接続確認

別ターミナルで、ローカルポートに対してアクセスしてみます。

$ curl -I localhost:51959 HTTP/1.1 200 OK Server: nginx/1.12.2 Date: Sat, 21 Sep 2019 11:23:27 GMT Content-Type: text/html Content-Length: 3520 Last-Modified: Wed, 28 Aug 2019 19:52:13 GMT Connection: keep-alive ETag: "5d66db6d-dc0" Accept-Ranges: bytes 

確かに、ポートフォワードされていますね。

ポートフォワードアクティヴィティを監視

本機能を利用すると、意図的に特定ポートの通信を塞ぐようにネットワーク設計した環境において、利用者がその制約を回避できてしまう可能性があります。

SSMエージェントや素のセッションマネージャーは、運用面のメリットから許容するとして、過度なポートフォワードの利用には監視の目を光らせたい場合は、CloudTrail を有効化し

  • CloudWatch Events を使って StartSession の API 呼び出しをリアルタイム監視
  • Athena を使って CloudTrail ログ から StartSession の API 呼び出しをバッチ監視

してください。

SSM:StartSession すると CloudTrail には以下の様なログが残ります。

{ "eventVersion": "1.05", "userIdentity": { "type": "AssumedRole", "principalId": "...", "arn": "arn:aws:sts::1234:assumed-role/...", "accountId": "1234", "accessKeyId": "...", "sessionContext": { ... } }, "eventTime": "2019-09-21T11:28:18Z", "eventSource": "ssm.amazonaws.com", "eventName": "StartSession", "awsRegion": "eu-central-1", "sourceIPAddress": "1.2.3.4", ... "requestParameters": { "target": "i-1234", "documentName": "AWS-StartPortForwardingSession", "parameters": { "localPortNumber": [ "8000" ], "portNumber": [ "80" ] }, "responseElements": { ... }, "requestID": "...", "eventID": "...", "resources": [ { "accountId": "1234", "ARN": "arn:aws:ec2:eu-central-1:1234:instance/i-1234" }, { "accountId": "1234", "ARN": "arn:aws:ssm:eu-central-1::document/AWS-StartPortForwardingSession" } ], "eventType": "AwsApiCall", "recipientAccountId": "1234" } 

ドキュメント AWS-StartPortForwardingSession の仕様を確認

  • PortNumber(フォワードされるリモートサーバーのポート)
  • localPortNumber(フォワード先のローカルサーバーのポート)

が定義されているだけです。

{ "schemaVersion": "1.0", "description": "Document to start port forwarding session over Session Manager", "sessionType": "Port", "parameters": { "portNumber": { "type": "String", "description": "(Optional) Port number of the server on the instance", "allowedPattern": "^([1-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$", "default": "80" }, "localPortNumber": { "type": "String", "description": "(Optional) Port number on local machine to forward traffic to. An open port is chosen at run-time if not provided", "allowedPattern": "^([0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$", "default": "0" } }, "properties": { "portNumber": "{{ portNumber }}", "type": "LocalPortForwarding", "localPortNumber": "{{ localPortNumber }}" } } 

最後に

AWS Systems Manager セッションマネージャーのポートフォワード機能を紹介しました。

SSH の複雑なオプションと格闘することなく、だれでも簡単にポートフォワードできます。

現時点ではシンプルなポートフォワードにしか対応していませんが、今後のアップデートにより、より多くの SSH ポートフォワードのケースを置き換えられるようになるのではないでしょか。

それでは。

参考

この記事をシェアする

FacebookHatena blogX

関連記事