Amazon Web Services ブログ

New – Amazon ECS Exec による AWS Fargate, Amazon EC2 上のコンテナへのアクセス

この記事は、 NEW – Using Amazon ECS Exec to access your containers on AWS Fargate and Amazon EC2 を翻訳したものです。

本日、開発者、運用者を含むすべての Amazon ECS ユーザに向けて、 Amazon EC2 もしくは AWS Fargate にデプロイされたタスク内のコンテナに “Exec” する機能を発表しました。この新しい機能は、 ECS Exec と名付けられ、コンテナに対して対話型のシェル、あるいは一つのコマンドを実行できるようになります。これは AWS コンテナロードマップ上で最も要望の多かった機能の一つであり、一般公開できることを大変嬉しく思います。

ユーザが個々のコンテナに SSH 接続すべきでなく、監視やデバッグ、ログ分析のために適切な可観測性の仕組みを導入することは、コンテナ利用においてよく知られるセキュリティのベストプラクティスです。この発表は、ベストプラクティスを変更することなく、アプリケーションのセキュリティを改善するのに役立ちます。アプリケーション開発サイクルの初期段階においては、迅速なフィードバックループを回す必要がある場面がしばしばあります。例えば、あなたがローカル環境で開発とテストを行っていて、 docker exec を利用している場合、この新しい ECS の機能はきっと役に立つでしょう。またこの機能は、本番環境で重要度の高い問題をデバッグするために、コンテナへの “緊急用アクセス” が必要になる場合にも役立ちます。ここで、コンテナに対して “Exec” する時に利用できるツールと機能は、コンテナ内にインストールされているもののみであることに注意が必要です。つまり、例えば netstatheapdump コマンドがコンテナのベースイメージにインストールされていない場合、それらを使用することはできません。

この機能をアナウンスするまでは、 ECS ユーザが EC2 上にデプロイしたタスクのトラブルシュートを行うためには、下記の手順が必要でした。

  • EC2 インスタンスへの SSH アクセスの許可
    • これを実現するためにはポート開放、鍵もしくはパスワードの配布、その他の作業など多大な苦労が必要でした
  • タスクがデプロイされた EC2 インスタンスのクラスター内での特定
  • EC2 インスタンスへの SSH 接続
  • コンテナに対するトラブルシュートのための docker exec

EC2 インスタンスで実行されているコンテナへの単純な作業の割に、セキュリティベストプラクティスに反する多くの作業が必要でした。

さらに、 Fargate の場合は SSH 接続できる EC2 インスタンスがないため、 Fargate にタスクをデプロイする ECS ユーザはこの選択肢を取れませんでした。つまり、 ECS on Fargate ではコンテナに docker exec することはできませんでした。お客様が取りうる選択肢の一つは、タスクを EC2 に再デプロイして docker exec するか、 IDE によるクラウドデバッグを使用できるようにすることでした。

ECS Exec は、 AWS SDK , AWS CLI および AWS Copilot を介してサポートされています。将来的には、 AWS コンソールからご利用いただけるようにする予定です。また、この機能は Linux コンテナのみをサポートします (ECS Exec での Windows コンテナサポートは、この発表に含まれません) 。

この投稿の次のパートでは、この機能の中心となるいくつかの部分について詳しく説明します。これらには、 ECS Exec の動作の概要、前提条件、セキュリティ上の考慮事項などが含まれます。投稿の最後のセクションでは、 nginx コンテナへ直接シェルアクセスする方法を示す例を紹介します。

ウォークスルーでは、 AWS CLI のエクスペリエンスにフォーカスします。AWS Copilot でこの機能を活用する方法については、 こちらのドキュメントを参照してください。

ECS Exec がどのように動作するのか

ECS Exec は、 AWS Systems Manager (SSM) の、特に SSM Session Manager の機能を活用して、利用者のデバイスからターゲットのコンテナに “exec” コマンドを実行するセキュアなチャンネルを作ります。エンジニアリングチームは Github での Proposal にてこれらの機能がどのように動くのか、一部の詳細を公開しています。簡単にまとめると、必要な SSM エージェントのバイナリをコンテナにバインドマウントします。そして、 ECS エージェント (もしくは Fargate エージェント) は、アプリケーションコードと一緒にコンテナ内で SSM コアエージェントを起動する役割を持ちます。重要な点は、この動作が AWS によって完全に管理され。ユーザに対して透過的であることです。つまり、ユーザは SSM バイナリがバインドマウントされ、コンテナ内で起動していることを意識する必要がありません。ユーザは、 Dockerfile で定義されたアプリケーションプロセスにのみ注意を払えば良いのです。

