ECSにおける「実行ロール」と「タスクロール」の違いを明確にしてみた

こんにちは。インフラ担当の小林匠です。
みなさん、AWS ECS 使用されていますでしょうか。

AWS ECS (Amazon Elastic Container Service) というのは、AWSサービスの1つであり、コンテナ化されたアプリケーションをより効率的にデプロイ、管理、スケーリングするのに役立つフルマネージド型のコンテナオーケストレーションサービスのことです。

コンテナ技術は言うまでもなく今の現代において必須と言えるツールです。
その特徴として、高速動作で軽量な点から必要最低限の使用するリソースに対して処理ができることや、アプリケーションをパッケージ化することで様々な環境で迅速に起動し、起動し続けることができることが最大のメリットであるといえるでしょう。

特に、ECS を初めて本格的に触ると、多くの人がつまずくポイントの1つがIAMロールです。
ECS に触る上で必要である「タスク実行ロール(Task Execution Role)」と「タスクロール(Task Role)」は、名前も似ており混乱しやすい概念であると思います。

かくいう私も、最近業務でTerraformを使用して、初めてECSを構築する機会がありましたが、

  • 「とりあえずロールをつけたのにエラーが出力される」
  • 「どちらのロールに権限を追加すべきかわからない」
  • 「そもそもこれらのロールについてきちんと説明ができない」

といった状況に何度も遭遇しています。

ということで、今回はECS 初学者の立場から次の2点を中心に、できるだけ噛み砕いて整理していこうと思います。

  • なぜECSには2種類のロールが存在するのか
  • それぞれのロールが「いつ、誰によって」使われるのか

また、本記事において、ECSとIAMロールの概念理解に着目しておりますので、これからECSを触る方や過去に混乱した経験がある方、「この2つのロールについて説明して!」と突然聞かれてもスムーズに回答できないかも・・・という方の参考になれば幸いです。

なぜECSには「2種類のロール」が必要なのか

ECS における最大の前提として、「ECSサービス自身」と「コンテナ内アプリケーション」は別の存在であるという点です。

  • ECSサービス(正確にはECSエージェントやAWSマネージドコンポーネント)
  • タスク内で動作するアプリケーション(コンテナ)

上記2つはAWSへAPIを呼び出すこと自体の主体が異なります。 もし、1つのIAMロールに全ての権限を集約してしまうと、

  • 本来ECS側だけが使うべき権限をアプリが持ってしまう
  • アプリに不要な強い権限を与えてしまう可能性がある

といった最小権限の原則を破ってしまう構成になりがちです。

docs.aws.amazon.com

そこでECSでは、

  • ECSがタスクを起動・管理するためのロール
  • タスク内アプリケーションがAWSサービスにアクセスするためのロール

を明確に分離しています。
これらが「タスク実行ロール」と「タスクロール」です。

IAMロールの責任分離イメージ図

タスク実行ロール(Task Execution Role)

役割の概要

タスク実行ロールは、ECSがタスクを「起動する瞬間」に使用するIAMロールです。(ECSがタスクを起動する準備(コンテナの用意など)に使用する権限) 具体的には、以下のような処理で使われます。

  • ECRからコンテナイメージをpullする
  • CloudWatch Logsにログストリームを作成する
  • 起動時にSecrets Manager / SSM Parameter Store からシークレットを取得する(※ ECSがコンテナを立ち上げる際、定義されたシークレットを「環境変数」として注入するために使用)

ここで重要なのが、このロールはコンテナ内のアプリケーションから直接は使われないという点です。

私の勘違い

初学者(私のこと)がやってしまっていたことが、

CloudWatch Logsにログが1行も出ておらず、コンテナが起動しなかった
→ 必死にタスクロールの方にS3権限やLogs権限を確認しては付け足していた。

という対応です。
しかし、これは間違っていました。

タスク実行ロールはECSが使うロールであり、アプリケーションのAWS SDKがこのロールを使うことはありません。
ログが出力されないということは、実行ロール側に問題がある、という認識の前提が必要でした。
そもそも、タスク実行ロール自体がどんな役割をするかを理解していれば、このような誤った対応はしなかったと思っています。

必要最小限の権限

AWSが公式に用意しているAmazonECSTaskExecutionRolePolicyには

  • ECR認証・イメージ取得
  • CloudWatch Logs出力

といった、起動に必要な最低限の権限が含まれています。

docs.aws.amazon.com

基本的には、このマネージドポリシーと起動時に必要なシークレット取得権限、という構成にしておくと安全であると言えます。

タスク起動時の処理イメージ図

タスクロール(Task Role)

役割の概要

