AWS FargateのECSタスクのコンテナでポートフォワードする

ECS ExecがどうもマネージドなSSM Agentを使って動いているということはわかっていたが、実際どうなっているのかよくわからなかった。

aws ssm start-sessionを実行できそうな雰囲気があるが、--targetに何を渡せばいいのかよくわからなかった。 session-manager-pluginを実行しているようなので、aws ecs execute-commandを実行しつつpsコマンドを実行してみる。

sugawara         80091   0.1  0.1  5441620  17444 s002  S+    4:39PM   0:00.11 session-manager-plugin {"sessionId": "ecs-execute-command-0acebb01a1ed41142", "streamUrl": "wss://ssmmessages.ap-northeast-1.amazonaws.com/v1/data-channel/ecs-execute-command-0acebb01a1ed41142?role=publish_subscribe", "tokenValue": "(省略)"} ap-northeast-1 StartSession  {"Target": "ecs:hello_7412261320c54ef9a1ae606175e9bec1_7412261320c54ef9a1ae606175e9bec1-3811061257"} https://ecs.ap-northeast-1.amazonaws.com

"Target": "ecs:hello_7412261320c54ef9a1ae606175e9bec1_7412261320c54ef9a1ae606175e9bec1-3811061257"

なにこれ?

いろいろ探してみるがドキュメントが見当たらないのでaws cliソースコードを読む。

github.com

def build_ssm_request_paramaters(response, client):
    cluster_name = response['clusterArn'].split('/')[-1]
    task_id = response['taskArn'].split('/')[-1]
    container_name = response['containerName']
    # in order to get container run-time id
    # we need to make a call to describe-tasks
    container_runtime_id = \
        get_container_runtime_id(client, container_name,
                                 task_id, cluster_name)
    target = "ecs:{}_{}_{}".format(cluster_name, task_id,
                                   container_runtime_id)
    ssm_request_params = {"Target": target}
    return ssm_request_params

クラスタ名・タスクID・コンテナIDでTergetを構築しているっぽい。 クラスタ名とタスクIDとコンテナの名前がわかっているなら以下のようにaws ssm start-sessionを実行できる。

~% CLUSTER=hello
~% TASK_ID=7412261320c54ef9a1ae606175e9bec1
~% CONTAINER_NAME=busybox
~% CONTAINER_ID=$(aws ecs describe-tasks --cluster $CLUSTER --task $TASK_ID | jq -r --arg CONTAINER_NAME $CONTAINER_NAME '.tasks[0].containers[] | select(.name == $CONTAINER_NAME).runtimeId')
~% aws ssm start-session --target ecs:${CLUSTER}_${TASK_ID}_${CONTAINER_ID}

Starting session with SessionId: root-06ad4aa7ce3831373
# 

ポートフォワードも可能。

~% aws ssm start-session --target ecs:${CLUSTER}_${TASK_ID}_${CONTAINER_ID} --document-name AWS-StartPortForwardingSession --parameters '{"portNumber":["8080"],"localPortNumber":["18080"]}'

Starting session with SessionId: root-08212759680ea948b
Port 18080 opened for sessionId root-08212759680ea948b.
Waiting for connections...

Connection accepted for session [root-08212759680ea948b]
~% curl localhost:18080
Hello World!

これでコンテナにstoneでも入れておけば、Fargateのタスクを踏み台にしてデータベースなどへのアクセスができる。 ドキュメントがないっぽいのがやや気になるが…