Skip to content

Instantly share code, notes, and snippets.

@jnbdz
Created March 20, 2026 17:37
Show Gist options
  • Select an option

  • Save jnbdz/16063aa844d3f1a9025c2ecd7def1912 to your computer and use it in GitHub Desktop.

Select an option

Save jnbdz/16063aa844d3f1a9025c2ecd7def1912 to your computer and use it in GitHub Desktop.
locals {
prefix = "${var.project_name}-${var.environment}"
}
# ──────────────────────────────────────────────
# ECS Task Execution Role
# Used by the ECS control plane to pull images
# and write logs — NOT your application code.
# ──────────────────────────────────────────────
resource "aws_iam_role" "ecs_execution" {
name = "${local.prefix}-ecs-execution-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "ecs-tasks.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_role_policy_attachment" "ecs_execution_managed" {
role = aws_iam_role.ecs_execution.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}
# ──────────────────────────────────────────────
# ECS Task Role
# This is what your Python code runs as.
# Vault uses AWS IAM auth — this role is what
# hvac presents to Vault to authenticate.
# ──────────────────────────────────────────────
resource "aws_iam_role" "ecs_task" {
name = "${local.prefix}-ecs-task-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "ecs-tasks.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}
# Vault IAM auth requires sts:GetCallerIdentity on the task role
resource "aws_iam_role_policy" "ecs_task_vault_auth" {
name = "${local.prefix}-vault-iam-auth"
role = aws_iam_role.ecs_task.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "sts:GetCallerIdentity"
Resource = "*"
}]
})
}
# Add any extra AWS permissions your scripts need here
# e.g. S3, SQS, DynamoDB, etc.
# resource "aws_iam_role_policy" "ecs_task_s3" { ... }
# ──────────────────────────────────────────────
# Step Functions Execution Role
# Allows Step Functions to start ECS tasks
# and write logs/traces.
# ──────────────────────────────────────────────
resource "aws_iam_role" "sfn" {
name = "${local.prefix}-sfn-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "states.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_role_policy" "sfn_ecs" {
name = "${local.prefix}-sfn-ecs-policy"
role = aws_iam_role.sfn.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
# Run and describe ECS tasks
Effect = "Allow"
Action = [
"ecs:RunTask",
"ecs:StopTask",
"ecs:DescribeTasks",
]
Resource = "*"
},
{
# Required for .sync:2 — Step Functions polls via EventBridge
Effect = "Allow"
Action = [
"events:PutTargets",
"events:PutRule",
"events:DescribeRule",
]
Resource = "arn:aws:events:${var.aws_region}:*:rule/StepFunctionsGetEventsForECSTaskRule"
},
{
# Pass the task and execution roles to ECS
Effect = "Allow"
Action = "iam:PassRole"
Resource = [
aws_iam_role.ecs_execution.arn,
aws_iam_role.ecs_task.arn,
]
},
{
# CloudWatch logging for the state machine
Effect = "Allow"
Action = [
"logs:CreateLogDelivery",
"logs:GetLogDelivery",
"logs:UpdateLogDelivery",
"logs:DeleteLogDelivery",
"logs:ListLogDeliveries",
"logs:PutResourcePolicy",
"logs:DescribeResourcePolicies",
"logs:DescribeLogGroups",
]
Resource = "*"
}
]
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment