Satoshi Tajima

はじめに

AWS Fargate、便利ですよね。

EC2のコンテナインスタンスの管理が不要になり、コンテナの管理だけを気にすればよくなるため、設定の管理やアップデート等の運用の手間が大きく減ります。

また、コンテナインスタンスを管理しないため、コンテナインスタンスにSSHし、docker execすることでコンテナの内部にシェルを起動することができません。これはコンテナインスタンスやコンテナや内で悪意あるプロセスを立ち上げられてしまうというリスクを低減するためにとても有効です。

Fargate運用の難しさ

一方で、この制限は正規の管理者がシェルを立ち上げてトラブルシュートやデバッグをすることもできないという不便さでもあります。

実際に、Fargate上のコンテナにdocker execができないことでこれだけの人々が困っているようです。

How to run “docker exec… ” command in ECS #143
https://github.com/aws/amazon-ecs-cli/issues/143#issuecomment-386106151

このような不便さに対して、現時点でのプラクティスとしては、

  • ECSにデプロイする前に、手元の環境で十分にコンテナの動作確認を行う。
  • ログを十分に出力し、CloudWatch Logsで必要な情報が確認できるようにする。
  • モニタリングエージェントを使って各種メトリクスを十分に取得する。
  • 問題の切り分けがしやすいようにできるかぎりタスクやコンテナを分割する。

などといったやり方があるようです。
このようなやり方だけでは思うような運用ができない等、
どうしてもコンテナ上にシェルを立ち上げたいときは、最終手段として

  • コンテナ内にsshdを立ち上げて、SSH経由でシェルを立ち上げる。

といったことをしているという例もありました。
しかし、sshdを立ち上げてしまうと、そこから不正なプロセスを立ち上げられてしまう可能性がでてきたたり、ユーザーや認証情報をどうやって管理するの?そこで実行されたコマンドをどうやって監査するの?といった問題が出てきてFargateのセキュアさや手軽さが損なわれてしまいます。

同様の課題は、Fargateを利用する時に限らずSSHレスの運用をしようとしているときにも浮上してくることでしょう。(この場合は、条件が合えばSSM AgentのRun CommandやSession Managerを使うこともできますね。)

Postfix on Fargate

今回、とある事情でFargateを使ってPostfixを起動することになりました。
Postfixを運用する際、必要になってくるのが postqueue コマンドや postsuper コマンド等によるメールキューの管理です。
これらのコマンドを使ったオペレーションは、前述のプラクティスでは、sshdを起動する以外の選択肢はなさそうで、どうしたものかと悩んでいました。

shell2http

他にいいやり方はないものかと調べていたところ、こんなものを見つけました。

https://github.com/msoap/shell2http

HTTPサーバとして起動し、予め決められたパスでHTTPのリクエストを受け取ると、決められたコマンドを実行してくれるツールです。

Postfixを起動するコンテナで、このように shell2http を立ち上げておくことで、(完全に思い通りとはいかないものの)SSHすることなくメールキューの操作が行えるようになります。

/bin/shell2http \
	/postqueue   'postqueue -p' \
	/postcat_all 'postcat $(cd /var/spool/postfix/; find incoming active bounce corrupt deferred hold defer flush maildrop saved trace -type f)' &

このように、とても便利なツールではあるのですが、利用にはいくつかの注意が必要です。

OSコマンドインジェクション

ざっと確認したところ今の使い方の範囲内では大丈夫そうなのですが、この手のツールはつくり方や設定によってはOSコマンドインジェクションによって (設定者が意図していない) 任意のコマンドが実行できてしまう可能性があります。

例えば shell2http には、HTTPリクエスト内の任意のパラメータをコマンドに含めることができる機能はあるのですが、それは今回は利用せずに様子をみることにしています。

また、万が一OSコマンドインジェクションが成立してしまった場合の影響を小さくするため、shell2httpを起動するユーザーには注意しましょう。

認証

shell2http は、デフォルトでは特別な認証なくHTTPリクエストさえ送信できればコマンドが実行できる状態で起動します。

SSHの場合は基本的にはパスワードや公開鍵/秘密鍵による認証があるため、その点を比較すると危険であるといえるでしょう。

オプションでBASIC認証をかけることはできます。また、 shell2http 単体では実現できませんが、NginxなどでProxyすることで、クライアント証明書による認証をすることもできるでしょう。

通信内容の暗号化

shell2http は、デフォルトではhttpでの通信となるため、通信の内容は平文になっています。
設定で、SSL/TLSの証明書を指定してhttpsでの通信をすることもできるようなので、センシティブな情報が流れる可能性がある場合には利用しましょう。

リクエスト元の制限

shell2http は、デフォルトではGETリクエストによってコマンドを実行するため、意図せずリクエストが投げられてしまわないように注意する必要があります。
自分で誤ってリクエストしてしまうことがなくとも、クローラー(さすがにインターネットにこのエンドポイントを公開するといったことはしないと思いますが)や、
Webブラウザの暗黙的なリクエストを想定し、リクエスト元を適切に制限しておきましょう。


以上、shell2httpでAWS FargateやSSHレスの運用を少しだけ楽にする話でした。 もし今回のような課題を解決するもっと良さそうなやり方があったら教えてもらえるととても助かります。