@@ -16,6 +16,28 @@ resource "aws_ecs_cluster" "main" {
1616 tags = var. common_tags
1717}
1818
19+ resource "aws_ecr_lifecycle_policy" "main" {
20+ repository = aws_ecr_repository. main . name
21+
22+ policy = jsonencode ({
23+ rules = [
24+ {
25+ rulePriority = 1
26+ description = " Remove untagged images"
27+ selection = {
28+ tagStatus = " untagged"
29+ countType = " sinceImagePushed"
30+ countUnit = " days"
31+ countNumber = 7
32+ }
33+ action = {
34+ type = " expire"
35+ }
36+ }
37+ ]
38+ })
39+ }
40+
1941resource "aws_ecr_repository" "main" {
2042 name = " ${ var . project_name } -${ var . environment } -backend"
2143 image_scanning_configuration {
@@ -60,8 +82,43 @@ resource "aws_iam_policy" "ecs_tasks_execution_role_ssm_policy" {
6082 })
6183}
6284
63- resource "aws_iam_role_policy_attachment" "ecs_tasks_execution_role_policy" {
64- policy_arn = " arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
85+ resource "aws_iam_policy" "ecs_tasks_execution_policy" {
86+ name = " ${ var . project_name } -${ var . environment } -ecs-tasks-execution-policy"
87+ description = " Custom policy for ECS task execution - ECR and CloudWatch Logs access"
88+
89+ policy = jsonencode ({
90+ Version = " 2012-10-17"
91+ Statement = [
92+ {
93+ Action = [
94+ " ecr:GetAuthorizationToken"
95+ ]
96+ Effect = " Allow"
97+ Resource = " *"
98+ },
99+ {
100+ Action = [
101+ " ecr:BatchCheckLayerAvailability" ,
102+ " ecr:BatchGetImage" ,
103+ " ecr:GetDownloadUrlForLayer"
104+ ]
105+ Effect = " Allow"
106+ Resource = aws_ecr_repository.main.arn
107+ },
108+ {
109+ Effect = " Allow"
110+ Action = [
111+ " logs:CreateLogStream" ,
112+ " logs:PutLogEvents"
113+ ]
114+ Resource = " arn:aws:logs:${ var . aws_region } :${ data . aws_caller_identity . current . account_id } :log-group:/aws/ecs/${ var . project_name } -${ var . environment } -*:*"
115+ }
116+ ]
117+ })
118+ }
119+
120+ resource "aws_iam_role_policy_attachment" "ecs_tasks_execution_policy_attachment" {
121+ policy_arn = aws_iam_policy. ecs_tasks_execution_policy . arn
65122 role = aws_iam_role. ecs_tasks_execution_role . name
66123}
67124
@@ -111,8 +168,37 @@ resource "aws_iam_role" "event_bridge_role" {
111168 })
112169}
113170
114- resource "aws_iam_role_policy_attachment" "event_bridge_role_policy" {
115- policy_arn = " arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceEventsRole"
171+ resource "aws_iam_policy" "event_bridge_ecs_policy" {
172+ name = " ${ var . project_name } -${ var . environment } -event-bridge-ecs-policy"
173+ description = " Allow EventBridge to run ECS tasks"
174+
175+ policy = jsonencode ({
176+ Version = " 2012-10-17"
177+ Statement = [
178+ {
179+ Action = " ecs:RunTask"
180+ Effect = " Allow"
181+ Condition = {
182+ ArnLike = {
183+ " ecs:cluster" = aws_ecs_cluster.main.arn
184+ }
185+ }
186+ Resource = " arn:aws:ecs:${ var . aws_region } :${ data . aws_caller_identity . current . account_id } :task-definition/${ var . project_name } -${ var . environment } -*:*"
187+ },
188+ {
189+ Action = " iam:PassRole"
190+ Effect = " Allow"
191+ Resource = [
192+ aws_iam_role.ecs_task_role.arn,
193+ aws_iam_role.ecs_tasks_execution_role.arn
194+ ]
195+ }
196+ ]
197+ })
198+ }
199+
200+ resource "aws_iam_role_policy_attachment" "event_bridge_policy_attachment" {
201+ policy_arn = aws_iam_policy. event_bridge_ecs_policy . arn
116202 role = aws_iam_role. event_bridge_role . name
117203}
118204
@@ -128,7 +214,7 @@ module "sync_data_task" {
128214 ecs_tasks_execution_role_arn = aws_iam_role. ecs_tasks_execution_role . arn
129215 environment = var. environment
130216 event_bridge_role_arn = aws_iam_role. event_bridge_role . arn
131- image_url = aws_ecr_repository. main . repository_url
217+ image_url = " ${ aws_ecr_repository . main . repository_url } : ${ var . image_tag } "
132218 memory = var. sync_data_task_memory
133219 private_subnet_ids = var. private_subnet_ids
134220 project_name = var. project_name
@@ -157,7 +243,7 @@ module "owasp_update_project_health_metrics_task" {
157243 ecs_tasks_execution_role_arn = aws_iam_role. ecs_tasks_execution_role . arn
158244 environment = var. environment
159245 event_bridge_role_arn = aws_iam_role. event_bridge_role . arn
160- image_url = aws_ecr_repository. main . repository_url
246+ image_url = " ${ aws_ecr_repository . main . repository_url } : ${ var . image_tag } "
161247 memory = var. update_project_health_metrics_task_memory
162248 private_subnet_ids = var. private_subnet_ids
163249 project_name = var. project_name
@@ -178,7 +264,7 @@ module "owasp_update_project_health_scores_task" {
178264 ecs_tasks_execution_role_arn = aws_iam_role. ecs_tasks_execution_role . arn
179265 environment = var. environment
180266 event_bridge_role_arn = aws_iam_role. event_bridge_role . arn
181- image_url = aws_ecr_repository. main . repository_url
267+ image_url = " ${ aws_ecr_repository . main . repository_url } : ${ var . image_tag } "
182268 memory = var. update_project_health_scores_task_memory
183269 private_subnet_ids = var. private_subnet_ids
184270 project_name = var. project_name
@@ -198,7 +284,7 @@ module "migrate_task" {
198284 ecs_cluster_arn = aws_ecs_cluster. main . arn
199285 ecs_tasks_execution_role_arn = aws_iam_role. ecs_tasks_execution_role . arn
200286 environment = var. environment
201- image_url = " ${ aws_ecr_repository . main . repository_url } :latest "
287+ image_url = " ${ aws_ecr_repository . main . repository_url } :${ var . image_tag } "
202288 memory = var. migrate_task_memory
203289 private_subnet_ids = var. private_subnet_ids
204290 project_name = var. project_name
@@ -215,9 +301,11 @@ module "load_data_task" {
215301 " -c" ,
216302 <<- EOT
217303 set -e
218- pip install --target=/tmp/awscli-packages awscli
219- export PYTHONPATH="/tmp/awscli-packages:$PYTHONPATH"
220- python /tmp/awscli-packages/bin/aws s3 cp s3://${ var . fixtures_bucket_name } /nest.json.gz /tmp/nest.json.gz
304+ python -c "
305+ import boto3
306+ s3 = boto3.client('s3')
307+ s3.download_file('${ var . fixtures_bucket_name } ', 'nest.json.gz', '/tmp/nest.json.gz')
308+ "
221309 python manage.py load_data --fixture-path /tmp/nest.json.gz
222310 EOT
223311 ]
@@ -227,7 +315,7 @@ module "load_data_task" {
227315 ecs_cluster_arn = aws_ecs_cluster. main . arn
228316 ecs_tasks_execution_role_arn = aws_iam_role. ecs_tasks_execution_role . arn
229317 environment = var. environment
230- image_url = " ${ aws_ecr_repository . main . repository_url } :latest "
318+ image_url = " ${ aws_ecr_repository . main . repository_url } :${ var . image_tag } "
231319 memory = var. load_data_task_memory
232320 private_subnet_ids = var. private_subnet_ids
233321 project_name = var. project_name
@@ -247,7 +335,7 @@ module "index_data_task" {
247335 ecs_cluster_arn = aws_ecs_cluster. main . arn
248336 ecs_tasks_execution_role_arn = aws_iam_role. ecs_tasks_execution_role . arn
249337 environment = var. environment
250- image_url = " ${ aws_ecr_repository . main . repository_url } :latest "
338+ image_url = " ${ aws_ecr_repository . main . repository_url } :${ var . image_tag } "
251339 memory = var. index_data_task_memory
252340 private_subnet_ids = var. private_subnet_ids
253341 project_name = var. project_name
0 commit comments