SSMセッションマネージャーのリモートホストへのポートフォワードが切断される

概要

待望のSystems Manager セッションマネージャーのリモートホストへのポートフォワード機能がリリースされました。

早速試していたところ、最初はうまくいくのですが、途中で接続が切断されてしまう問題が発生し、調査を通して解決できたので、今回記事に起こしてみました。


まとめ

踏み台サーバーのSSMエージェントのバージョンを3.1.1476.0以上にする。

リモートホストへのポートフォワード機能の使用自体は3.1.1374.0以上が必要


目次

目次


リモートホストへのポートフォワード

ローカル環境からプライベートサブネットのRDSなどへのアクセスをしたいときってありますよね。


今までは踏み台サーバーを通して、Systems Manager(SSM)のセッションマネージャーSSHポートフォワード機能(とSSH自体のトンネリングの設定)を通して行うことができました。

しかしこの場合、踏み台サーバー上でSSHデーモンを起動し、22番ポートを開け、クライアントにはSSHのコンフィグファイルを置いて、各ユーザーのSSH秘密鍵を作成して配布して・・・などの手間やセキュリティ的な問題もあり、運用には少し大変なところがありました。

(他にもVPNを用いた方法などもありますが、今回は触れません。)


もともと、セッションマネージャーにはポートフォワード機能というものがありました。

しかしこれは、クライアントから踏み台サーバーのリッスンするポートへの接続フォワーディングであり、その先で接続したいRDSなどリモートホストへのフォワーディングはできませんでした。


しかし今回、なんとこの問題を解決する、SSMセッションマネージャーからリモートホストへのポートフォワード機能」がリリースされました!

aws.amazon.com


前提

今回の検証環境ですが、踏み台サーバーにはEC2ではなく、ECS on Fargate(プライベートサブネット)を用いております。

基本的には挙動は変わらないはずですが、もし違いなどがありましたらすみません。。。

※ECSのコンテナにはubuntu:20.04(x86_64)のイメージを使用しています。

※クライアントPC(ローカルPC)環境はMac OS + bashになります。


現象

やりたかったこと

ローカルPC -> 踏み台 -> Aurora(プライベートサブネット)

こちらをSSM セッションマネージャーのリモートホストへのポートフォワード機能で実現したいというのが目的でした。

具体的には、セッションマネージャーによるポートフォワード完了後、ローカルPCのターミナルから直接MySQLにログインする、ということがしたかったわけです。


※踏み台・SSM自体の構築方法などは省略します。


接続成功

とりあえず、セッションマネージャーを通してリモートホストへのポートフォワードは完了し、ローカルPCから直接MySQLSQLクエリも投げることができました。

  • ターミナル1: SSM
$ DB_HOST="(db host)"
$ LOCAL_DB_PORT="13306"
$ REMOTE_DB_PORT="3306"

$ target="(target instance ID)"
$ parameters="{\"host\":[\"${DB_HOST}\"],\"portNumber\":[\"${REMOTE_DB_PORT}\"], \"localPortNumber\":[\"${LOCAL_DB_PORT}\"]}"

$ aws ssm start-session \
$     --target ${target} \
$     --document-name AWS-StartPortForwardingSessionToRemoteHost \
$     --parameters "${parameters}"

Starting session with SessionId: goto-xxxxxxxxxxxxxx
Port 13306 opened for sessionId goto-xxxxxxxxxxxxxx.
Waiting for connections...

Connection accepted for session [goto-xxxxxxxxxxxxxx]
  • ターミナル2: MySQL
$ mysql -u goto -p -h127.0.0.1 -P13306 # localポートを13306にしてある
Enter password: 

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 38686
Server version: 5.7.12-log MySQL Community Server (GPL)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
s
mysql> SELECT COUNT(*) FROM tbl1;
+----------+
| count(*) |
+----------+
|      122 |
+----------+
1 row in set (0.02 sec)


問題発生:切断

本題です。

一度SQLクエリを投げ安心した後、少し時間を置いて(1分くらい)再度SQLクエリを投げると・・・


  • ターミナル1: SSM
## ターミナル2でMySQLクエリを再度投げてエラーが出たときに以下メッセージが出力
Cannot perform start session: EOF
  • ターミナル2: MySQL
mysql> SELECT COUNT(*) FROM tbl1;
ERROR 2013 (HY000): Lost connection to MySQL server during query
No connection. Trying to reconnect...
Enter password: 
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0
ERROR: 
Can't connect to the server


途中で接続が切断されてしまう問題が発生しました。。。

何度か試してみると、だいたい30秒くらい間を置いておくと接続が切れるようです。


調査①

SSMエージェントの設定

踏み台サーバー内の、SSMエージェントの設定ファイルを確認してみることにしました。

※もともとSSMエージェントインストール時に用意されるamazon-ssm-agent.json.templateファイルは以下のようになっています。

github.com


amazon-ssm-agent.jsonファイル全内容(デフォルト)