最初のリリースでは、 ECS Exec はコンテナに対する対話型なセッション (docker exec -it と同等) を実行する機能を提供します。近い将来、 ECS Exec はコンテナに対する非対話型コマンドの送信 (docker exec -t と同等) もサポートできるようになる予定です。

この機能には、セッションの両側に SSM 機能が必要であるため、デプロイや設定の内容に応じてユーザが前提条件として設定するべきものがいくつかあります。次の「前提条件」のセクションで説明します。

ECS Exec のための前提条件

先に述べたとおり、この機能は AWS SSM の機能を活用しています。そのため、この機能を利用するためにはいくつかの適切な SSM の設定が必要です。これは、接続元(ラップトップなど)と、接続先のエンドポイント(コンテナが起動している EC2 や Fargate) の両方に当てはまります。

クライアントサイドでの前提条件

もし exec コマンドを実行するために AWS CLI を利用するなら、 AWS CLI 用の Session Manager plugin をインストールする必要があります。手順に従って、利用しているプラットフォーム (Linux, Mac, Windows) に合うバイナリをセットアップします。現在、 AWS CLI v1 は更新され、この機能が含まれるようになりました。 AWS CLI v2 は今後数週間で更新される予定です。なお、 AWS CLI v1 を利用可能な最新バージョンにアップグレードすることも忘れないでください。このバージョンには、 ECS Exec 用の追加機能と、 Session Manager plugin をフックしてコンテナへの安全な接続を提供する機能が含まれています。

サーバーサイドでの前提条件 (Amazon EC2)

Proposal で説明されているとおり、この機能は exec 対象のコンテナが実行されているホストで、必要な SSM コンポーネントが利用可能であることを前提としています (前述したとおり該当のコンテナにバイナリをバインドマウントします) 。

もし ECS optimized AMI を利用する場合は、最新のバージョンでは必要な SSM コンポーネントが既に含まれているため、何かをする必要はありません。 最初のリリースでは、お客様がこの前提条件を独自の AMI で達成する方法は提供されません。ローンチ後に、その柔軟性を持たせることを計画しています。

サーバーサイドでの前提条件 (AWS Fargate)

ECS のタスクとコンテナが Fargate 上で動いている場合、この ECS の機能を利用するための前提条件が Fargate に含まれているため、何かをする必要はありません。 Fargate のソフトウェアスタックがプラットフォーム バージョンとして管理されているため (入門書が必要な場合はこちらのブログを確認してください) であり、利用者は PV 1.4 を選択するだけでこの機能を利用できます (最新のバージョンで、 ECS Exec の前提条件を満たします)。

ECS Exec のためのインフラストラクチャの構成

ここまでで、前提条件について述べてきました。次はこの機能を実行するためにインフラストラクチャに対して必要な設定について確認します。

ロギングオプションの設定 (オプショナル)

ECS Exec は、対話型のターミナル (ラップトップや AWS Cloudshell, AWS Cloud9 など) へのセッションのログ記録に加えて、コマンドとその出力のログ記録をサポートしています。 出力先は下記のいずれか、もしくは両方です。

これは、アーカイブや監査を目的としたコマンド自体の AWS CloudTrail への記録とともに実行されます。

コマンドが /bin/bash などのシェルを呼び出すと、コンテナへの対話型のアクセスが得られます。その場合、シェルセッション内の全てのコマンドとその出力は、 S3 または CloudWatch 、もしくはその両方に記録されます。シェルの呼び出しコマンドそのものは、実行したユーザの情報とともに ECS ExecuteCommand API コールの一部として、 AWS CloudTrail に監査を目的に記録されます。

一方で、コマンドが pwd などの単一のコマンドを呼び出す場合、S3 または CloudWatch 、もしくはその両方に記録されます。シェルの呼び出しコマンドそのものは ECS ExecuteCommand API コールの一部として AWS CloudTrail に記録されます。このケースにおける監査では、ログのエントリを AWS CloudTrail 内の対応する API コールと関連付けるために、追加の手順が必要になります。将来的にはこの操作を簡素化する予定です。

