この記事は公開されてから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 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 ポートフォワードのケースを置き換えられるようになるのではないでしょか。
それでは。