LoginSignup
4
2

More than 1 year has passed since last update.

AWS Fargateでポートフォワーディング

Last updated at Posted at 2021-12-06

この記事はAWS Containers Advent Calendar 2021の7日目です。


業務でAWS Fargateを使ってシステムを構築しているんですが、手元から直接DBにアクセスしたい作業などがあるのでポートフォワーディングをなんとかできないかと考えていました。

ECS ExecがマネージドなSSMエージェントで動いているようだったので、なんとなくポートフォワーディングできそうな雰囲気を感じていたのですが、マネージドなSSMエージェントを使う具体的なやり方は不明。

多分、aws ssm start-session--targetに何かを渡せば良さそうですが、何を渡せばいいのかわからず。aws ecs execute-command実行時にsession-manager-pluginを実行しているようだったので、とりあえず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のソースコードを読みました。

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 N=$CONTAINER_NAME \
      '.tasks[0].containers[] | select(.name == $N).runtimeId')
$ aws ssm start-session --target ecs:${CLUSTER}_${TASK_ID}_${CONTAINER_ID}

Starting session with SessionId: root-06ad4aa7ce3831373
# 

SSMドキュメントを指定すればポートフォワーディングも可能です。

$ 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のタスクを踏み台にしてDBにアクセスできるようになりました。

※ちなみに一連のTarget文字列生成とaws ssm start-sessionをまとめて行うecs-exec-pfというコマンドも作成しました。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2