コマンドログを S3 や CloudWatch に正しくアップロードするには、コンテナイメージで script (util-linux の一部) と cat (coreutils の一部) をインストールする必要があります。このブログの最後にあるウォークスルーでは、これらが既にインストールされている nginx のコンテナイメージを使用します。イメージイメージ内に、必要なツールがインストールされていることを確認しましょう。

これらのロギングオプションは ECS のクラスターレベルで設定されます。最新の AWS CLI では、--configuration という新しい (オプショナルな) フラグをサポートし、 create-clusterupdate-cluster コマンドで設定を定義できます。このブログの最後のウォークスルーでは、 create-cluster の例を示しますが、事前に executeCommandConfiguration という新しい構文の外観を示します。

executeCommandConfiguration={kmsKeyId=string,\
                            logging=string,\
                            logConfiguration={cloudWatchLogGroupName=string,\
                                            cloudWatchEncryptionEnabled=boolean,\
                                            s3BucketName=string,\
                                            s3EncryptionEnabled=boolean,\
                                            s3KeyPrefix=string}}

この logging 変数が、 ECS Exec ロギング機能の動作を決定します。

  • NONE: ロギングは無効
  • DEFAULT: ログは awslogs ドライバーとして定義 (ドライバーが未設定の場合はログは保管されない)
  • OVERRIDE: ログは CloudWatch ロググループと S3 バケットのいずれか、もしくは両方に出力

この新しいフラグの詳細の説明については、 AWS CLI のドキュメントを確認してください。

exec セッションの出力のログへの記録について言及している点に注意してください。これは、コンテナ上のアプリケーションのロギングとは何の関係もありません。アプリケーションは一般的に、 stdout もしくはログファイルにログを出力するよう構成されており、このログは、この投稿で説明している exec コマンドのログとは異なります。

適切な IAM ポリシーのためのタスクロールの設定

コンテナは、 SSM コアエージェントを (アプリケーションと一緒に) 実行します。このエージェントが実行されると、セキュアチャンネルを作成するために SSM サービスを呼び出します。つまり、 ECS タスクは SSM エージェントが SSM サービスを呼び出すための適切な IAM 権限を必要とします。これは、 ECS タスクロールに対して適切な IAM 権限を適用することで実現できます。

明確にしておくと、 SSM エージェントはサイドカーコンテナとして実行されません。 SSM エージェントはアプリケーションコンテナの追加のプロセスとして実行されます。詳細は、 Github Issue 内の Proposal に記載されています。

さらに言うと、クラスターで ECS Exec のロギングオプションの設定がなされた場合、タスクロールは S3 や CloudWatch にログを出力するための IAM 権限を必要とします。もし設定がなされなかった場合、上述の IAM 権限は必要とされません。

この投稿の最後にある実用的なウォークスルーには、この例もあります。

ECS Exec でのセキュリティと監査に関する設定

ここまでで、前提条件とインフラストラクチャの構成について説明しました。次に、 新しい ECS Exec 機能に関するセキュリティ制御とコンプライアンスのサポートについて説明します。

IAM によるセキュリティの制御

セキュリティはネイティブに統合され、 IAM ユーザ、 IAM グループ、 IAM ロールなどのプリンシパルに割り当てられる IAM ポリシーにてコマンドの実行権限を設定可能です。

この制御は、 新しい ecs:ExecuteCommand という IAM アクションによって管理します。ユーザ権限は、クラスターレベルから、特定の ECS タスク内の特定のコンテナという細かい範囲にまで絞り込めます。タスクのデプロイメントは非常に動的であるため、ユーザは特定のタスクに依存するポリシーを定義することはできません。その代わりに、タスクへのタグの割り当てと、 IAM ポリシーでのタグコンディションの定義を推奨します。 ecs:ResourceTag/tag-key と、 aws:ResourceTag/tag-key の 2 つのコンディションキーがサポートされることに注意してください。アクセスを制限するスコープダウンポリシーの例を下記に示します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecs:ExecuteCommand"
            ],
            "Condition": {
                "StringEquals": {
                    "aws:ResourceTag/tag-key": "tag-value"",
                    "StringEquals": {
                        "ecs:container-name": "<container_name>"
                    }
                }
            },
            "Resource":"arn:aws:ecs:<region>:<aws_account_id>:cluster/<cluster_name>"
        }
    ]
}

このポリシーでは、特定のクラスター内の特定の名前のコンテナでの exec の実行を許可しています。加えて、前述の通りタグを使ったポリシー条件を使用することもできます。

