🤖

ECSからAWS CLIでS3へアクセス

2024/07/13に公開

背景

s3へのアクセスをecsから行いたい。
aws configureしなくてもaws cliがecsコンテナ内部から使えるらしいと知ったので試してみた。

設定

こんな感じで、AmazonS3ReadOnlyAccessを付与したecs task execution roleを付与したら行けた.
task_roleとexecution_roleの違いがわからず、若干ハマる...

  • task_role: ecsのコンテナ内で実行するプログラムからアクセスする際の権限.
  • execution_role: ecsコンテナを起動する際の権限.
ecs.tf
resource "aws_ecs_cluster" "cluster" {
  provider = aws.this
  name     = "${local.app_name}-cluster"
}

resource "aws_iam_role" "ecs_task_execution" {
  provider = aws.this
  name     = "${local.app_name}-ecs-task-execution-role"

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

  managed_policy_arns = [
    "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",
  ]
}

resource "aws_iam_role" "ecs_task_inside" {
  provider = aws.this
  name     = "${local.app_name}-ecs-task-inside-role"

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

  managed_policy_arns = [
    "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",
    aws_iam_policy.ecs_s3_access_policy.arn
  ]
}

resource "aws_cloudwatch_log_group" "log_group" {
  provider          = aws.this
  name              = "${local.app_name}-log-group"
  retention_in_days = 7
}

resource "aws_ecs_task_definition" "task" {
  provider           = aws.this
  family             = "${local.app_name}-task"
  requires_compatibilities = ["FARGATE"]
  network_mode       = "awsvpc"
  memory             = "1024"
  cpu                = "512"
  execution_role_arn = aws_iam_role.ecs_task_execution.arn
  task_role_arn      = aws_iam_role.ecs_task_inside.arn

  container_definitions = jsonencode([
    {
      name      = "${local.app_name}-container"
      image     = local.image_url
      essential = true
      memory    = 1024
      cpu       = 512
      portMappings = [
        {
          containerPort = 80
          hostPort      = 80
        }
      ]
      logConfiguration = {
        logDriver = "awslogs"
        options = {
          "awslogs-group"         = aws_cloudwatch_log_group.log_group.name
          "awslogs-region"        = local.region
          "awslogs-stream-prefix" = "ecs"
        }
      }
    }
  ])
}
s3.tf
resource "aws_s3_bucket" "bucket" {
  provider = aws.this
  bucket   = "${local.app_name}-playground"
}

resource "aws_s3_bucket_ownership_controls" "s3_bucket_ownership_controls" {
  provider = aws.this
  bucket   = aws_s3_bucket.bucket.id
  rule {
    object_ownership = "BucketOwnerEnforced"
  }
}

resource "aws_iam_policy" "ecs_s3_access_policy" {
  provider    = aws.this
  name        = "${local.app_name}_ecs_s3_access_policy"
  description = "Allow ECS tasks to access S3"
  policy      = jsonencode({
    Version   = "2012-10-17",
    Statement = [
      {
        Effect = "Allow",
        Action = [
          "s3:GetObject",
          "s3:PutObject",
          "s3:DeleteObject",
          "s3:ListBucket"
        ],
        Resource = [
          "arn:aws:s3:::${aws_s3_bucket.bucket.id}",
          "arn:aws:s3:::${aws_s3_bucket.bucket.id}/*"
        ]
      }
    ]
  })
}

実行

こんな感じで実行確認できた

run.sh
aws ecs run-task \
  --cluster "$CLUSTER" \
  --task-definition "$TASK_ARN" \
  --launch-type FARGATE \
  --network-configuration "awsvpcConfiguration={subnets=[$SUBNETS],securityGroups=[$ECS_ID],assignPublicIp=ENABLED}"

Discussion