Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Terraform
terraform.tfstate
terraform.tfstate.*
.terraform/

16 changes: 16 additions & 0 deletions terraform/aws/ecr.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# -----------------------
# ECR Repository for Backend
# -----------------------
resource "aws_ecr_repository" "backend_repo" {
name = "devops-backend"
image_tag_mutability = "MUTABLE"

image_scanning_configuration {
scan_on_push = true
}

tags = {
Name = "devops-backend-repo"
}
}

61 changes: 61 additions & 0 deletions terraform/aws/ecs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# -----------------------
# ECS Cluster
# -----------------------
resource "aws_ecs_cluster" "this" {
name = "${var.app_name}-cluster"
}

# -----------------------
# CloudWatch Log Group
# -----------------------
resource "aws_cloudwatch_log_group" "ecs" {
name = "/ecs/${var.app_name}"
retention_in_days = 7
}

# -----------------------
# ECS Task Definition
# -----------------------
resource "aws_ecs_task_definition" "this" {
family = var.app_name
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = var.container_cpu
memory = var.container_memory

execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
task_role_arn = aws_iam_role.ecs_task_role.arn

container_definitions = jsonencode([
{
name = var.app_name
image = "${aws_ecr_repository.backend_repo.repository_url}:latest"
essential = true

portMappings = [
{
containerPort = var.container_port
hostPort = var.container_port
protocol = "tcp"
}
]

secrets = [
{
name = "APP_SECRET"
valueFrom = aws_secretsmanager_secret.app_secret.arn
}
]

logConfiguration = {
logDriver = "awslogs"
options = {
awslogs-group = aws_cloudwatch_log_group.ecs.name
awslogs-region = var.aws_region
awslogs-stream-prefix = "ecs"
}
}
}
])
}

66 changes: 66 additions & 0 deletions terraform/aws/iam.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# -----------------------
# ECS Task Execution Role
# -----------------------
resource "aws_iam_role" "ecs_task_execution_role" {
name = "ecs-task-execution-role"

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

# Attach AWS managed policy (ECR + CloudWatch)
resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy" {
role = aws_iam_role.ecs_task_execution_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

# -----------------------
# ECS Task Role (Application Role)
# -----------------------
resource "aws_iam_role" "ecs_task_role" {
name = "ecs-task-role"

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

# -----------------------
# Custom policy for Secrets Manager access
# -----------------------
resource "aws_iam_policy" "secrets_manager_policy" {
name = "ecs-secrets-manager-policy"

policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = [
"secretsmanager:GetSecretValue"
]
Resource = "*"
}]
})
}

# Attach custom policy to ECS Task Role
resource "aws_iam_role_policy_attachment" "ecs_task_role_secrets_policy" {
role = aws_iam_role.ecs_task_role.name
policy_arn = aws_iam_policy.secrets_manager_policy.arn
}