将来、非対話型のコマンドのサポートがローンチされるときに、許可される対話型のタイプを制限するためのコントロールも提供します (例えば、あるユーザは非対話型のコマンドのみを実行でき、その他のユーザは対話型と非対話型の両方を実行できる、などです)。

セキュリティと監査

最初に述べたとおり、個々のタスクに SSH 接続することはアンチパターンとされており、考慮事項が増える要因となります。特に制限の厳しい環境においてはその傾向は顕著です。これが、 ECS Exec が IAM で厳しく制御され、全てのリクエストが監査目的で AWS CloudTrail にロギングされる理由です。

AWS API コールのみが (呼び出されたコマンドと共に) ログに記録されることを理解することが重要です。たとえば、対話的なセッションを開くと、 CloudTrail ログには /bin/bash のみが記録され、シェル内のその他のコマンドは記録されません。しかしながら、クラスターの設定によってシェル内で実行されたコマンドは CloudWatch、S3 のいずれかまたは両方に記録されます。

以下のウォークスルーにはこのシナリオの例があります。

データチャネルの暗号化

クライアント端末とコンテナの間で使われるコネクションは、デフォルトで TLS1.2 を使って暗号化されます。また、独自の AWS Key Management Service (KMS) の鍵を使って暗号化することも可能です。 ECS クラスターの設定では、オプション設定でのカスタマーキーの指定をサポートします。定義された場合、指定されたキーを使って暗号化が行われます。最終的に、 ECS Exec では SSM のコア機能 を活用しています。

AWS CLI を使った ECS Exec の実行

ここまでで、理論について説明しました。それでは、実際の例をみてみましょう。次のウォークスルーでは、 Fargate 上で動くタスクの一部として実行されている nginx コンテナのインタラクティブシェルを取得する方法を示します。この例は実際のトラブルシューティングシナリオを模する目的ではなく、機能そのものにフォーカスを当てています。これらのコアトラブルシューティング機能が必要となる充分な機会やシナリオがカバーできていると確信しています?

まず最初に、先に述べた “クライアントサイドの前提条件” が満たされていることを確認してください。 AWS CLI の最新バージョンが使用され、 AWS CLI 用の Session Manager plugin がインストールされている必要があります。

次に、タスクをまっさらな状態からデプロイします。既に ECS の経験が深い利用者は、既存のタスクや IAM ロールに対して下記に示す ECS Exec の特定の設定を投入することも可能です。もし AWS Copilot CLI の利用者で AWS CLI のウォークスルーに興味を持たない場合、 Copilot のドキュメントを参照してください。また、この機能は将来的に Amazon ECS の AWS マネジメントコンソール上から実行できるようにする予定です。

ここでは、これ以降のステップを実行できるよう、適切な権限が付与されたプリンシパルの認証情報が AWS CLI に設定されています。

まず最初に、空のフォルダを作成してそこに移動しましょう。また、後ほど利用するいくつかの変数を定義します。変数には、リージョン、 VPC 、そして VPC に含まれる 2 つのパブリックサブネットが含まれます。また、バケットネームはユニークな名前を指定する必要があるので、下記のようにランダムな文字列をバケット名に含みましょう (この例では、 ecs-exec-demo-output-3637495736 を使用しています)。

export AWS_REGION=<xxxxxxx>
export VPC_ID=<vpc-xxxx>
export PUBLIC_SUBNET1=<subnet-xxxxx>
export PUBLIC_SUBNET2=<subnet-xxxxx>
export ECS_EXEC_BUCKET_NAME=ecs-exec-demo-output-xxxxxxxxxx

ECS タスクロールと、 ECS タスク実行ロールを定義するための前提条件として、 IAM ポリシーを作成する必要があります。 ecs-tasks-trust-policy.json という名前のファイルを作成し、下記の内容を記述します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "ecs-tasks.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

これで、 AWS のリソースを作成する準備が整いました。また、下記に示す前提条件は後ほど定義され、その後 ECS タスクが実行されます。

  • ECS Exec のデータチャネルを暗号化するための KMS キー
  • ECS クラスター
  • CloudWatch ロググループ
    • このロググループは 2 つのログストリームを有します、 1 つはコンテナの stdout のため、もう一つは ECS Exec のログを出力するためです
  • ECS Exec のログを出力するための S3 バケット (必要に応じてプレフィックスを指定)
  • nginx コンテナの 80 番ポートへのリクエストを許可するためのセキュリティグループ
  • ECS タスクロールと ECS タスク実行ロールのための 2 つの IAM ロール