# cat /etc/amazon/ssm/amazon-ssm-agent.json
{
    "Profile":{
        "ShareCreds" : true,
        "ShareProfile" : "",
        "ForceUpdateCreds" : false,
        "KeyAutoRotateDays": 0
    },
    "Mds": {
        "CommandWorkersLimit" : 5,
        "StopTimeoutMillis" : 20000,
        "Endpoint": "",
        "CommandRetryLimit": 15
    },
    "Ssm": {
        "Endpoint": "",
        "HealthFrequencyMinutes": 5,
        "CustomInventoryDefaultLocation" : "",
        "AssociationLogsRetentionDurationHours" : 24,
        "RunCommandLogsRetentionDurationHours" : 336,
        "SessionLogsRetentionDurationHours" : 336,
        "PluginLocalOutputCleanup": "",
        "OrchestrationDirectoryCleanup": ""
    },
    "Mgs": {
        "Region": "",
        "Endpoint": "",
        "StopTimeoutMillis" : 20000,
        "SessionWorkersLimit" : 1000,
        "DeniedPortForwardingRemoteIPs" : [
            "169.254.169.254",
            "fd00:ec2::254",
            "169.254.169.253",
            "fd00:ec2::253",
            "169.254.169.123",
            "169.254.169.250"
        ]
    },
    "Agent": {
        "Region": "",
        "OrchestrationRootDir": "",
        "SelfUpdate": false,
        "TelemetryMetricsToCloudWatch": false,
        "TelemetryMetricsToSSM": true,
        "AuditExpirationDay" : 7,
        "LongRunningWorkerMonitorIntervalSeconds": 60
    },
    "Os": {
        "Lang": "en-US",
        "Name": "",
        "Version": "1"
    },
    "S3": {
        "Endpoint": "",
        "Region": "",
        "LogBucket":"",
        "LogKey":""
    },
    "Kms": {
        "Endpoint": ""
    }
}


※各パラメータの説明は以下になります。

github.com


StopTimeoutMillis

よく見ると、MdsMgsに、"StopTimeoutMillis" : 20000という設定があります。

    "Mds": {
        ...
        "StopTimeoutMillis" : 20000,
        ...
    },
    ...
    ...
    "Mgs": {
        ...
        "StopTimeoutMillis" : 20000,
        ...
    },
    ...


設定変更

上記2箇所にあるStopTimeoutMillisが怪しいと踏んで、設定を変更してみることにしました。

ただ、MdsMgs、どちらをいじれば良いのかわからなかったため、とりあえず両方ともStopTimeoutMillisをテキトーに600000(ミリ秒)、つまり10分にしてみました


  • 変更前
    • Mgs."StopTimeoutMillis" : 20000 # 20秒
    • Mds."StopTimeoutMillis" : 20000 # 20秒
  • 変更後
    • Mgs."StopTimeoutMillis" : 600000 # 600秒
    • Mds."StopTimeoutMillis" : 600000 # 600秒


※Mds, Mgsとは以下の通りだそうです。

  • Mds = Message Delivery Service
    • Mgs - represents configuration for Message Gateway service
  • Mgs = Message Gateway Service
    • Mds - represents configuration for Message delivery service (MDS) where agent listens for incoming messages


再検証

上記の設定変更後、同じ内容で検証してみました。



しかし。。。

直りませんでした。。。


調査②

リリース情報確認

Session ManagerプラグインとSSMエージェントのリリース・更新情報を見ていると、直近で何だかそれっぽいバグフィックスのコミットメッセージを発見しました。


Version Release date Details
1.2.331.0 May 27, 2022 Bug fix: Fix port sessions closing prematurely when the local server doesn't connect before timeout.

docs.aws.amazon.com


  • SSMエージェント
Version Release date Details
3.1.1476.0 May 27, 2022 Fix port session premature close when local server is not connected before timeout

github.com


バージョンアップデート

まずはバージョンを確認して、最新のバージョンにアップデートしてみました。

AWS CLI(ローカルPC)

  • 検証時
    • aws-cli/2.4.6 Python/3.8.8 Darwin/19.6.0 exe/x86_64 prompt/off
  • アップデート後
    • aws-cli/2.7.5 Python/3.9.11 Darwin/19.6.0 exe/x86_64 prompt/off


Session Manager プラグイン(ローカルPC)

  • 検証時
    • 1.2.279.0
  • アップデート後
    • 1.2.331.0

前述のバグフィックス反映される前のものを使用していたので、これで反映されるはずです。


SSMエージェント(踏み台サーバー)

  • 検証時
    • 3.1.1446.0
  • アップデート後
    • 3.1.1476.0

こちらも前述のバグフィックス反映される前のものを使用していました。

※今回のリモートホストへのポートフォワード機能を使うには、SSMエージェントのバージョンは 3.1.1374.0 以上が必要です。


再検証

上記SSMエージェントなどのバージョンを上げて試してみました。

すると。。。



10分放置した後にSQLを投げてもクエリが通りました!!

つまり、切断される問題が発生しなくなりました!!!


補足

無事、切断される問題が発生しなくなったのでめでたしなのですが、一応以下補足を追記します。


バージョンアップの対象

上記では、AWS CLI、Session Manager プラグイン、SSMエージェントそれぞれのアップデートを行いました。

しかし結局どれが問題解決に直結したのかわからなかったため、検証してみました。


ローカルPCのSession Manager プラグインのみアップデート(踏み台サーバーのSSMエージェントはアップデートしない)して検証しても、問題は解消しませんでした。

一方、ローカルPCのAWS CLI、Session Manager プラグインが古いまま、踏み台サーバーのSSMエージェントのみアップデートした場合、問題が解消されました。


つまり、結果として、踏み台サーバーのSSMエージェントのアップデートのみで問題は解決するということがわかりました。


最後に

すごく便利で、個人的にもまさに待望な機能だったので、ちゃんと使えるようになって良かったです。

いつか踏み台サーバ自体が必要なくなったらさらにいいんだけどな・・・