[AWS ECS]Fargateのcontainerにシェルで入りたい(sshd無しで！)

# [AWS ECS]Fargateのcontainerにシェルで入りたい(sshd無しで！)

## 2021/3/16

ついにecsのfargateにもaws cli経由でdocker exec的なことができるようになったそうです。
実際に僕もfargateのecsクラスタでためしてみましたが、 タスクroleに権限追加したのと、platform-veresionを1.4.0に、さらに、ドキュメンにあるとおりの追加のオプションをつけるだけでローカルのmacからecsのコンテナに入ることができました。

こちらのほうがだいぶ使いやすそうなので、これからはこちらがおすすめだと思います。
https://aws.amazon.com/jp/about-aws/whats-new/2021/03/amazon-ecs-now-allows-you-to-execute-commands-in-a-container-running-on-amazon-ec2-or-aws-fargate/

一点ハマったのは、 実際にコンテナに入る `aws ecs execute-command` が

```
% aws --version
aws-cli/2.1.30 Python/3.8.8 Darwin/20.3.0 exe/x86_64 prompt/off
```
のaws cli2だとまだ実装されていないようで、エラーになってしまいました。(2021/3/16現在の2系の最新だと思うんですが・・・)
aws cli1系の最新だと正常に実行できるようでした。
(3/17追記 v2系に execute-commandが入るのは、 2.1.31 からのようです。 https://github.com/aws/aws-cli/issues/6022)

---------
ecsのFargateいいですね。コンテナ単位でcpuとかメモリとか指定する必要はあれど、elastic beanstalkや ec2ベースのecsクラスタのようにec2を意識せずにクラスタ組めるのはともていい感じだと思います。

・・・が、ec2を意識しないが故に、困ったときのsshアクセスができません。これはトラブルシュート時や開発初期はとても困ります。
かといって、docker containerにsshの口を開けるのもなんとも負けた感じがします。

Fargateいいけど、docker execできたらなーと思っていましたが、そんなことはみんなが思っていることのようで、下記のようなissueが数年前から立っておりました。

[How to run "docker exec... " command in ECS](https://github.com/aws/containers-roadmap/issues/187)

すると最近(2019/5/8)

*「SSMつかったら、Fargateコンテナのシェルにアクセスできたよ」*

というコメントが出てきました！！ (参考： https://github.com/aws/containers-roadmap/issues/187#issuecomment-490347856)

セッションマネージャーでawsコンソール(やaws-cli)から、シェルアクセスできるのは知っていたのですが、ec2が見えないfargateに関しては無理だろうと思い込んでいたのですが、読んでみるとできるようです。

これは来た！！とおもい試してみたところ、いろいろ使いづらいところはありつつも成功したのでメモ代わりに残しておきます。

# セッションマネージャー

AWS System managerの セッションマネージャーに関しては下記の記事を参照ください。

[SSH不要時代がくるか!?AWS Systems Manager セッションマネージャーがリリースされました!](https://dev.classmethod.jp/cloud/aws/ssm-session-manager-release/)

簡単にいうと、awsのコンソールや、cliの環境から、特定のaws内のec2にシェルアクセスができる、というものです。

インスタンスIDなどが必要なことから、実際に見えるEC2でないとできないのかな？と思いこんでいたのですが、上記のissueのコメントを見てみるとどうもそうではないらしかったので試してみます。

# 手順
Fargate自体の仕組みや、設定に関するところ全体を書くと、関係しない部分が多くなるため、必要な部分のみ抜粋します。

## しくみの概要

詳細手順の前に、どのように（EC2の見えない)Fargateコンテナに対して設定するのかの概要です。

前提：System Managerでは、aws内のec2以外でも、 AWSのコンソール(やcli)からアクティベーション処理を行う機能があり、 `amazon-ssm-agent` を起動しておくことで、 任意の環境のホストをセッションマネージャーのログイン対象にできる。


1. これを踏まえて、事前にアクティベーションを登録しておいて、 `Activation Code` と `Activatoin Id` を取得（これらに関しては後述)しておく
2. Fargateで動くコンテナのビルド時にDockerfileで、 `amazon-ssm-agent` をインストールしておく。
3. Fargetでコンテナが起動する際に、 上記「1.」の `Activation Code` 、 `Activation Id` を使って、自分のコンテナを System Managerに登録する、かつ、`amazon-ssm-agent` を引数なしで起動する。

これで、セッションマネージャーにFargateのコンテナが登録されてシェルを起動できるようになります。

## しくみの詳細

## Sysetem Managerにアクティベーション登録をする

AWS System Manager -> アクティベーションから「アクティベーションの作成」を実行する

![スクリーンショット 2019-06-25 9.49.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34692/b374c2c3-0872-e15a-e6f1-4591799f62fc.png)

「インスタンス制限」 というのがあり、一つのアクティベーションに対して、最大何個のホストを登録できるかの設定項目があります。
dockerで運用する場合、コンテナが起動する度に違うホスト扱いになり、コンテナを起動するたびに「登録できる残りコンテナ数」が減っていきます。

コンテナ破棄時に、ここの登録済み数をクリアする事ができれば気にしなくても良さそうなのですが、ちょっと方法がわからず、知っている方がいたら教えてほしい(切実)

(また、やらしいことに、 managed ec2以外を対象にする場合、ここのアクティベーションと登録済みインスタンス数によって課金とかにも関わってくるらしく気にせず作りっぱなしとかにもできなさそう(あまり詳しく調べていない)なのがつらいところです)

このアクティベーションを行うことで、下記のような `Activation Code` と `Activation ID` が生成されるのでメモします(一回しか出てこないので注意)

<img width="1159" alt="スクリーンショット 2019-06-25 23.07.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34692/9cb2bdff-4cb1-c41c-86a3-d226b54de910.png">


## エージェントのインストール

Fargateで動かすコンテナに `amazon-ssm-agent` をインストールする。

[上記のissueコメント](https://github.com/aws/containers-roadmap/issues/187#issuecomment-490347856)にあるように、

https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-install-managed-linux.html

で、OS毎に agent　のインストール方法がのっているので、これにしたがい Dockerfileに追記します。
今回自分の場合は ubuntu だったため、下記のようになります。

Dockerfile 

```Dockerfile
RUN curl https://s3.ap-northeast-1.amazonaws.com/amazon-ssm-ap-northeast-1/latest/debian_amd64/amazon-ssm-agent.deb -o /tmp/amazon-ssm-agent.deb \
    && dpkg -i /tmp/amazon-ssm-agent.deb \
    && cp /etc/amazon/ssm/seelog.xml.template /etc/amazon/ssm/seelog.xml
```

## コンテナの登録と、セッションマネージャー用エージェントの起動

### コンテナの登録
Fargateのコンテナ起動時に、上記アクティベーション時のコードと、IDでコンテナをSSMに登録します。

Fargateコンテナからアクセスする必要がある秘匿情報なので、最近使えるようになった、暗号化されたSSMのパラメータストアから取得するといいと思います。

詳細は、下記参照

[【祝！】FargateでもECSにごっつ簡単に環境変数に機密情報を渡せるようになりました！ ｜ DevelopersIO](https://dev.classmethod.jp/cloud/aws/fargarte-secrets/)

`SSM_AGENT_CODE`、`SSM_AGENT_ID`が、それぞれ上記で、メモした `Activation Code` と `Activation ID`です。

```sh
amazon-ssm-agent -register -code "${SSM_AGENT_CODE}" -id "${SSM_AGENT_ID}" -region "ap-northeast-1"
```

### エージェントの起動

セッションマネージャーからアクセスする際にエージェントが起動していないといけないのでバックグラウンドで起動しておきます。
この際、awsのドキュメントだと、サービスとして動かしているサンプルばかりなのですが、dockerコンテナなので、サービスいれるのもちょっとなと思って、単純にバックグラウンド起動にしています。 (supervisordとかで起動するのもいいかも)

```sh
  # agent 起動
  amazon-ssm-agent &
```

これで、fargateのコンテナが正常に起動すれば準備OKです！

## セッションマネージャーからのアクセス

System Managerのセッションマネージャーからセッションの開始を選択し、今登録されたインスタンスID(`amazon-ssm-agent -register` のログなどから確認してください)を指定します。

<img width="959" alt="スクリーンショット 2019-06-25 23.19.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34692/fd8f95be-d3ca-12e8-a426-a7731e3999d0.png">


## セッション開始！

下記のようにシェルのセッションが開始されます。

<img alt="スクリーンショット 2019-06-25 23.23.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34692/cb1b99ee-2c0c-3bb9-b263-01b1ca35d9a9.png">


この際ユーザが `ssm-user` というユーザになっているため、 docker containerが root で実行されているといろいろ実行できません。
（例えば、 `bin/rails console` など)

sudo可能なユーザなので、 Dockerfileで `sudo` 入れておいてsudoするのがいいと思います。
・・・が、その際、sudoで実行中のコマンドの環境変数は、Fargateで設定した環境変数が設定されていないため、

```
sudo -E bin/rails c
```

と、 sudo に、環境変数を保存する、 `-E` をつけて実行すると実行できるようになります。

この辺よくわかってないですが、コンテナ上で実行されているユーザはrootで、そこに対して環境変数が設定されているのですが、 セッションマネージャーで、ssm-userとして実行する際は、ssm-userの環境に環境変数が引き継がれているが、 sudoで実行するrootの環境変数には何も設定されていないようです。

## 掃除

料金体系とかあまり詳しくまだ調べられていないのですが マネージドなEC2に対してセッションマネージャーからアクセスするのと違い、少し違う設定が有効になるようです。

とりあえず、Fargateでこの設定を行う場合は、スポットでアクセスする場合に限り、一通り使った後は登録済みインスタンスや、アクティベーション等は手動で削除しています。

### 最後に

Fargateで唯一困ってたシェルアクセスに関して、結構安全そうな手段が見つかってよかったです。
ですが、やはり本来は、Fargateの機能としてシェルにアクセスしたい感じですよね。

そんな中、つい最近出ていた、Fargateの責任者の方へのインタビューだそうですが、

[AWSのコンテナ責任者が語るFargate、ECS、App Mesh、EKS、そしてKubernetes (1/2)：AWS Summit Tokyo 2019で聞いた - ＠IT](https://www.atmarkit.co.jp/ait/articles/1906/19/news022.html)

> また、FargateコンテナにSSHして、内部の情報を確認できるようにするなども予定している

まさにこの機能ですね！！！
早く実現してほしいものですが、それまではこういう方法も便利かも！という記事でした。