下記に、上述したリソースを作成する AWS CLI コマンドを示します。 ecs create-cluster コマンドを実行する際の新しいオプションである、 --configuration executeCommandConfiguration に注意してください。

KMS_KEY=$(aws kms create-key --region $AWS_REGION)
KMS_KEY_ARN=$(echo $KMS_KEY | jq --raw-output .KeyMetadata.Arn)
aws kms create-alias --alias-name alias/ecs-exec-demo-kms-key --target-key-id $KMS_KEY_ARN --region $AWS_REGION
echo "The KMS Key ARN is: "$KMS_KEY_ARN 

aws ecs create-cluster \
    --cluster-name ecs-exec-demo-cluster \
    --region $AWS_REGION \
    --configuration executeCommandConfiguration="{logging=OVERRIDE,\
                                                kmsKeyId=$KMS_KEY_ARN,\
                                                logConfiguration={cloudWatchLogGroupName="/aws/ecs/ecs-exec-demo",\
                                                                s3BucketName=$ECS_EXEC_BUCKET_NAME,\
                                                                s3KeyPrefix=exec-output}}"

aws logs create-log-group --log-group-name /aws/ecs/ecs-exec-demo --region $AWS_REGION

aws s3api create-bucket --bucket $ECS_EXEC_BUCKET_NAME --region $AWS_REGION --create-bucket-configuration LocationConstraint=$AWS_REGION 

ECS_EXEC_DEMO_SG=$(aws ec2 create-security-group --group-name ecs-exec-demo-SG --description "ECS exec demo SG" --vpc-id $VPC_ID --region $AWS_REGION) 
ECS_EXEC_DEMO_SG_ID=$(echo $ECS_EXEC_DEMO_SG | jq --raw-output .GroupId)
aws ec2 authorize-security-group-ingress --group-id $ECS_EXEC_DEMO_SG_ID --protocol tcp --port 80 --cidr 0.0.0.0/0 --region $AWS_REGION 
  
aws iam create-role --role-name ecs-exec-demo-task-execution-role --assume-role-policy-document file://ecs-tasks-trust-policy.json --region $AWS_REGION
aws iam create-role --role-name ecs-exec-demo-task-role --assume-role-policy-document file://ecs-tasks-trust-policy.json --region $AWS_REGION

この時点では、 2 つの IAM ロールにポリシーはアサインされていません。そのため、下記を実行する必要があります。

  • ECS タスク実行ロールに、すでに AWS 管理ポリシーとして存在する AmazonECSTaskExecutionRolePolicy をアタッチします
  • ECS タスクロールに、コンテナが SSM を経由してセキュリティ保護済みのセッションをオープンし、 ECS Exec が CloudWatch もしくは S3 (それぞれ上記で作成されたログストリーム、バケット) にログを出力することを許可するポリシーを作成、アタッチします

ecs-exec-demo-task-role-policy.json というファイルを作成し、下記の項目を適切な内容に修正して追記します。

  • <AWS_REGION>
  • <ACCOUNT_ID>
  • <ECS_EXEC_BUCKET_NAME> (ECS_EXEC_BUCKET_NAME 変数に含まれます)
  • <KMS_KEY_ARN> (KMS_KEY_ARN 変数に含まれます)
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssmmessages:CreateControlChannel",
                "ssmmessages:CreateDataChannel",
                "ssmmessages:OpenControlChannel",
                "ssmmessages:OpenDataChannel"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:DescribeLogGroups"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:DescribeLogStreams",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:<AWS_REGION>:<ACCOUNT_ID>:log-group:/aws/ecs/ecs-exec-demo:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::<ECS_EXEC_BUCKET_NAME>/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetEncryptionConfiguration"
            ],
            "Resource": "arn:aws:s3:::<ECS_EXEC_BUCKET_NAME>"
        },
        {
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": "<KMS_KEY_ARN>"
        }
    ]
}

これらの IAM 権限は、 (ECS タスク実行ロールレベルではなく) ECS タスクロールレベルで指定する必要がある点に注意してください。これは、 SSM コアエージェントがアプリケーションと同じコンテナ内で実行されるためです。他の AWS サービスに対して、これらのアクションを実行するのはコンテナ自体なので、 IAM 権限を付与する必要があります。

