IAM の構成を理解する
IAM まわりのリソースは、大きく分けると次の 3 つです。
| 概念 | 役割 |
|---|---|
| Role | AWS サービスが利用する身分 |
| Policy | 許可する権限 |
| Attachment | Role に Policy を紐づけるもの |
つまり、基本的な流れはいつも次のようになります。
Role を作成
→ Policy を作成
→ Policy を Role に Attach
ECS で Role が 2 つ必要になる理由
ECS では、一般的に Role が 2 種類必要になります。
| Role | 用途 |
|---|---|
| execution role | ECS 自体がタスクを起動・実行するため |
| task role | コンテナ内のアプリケーションコードが使うため |
この違いを理解することが一番重要です。
execution role
execution role は、ECS が task を起動するときに使用する Role です。
たとえば、次のような処理で使われます。
- ECR からイメージを pull する
- CloudWatch Logs にログを送信する
- Secrets Manager から secret を取得する
つまり、Secrets Manager から環境変数を読み込むための権限は、この execution role に付与する必要があります。
task role
task role は、コンテナ内部で動いているアプリケーションが使用する Role です。
たとえば、アプリケーションコードから次のような AWS サービスへアクセスする場合に使います。
- S3 へのアクセス
- DynamoDB へのアクセス
- SES によるメール送信
つまり、アプリケーションコード内で S3 SDK を使う場合は、task role に S3 の権限を付与します。
1. ECS Execution Role を作成する
resource "aws_iam_role" "ecs_task_execution" {
name = "${var.project}-ecs-task-execution-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "ecs-tasks.amazonaws.com"
}
Action = "sts:AssumeRole"
}
]
})
}
ここでは、ecs-tasks.amazonaws.com がこの Role を引き受けられるようにしています。
2. ECS Execution 用の基本 Policy を紐づける
ECS の実行に必要な AWS 管理ポリシーを attach します。
resource "aws_iam_role_policy_attachment" "ecs_task_execution" {
role = aws_iam_role.ecs_task_execution.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}
この Policy には、主に次のような権限が含まれています。
- ECR からの image pull
- CloudWatch Logs へのログ送信
ただし、重要なのは次の点です。
Secrets Manager へのアクセス権限は含まれていない
ということです。
3. Secrets Manager にアクセスするための Policy を作成する
Secrets Manager から値を読み取るための権限を、別途作成します。
resource "aws_iam_policy" "ecs_secrets" {
name = "${var.project}-ecs-secrets-policy"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"secretsmanager:GetSecretValue"
]
Resource = [
"arn:aws:secretsmanager:ap-northeast-2:yourIAMnumber:secret:yourapp"
]
}
]
})
}
4. Secrets 用 Policy を Execution Role に紐づける
ここはよく間違えやすいポイントです。
Secrets Manager の権限は、必ず次の Role に付与します。
execution role
resource "aws_iam_role_policy_attachment" "ecs_secrets_attach" {
role = aws_iam_role.ecs_task_execution.name
policy_arn = aws_iam_policy.ecs_secrets.arn
}
もしこの権限を task role に付与してしまうと、次のようなエラーが発生します。
AccessDeniedException:
is not authorized to perform:
secretsmanager:GetSecretValue
なぜなら、ECS が secret を読み込むときに使用する主体は task role ではなく、execution role だからです。
5. Task Role を作成する
次に、アプリケーションコード用の Role を作成します。
resource "aws_iam_role" "ecs_task" {
name = "${var.project}-ecs-task-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "ecs-tasks.amazonaws.com"
}
Action = "sts:AssumeRole"
}
]
})
}
6. アプリケーション用の権限を紐づける
たとえば、アプリケーションコードから S3 にアクセスする必要がある場合は、次のような Policy を作成します。
resource "aws_iam_policy" "ecs_s3_access" {
name = "${var.project}-ecs-s3-access"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"s3:ListBucket"
]
Resource = data.aws_s3_bucket.app.arn
},
{
Effect = "Allow"
Action = [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
]
Resource = "${data.aws_s3_bucket.app.arn}/*"
}
]
})
}
そして、この Policy を task role に attach します。
resource "aws_iam_role_policy_attachment" "ecs_s3_access" {
role = aws_iam_role.ecs_task.name
policy_arn = aws_iam_policy.ecs_s3_access.arn
}
7. ECS Task Definition に Role を設定する
ECS の task definition には、それぞれの Role を設定します。
resource "aws_ecs_task_definition" "app" {
execution_role_arn = aws_iam_role.ecs_task_execution.arn
task_role_arn = aws_iam_role.ecs_task.arn
}
それぞれの意味は次のとおりです。
| フィールド | 役割 |
|---|---|
| execution_role_arn | ECS が task を実行するための Role |
| task_role_arn | アプリケーションコードが使用する Role |
8. Secrets Manager の値を環境変数として設定する
Secrets Manager の値を ECS の環境変数として注入します。
locals {
secret_keys = [
"DATABASE_URL",
"AUTH_SECRET",
"AUTH_GOOGLE_ID"
]
}
secrets = [
for key in local.secret_keys : {
name = key
valueFrom = "${var.secrets_arn}:${key}::"
}
]
Secrets Manager 側の値は、JSON 形式になっている必要があります。
{
"DATABASE_URL": "...",
"AUTH_SECRET": "...",
"AUTH_GOOGLE_ID": "..."
}
最終的な構成
最終的な構成は、次のようになります。
ECS Task
├─ execution role
│ ├─ AmazonECSTaskExecutionRolePolicy
│ └─ SecretsManager access
│
└─ task role
└─ S3 access
重要なのは、次の切り分けです。
Secrets Manager の権限は execution role
アプリケーションの業務ロジックで使う権限は task role