タスクロールは、コンテナ内で動作するアプリケーションが使用するIAMロールです。 (アプリケーションが動くために必要な権限) アプリケーションが以下のようなAWSサービスにアクセスする場合、このロールが使われます。

  • S3
  • DynamoDB
  • SQS / SNS
  • Secrets Manager(実行中の取得)

AWS SDKは、ECSによって自動的に割り当てられたこのロールの一時クレデンシャルを利用します。

アプリ視点での理解

アプリ開発者の視点では、「EC2にIAMロールをアタッチする」こととほぼ同じ感覚で扱うことができます。
基本的な考え方としてはEC2での運用と同等ですが、ECSでは「タスク単位」で個別にロールを割り当てることができます。

これにより、同じ実行基盤上で動く複数のアプリケーションに対して、それぞれが必要な権限だけを厳密に持たせることができるため、よりセキュアで柔軟な権限管理を実現させることができます。

セキュリティ上でのメリット

タスクごとにロールを分離して設定できるため、

  • 同一クラスター内でもタスクごとに権限の変更ができる
  • マイクロサービスごとにIAM権限を最小化できる

アプリ側からAWSサービスへアクセスするイメージ図

通信の流れとロール相関のイメージ

ここまで整理すると、ECSタスクのライフサイクルは大きく2つのフェーズに分かれます。

1.タスク起動フェーズ

  • 使用されるロール:タスク実行ロール
  • 主体:ECS

2.アプリ実行フェーズ

  • 使用されるロール:タスクロール
  • 主体:コンテナ内アプリケーション

この「どのフェーズで、誰がAPIを叩いているのか」を意識すると、ロールの切り分けは一気に理解しやすくなります。

時系列で考える責任ロールが切り替わるイメージ図

Terraformでの設定例

業務でTerraformでAWSリソースを作成しています。 Terraformを利用した場合、ECSのタスク定義では、タスク実行ロールとタスクロールをそれぞれ明示的に指定します。
ここでは、設定時にどの項目がどのロールに対応するのかを確認します。

Terraformでは、ECSのタスク定義において以下2つのパラメータが明示的に分かれています。(以下、サンプルコード)

  • execution_role_arn:タスク実行ロール
# タスク実行ロール
resource "aws_iam_role" "ecs_execution" {
  name = "ecs-execution-role"

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

# タスク実行ロールに AmazonEC2ContainerRegistryReadOnly ポリシーをアタッチ
resource "aws_iam_role_policy_attachment" "ecs_execution_ecr_read_only" {
  role       = aws_iam_role.ecs_execution.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
}

# タスク実行ロールに CloudWatchLogsFullAccess ポリシーをアタッチ(本来はカスタムに権限を絞る方が良いです)
resource "aws_iam_role_policy_attachment" "ecs_execution_cwlogs_full_access" {
  role       = aws_iam_role.ecs_execution.name
  policy_arn = "arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"
}
  • task_role_arn:タスクロール
# タスクロール
resource "aws_iam_role" "ecs_task" {
  name = "ecs-task-role"

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

# タスクロールに AmazonS3ReadOnlyAccess ポリシーをアタッチ
resource "aws_iam_role_policy_attachment" "ecs_task_s3_read_only" {
  role       = aws_iam_role.ecs_task.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
}

# タスクロールに AmazonDynamoDBReadOnlyAccess ポリシーをアタッチ
resource "aws_iam_role_policy_attachment" "ecs_task_dynamodb_read_only" {
  role       = aws_iam_role.ecs_task.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess"
}

registry.terraform.io

これらの名称が示す通り、AWS側の概念を理解した上で、正しいロールを正しい場所に指定する必要があります。
ECS 初学者の段階では、どのIAMロールを作成して、それをどこに関連付けるのかを事前に整理しておくことが重要です。

どちらのロールが原因か見極める方法

権限エラーが発生した場合、以下の切り分けが役に立ちます。

  • タスクが起動しない、またはSTOPPEDになる → タスク実行ロールを疑う

  • タスクは起動するが、アプリ実行中にAccessDeniedが出る → タスクロールを疑う

トラブルシューティング時のイメージ図

CloudWatch Logsのエラーメッセージと、「エラーが出たタイミング(起動時なのか、または実行時か)」をセットで確認することで、原因のロールを特定しやすくなります。
これは、私自身が何度もハマって身についた判断基準です。

まとめ

ECSにおける「タスク実行ロール」と「タスクロール」は、

  • 誰がAPIを呼ぶのか
  • いつ使われるのか

という視点で分けて考えると、非常にシンプルです。

初学者のうちは混乱しやすいポイントですが、この2つを正しく理解することで、

  • 権限設計
  • セキュリティ
  • トラブルシューティング

の精度や調査にかかる工数削減に大きく向上します。

最後に
本記事が、同じように悩んだ経験を持つ方の助けになれば幸いです。

それではまた。