上記の IAM ポリシーは、実際のアプリケーションが動作するために他に必要となる IAM ポリシーと一緒に設定する必要がある点も、理解しておいてください。例えば、コンテナ内で動くアプリケーションが Amazon DynamoDB からデータを読み取る場合、 ECS タスクロールには、 ECS Exec を正しく動作させるための IAM ポリシーに加えて、 DynamoDB テーブルを読み取ることを許可する IAM ポリシーが必要です。

下記のとおり、 AWS CLI コマンドを実行して、ポリシーを IAM ロールに割り当てます。

aws iam attach-role-policy \
    --role-name ecs-exec-demo-task-execution-role \
    --policy-arn "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
    
aws iam put-role-policy \
    --role-name ecs-exec-demo-task-role \
    --policy-name ecs-exec-demo-task-role-policy \
    --policy-document file://ecs-exec-demo-task-role-policy.json

これで、 ECS タスク定義を登録する準備ができました。 ecs-exec-demo.json ファイルを作成し、下記の項目を修正してください。

  • <ACCOUNT_ID>
  • <AWS_REGION>
{"family": "ecs-exec-demo",
    "networkMode": "awsvpc",
    "executionRoleArn": "arn:aws:iam::<ACCOUNT_ID>:role/ecs-exec-demo-task-execution-role",
    "taskRoleArn": "arn:aws:iam::<ACCOUNT_ID>:role/ecs-exec-demo-task-role",
    "containerDefinitions": [
        {"name": "nginx",
            "image": "nginx",
            "linuxParameters": {
                "initProcessEnabled": true
            },            
            "logConfiguration": {
                "logDriver": "awslogs",
                    "options": {
                       "awslogs-group": "/aws/ecs/ecs-exec-demo",
                       "awslogs-region": "<AWS_REGION>",
                       "awslogs-stream-prefix": "container-stdout"
                    }
            }
        }
    ],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "256",
    "memory": "512"
}

タスク定義に新しい機能である ECS Exec に関する設定が含まれていないことに注意してください。これによって、既存のタスク定義を修正を加えることなく引き続き使用できます。ベストプラクティスとして、 SSM エージェントの子プロセスが孤立しないように initProcessEnabled パラメーターを true に設定することをお勧めします。ただし、これは必須ではありません。

次のコマンドは、上記で作成したファイルを使ってタスク定義を登録します。

aws ecs register-task-definition \
    --cli-input-json file://ecs-exec-demo.json \
    --region $AWS_REGION

これで、 Fargate タスクを実行できます!これまでのコマンドで定義したいくつかの環境変数を使用します。それらが適切に設定されていることを確認してください。また、 run-task コマンドでは、 --enable-execute-command オプションを使用して、この新しい機能に明示的にオプトインする必要がある点に注意してください。これにより、 ECS エージェントと Fargate エージェントは、 SSM エージェントをバインドマウントし、アプリケーションと一緒に実行します。また、 ECS サービスにおいても同様に、 create-service コマンドで --enable-execute-command フラグを指定することでこの機能を利用できます。 --enable-execute-command フラグを指定することなくタスクをデプロイした、もしくはサービスを起動した場合は、タスクを再デプロイする (run-task) か、サービスをアップデート (update-service) することで、コンテナへの exec 機能にオプトインすることができます。

aws ecs run-task \
    --cluster ecs-exec-demo-cluster  \
    --task-definition ecs-exec-demo \
    --network-configuration awsvpcConfiguration="{subnets=[$PUBLIC_SUBNET1, $PUBLIC_SUBNET2],securityGroups=[$ECS_EXEC_DEMO_SG_ID],assignPublicIp=ENABLED}" \
    --enable-execute-command \
    --launch-type FARGATE \
    --tags key=environment,value=production \
    --platform-version '1.4.0' \
    --region $AWS_REGION

run-task コマンドはタスクの詳細を返却するため、タスクの id を確認できます。出力から、 taskArn を探してみてください。タスクの id は、 ARN の末尾に表示されています。

"taskArn": "arn:aws:ecs:AWS_REGION:ACCOUNT_ID:task/ecs-exec-demo-cluster/*ef6260ed8aab49cf926667ab0c52c313*"

また、特定のキーペアで、タスクにタグを付与することがある点に注意してください。今回はこれを利用しませんが、必要に応じて、タグを使用して IAM による制御の条件を作成できます。

タスクが RUNNING 状態に正常に移行されたことを確認するため、 task id を使ってタスクをクエリします (run-task コマンドから取得した id を使用しています)。

aws ecs describe-tasks \
    --cluster ecs-exec-demo-cluster \
    --region $AWS_REGION \
    --tasks ef6260ed8aab49cf926667ab0c52c313

タスクステータスの “ExecuteCommandAgent” が、 RUNNING であり、 “enableExecuteCommand” に true が設定されていることを確認します。

機能が有効化されており、必要な権限が設定されていれば、 exec を使ってコマンドに入る準備が整った状態になります。

このウォークスルーでは、これまで使用してきた Administration ポリシーを、 IAM ロールで引き続き使用します。ただし、コンテナへの “exec” は ecs:ExecuteCommand という新しい IAM アクションによって管理され、そのアクションはタグの conditions と一緒に制御できることを理解してください。

さて、シェルを起動するコマンドを実行しましょう。

aws ecs execute-command  \
    --region $AWS_REGION \
    --cluster ecs-exec-demo-cluster \
    --task ef6260ed8aab49cf926667ab0c52c313 \
    --container nginx \
    --command "/bin/bash" \
    --interactive

The Session Manager plugin was installed successfully. Use the AWS CLI to start a session.


Starting session with SessionId: ecs-execute-command-0122b68a67f39258e
This session is encrypted using AWS KMS.
root@ip-172-31-32-237:/# hostname
ip-172-31-32-237.ap-southeast-1.compute.internal
root@ip-172-31-32-237:/#
root@ip-172-31-32-237:/# ls
bin   dev                  docker-entrypoint.sh  home  lib64           media  opt   root  sbin  sys  usr
boot  docker-entrypoint.d  etc                   lib   managed-agents  mnt    proc  run   srv   tmp  var
root@ip-172-31-32-237:/#
root@ip-172-31-32-237:/# echo "This page has been created with ECS Exec" > /usr/share/nginx/html/index.html
root@ip-172-31-32-237:/#
root@ip-172-31-32-237:/# exit
exit


Exiting session with sessionId: ecs-execute-command-0122b68a67f39258e.

上記のコマンドが --container パラメータを含んでいることに注意してください。タスクが 1 つのコンテナを実行する場合、このフラグはオプショナルです。しかしながら、タスクが複数のコンテナを実行する場合は、必須の設定となります。

ご覧の通り、 Fargate 上で動くコンテナに対してシェルを実行し、対話できることを確認しました。そこでは、 hostnamels の実行、また nginx が出力するページ (index.html ファイル) への “This page has been created with ECS Exec” という内容の書き込みを試しました。タスクはパブリック IP アドレスを持っているため、 curl コマンドを使って変更されたページが参照できるか確認します。

$ curl http://13.212.126.134/
This page has been created with ECS Exec
$

念のため述べておくと、 ECS Exec はコンテナ内にインストールされて利用可能なツールと機能のみを使用できます。

次の例に示す様に、シェルを取得する代わりに、単一のコマンドを呼び出すこともできます。この例では、 ls を使用してコンテナのルートディレクトリのコンテンツを一覧表示しています。

aws ecs execute-command  \
    --region $AWS_REGION \
    --cluster ecs-exec-demo-cluster \
    --task 1234567890123456789 \
    --container nginx \
    --command "ls" \
    --interactive

The Session Manager plugin was installed successfully. Use the AWS CLI to start a session.


Starting session with SessionId: ecs-execute-command-00167f6ecbc18ee7e
bin   docker-entrypoint.d   home   managed-agents  opt   run   sys  var
boot  docker-entrypoint.sh  lib    media           proc  sbin  tmp
dev   etc                   lib64  mnt             root  srv   usr


Exiting session with sessionId: ecs-execute-command-00167f6ecbc18ee7e.

この ls コマンドは、 AWS CloudTrail によって記録された ExecuteCommand API コールのペイロードの一部です。sessionIdcommand は、 CloudTrail ログコンテンツから抽出されています。 sessionId は、様々なタイムスタンプのイベントを相関分析するのに役立ちます。

     "requestParameters": {
        "cluster": "ecs-exec-demo-cluster",
        "container": "nginx",
        "command": "ls",
        "interactive": true,
        "task": "3b3b695a6d104ef5ae31fdb596f27429"
    },
    "responseElements": {
        "clusterArn": "arn:aws:ecs:ap-southeast-1:123456789012:cluster/ecs-exec-demo-cluster",
        "containerArn": "arn:aws:ecs:ap-southeast-1:123456789012:container/6c5790cb-7b68-4bab-9b12-aa6e880e00fa",
        "containerName": "nginx",
        "interactive": true,
        "session": {
            "sessionId": "ecs-execute-command-00167f6ecbc18ee7e",
            "streamUrl": "wss://ssmmessages.ap-southeast-1.amazonaws.com/v1/data-channel/ecs-execute-command-00167f6ecbc18ee7e?role=publish_subscribe",
            "tokenValue": "HIDDEN_DUE_TO_SECURITY_REASONS"
        },
        "taskArn": "arn:aws:ecs:ap-southeast-1:123456789012:task/ecs-exec-demo-cluster/3b3b695a6d104ef5ae31fdb596f27429"
    },

これは、同じ ls コマンドで S3 バケットに記録された出力です。これは、同じ ls コマンドで CloudWatch ログストリームに記録された出力です。

ヒント: S3 や CloudWatch にコマンドの出力を 記録する際に問題が発生した場合は、 IAM ポリシーが正しく構成されていない可能性があります。一般的に、この問題をトラブルシューティングする方法は、コンテナ内の /var/log/amazon/ssm/amazon-ssm-agent.log ファイルの内容を精査することです。

これで、実行中のコンテナでコマンドを実行し、 CloudTrail を使用してコンテナにアクセスしたユーザを監査し、各コマンドを S3 または CloudWatch Logs に出力してログに記録する方法を示すウォークスルーを終了します。

作成したリソースのクリーンアップ

次のコマンドを実行して、ウォークスルー中に作成したリソースを削除します。変数が正しく展開され、正しい ECS タスク ID を使用していることを確認してください。

aws ecs stop-task --cluster ecs-exec-demo-cluster --region $AWS_REGION --task <your task id> 
aws ecs delete-cluster --cluster ecs-exec-demo-cluster --region $AWS_REGION

aws logs delete-log-group --log-group-name /aws/ecs/ecs-exec-demo --region $AWS_REGION

# Be careful running this command. This will delete the bucket we previously created
aws s3 rm s3://$ECS_EXEC_BUCKET_NAME --recursive
aws s3api delete-bucket --bucket $ECS_EXEC_BUCKET_NAME

aws iam detach-role-policy --role-name ecs-exec-demo-task-execution-role --policy-arn "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
aws iam delete-role --role-name ecs-exec-demo-task-execution-role

aws iam delete-role-policy --role-name ecs-exec-demo-task-role --policy-name ecs-exec-demo-task-role-policy
aws iam delete-role --role-name ecs-exec-demo-task-role 

aws kms schedule-key-deletion --key-id $KMS_KEY_ARN --region $AWS_REGION

aws ec2 delete-security-group --group-id $ECS_EXEC_DEMO_SG_ID --region $AWS_REGION

まとめ

この投稿では、リリースされたばかりの ECS Exec の機能について説明しました。この機能は、 ECS ユーザに対して Amazon EC2 あるいは AWS Fargate にデプロイされたコンテナの対話的な操作やデバッグを簡単にするものでした。どのように AWS 上のコンテナ、特に Amazon ECS でのデバッグが簡単になるのかぜひお試しいただき、ご意見をお聞かせください。

パートナーもこれが発表されることを心待ちにしており、一部のパートナーはすでにこの機能のサポートを製品に統合しています。お客様は、 ECS Exec が開発者やオペレーターによって使用されたときに、セキュリティの面で影響を受けないようにするために、監視、アラート、およびレポート機能を必要とする場合があります。詳細については、パートナーからの次の投稿を参照してください。

Aqua: Aqua Supports New Amazon ECS exec Troubleshooting Capability
Datadog: Datadog monitors ECS Exec requests and detects anomalous user activity
SysDig: Running commands securely in containers with Amazon ECS Exec and Sysdig
ThreatStack: Making debugging easier on Fargate
TrendMicro: Cloud One – Conformity Rules Support Amazon ECS Exec

ECS Exec で将来予定されている拡張機能にキャッチアップするため、公式のドキュメントをチェックしておいてください。この機能は、 API, SDK, AWS CLI, AWS Copilot CLI, AWS CloudFormation を介して、全てのパブリックリージョンと中国リージョン、および GovCloud リージョンでお使いいただけます。

翻訳はソリューションアーキテクト石本 (いしもと) が担当しました。