1+ provider "aws" {
2+ region = " us-east-1"
3+ }
4+
5+ resource "aws_ecs_cluster" "bwwc_cluster" {
6+ name = " bwwc-cluster"
7+ }
8+
9+ # Create a CloudWatch Log Group for the backend service logs
10+ resource "aws_cloudwatch_log_group" "ecs_log_group_backend" {
11+ name = " /ecs/bwwc-backend"
12+ retention_in_days = 14
13+ }
14+
15+ # Define a custom IAM policy allowing ECS tasks to write logs to CloudWatch
16+ resource "aws_iam_policy" "cloudwatch_logs_policy" {
17+ name = " ecs-cloudwatch-logs-policy"
18+ description = " Policy to allow ECS tasks to write logs to CloudWatch"
19+
20+ policy = jsonencode ({
21+ Version = " 2012-10-17" ,
22+ Statement = [
23+ {
24+ Effect = " Allow" ,
25+ Action = [
26+ " logs:CreateLogStream" ,
27+ " logs:PutLogEvents"
28+ ],
29+ Resource = [
30+ " ${ aws_cloudwatch_log_group . ecs_log_group_backend . arn } :*"
31+ ]
32+ }
33+ ]
34+ })
35+ }
36+
37+ # Attach the CloudWatch logs policy to the ECS task execution role
38+ resource "aws_iam_role_policy_attachment" "cloudwatch_logs_policy_attachment" {
39+ role = aws_iam_role. ecs_task_execution_role . name
40+ policy_arn = aws_iam_policy. cloudwatch_logs_policy . arn
41+ }
42+
43+ # Define the ECS Fargate task for the backend service
44+ resource "aws_ecs_task_definition" "backend" {
45+ family = " bwwc-backend"
46+ network_mode = " awsvpc"
47+ requires_compatibilities = [" FARGATE" ]
48+ cpu = " 512"
49+ memory = " 1024"
50+ execution_role_arn = aws_iam_role. ecs_task_execution_role . arn
51+
52+ runtime_platform {
53+ cpu_architecture = " X86_64"
54+ }
55+
56+ container_definitions = jsonencode ([
57+ {
58+ name = " bwwc-backend" ,
59+ image = " multiparty/bwwc-backend:main" ,
60+ memory = 512 ,
61+ cpu = 256 ,
62+ essential = true ,
63+ portMappings = [{ containerPort = 8000 , hostPort = 8000 }], # application is listening on port 8000
64+ healthCheck = {
65+ command = [" CMD-SHELL" , " wget -q -O - http://localhost:8000/api/bwwc/healthz || exit 1" ]
66+ interval = 30
67+ timeout = 5
68+ retries = 3
69+ startPeriod = 60
70+ },
71+ environment = [
72+ { name = " SECRET_KEY" , value = " django-insecure-x$ee)y$zn8!egy6(9olf6maf2tt0%wtn&qd_qzlo_v9f_-!5)@" },
73+ { name = " BASE_URL" , value = " http://${ aws_lb . bwwc_lb . dns_name } " },
74+ { name = " PRIME" , value = " 180252380737439" },
75+ { name = " THRESHOLD" , value = " 3" },
76+ { name = " POSTGRES_HOST" , value = var.postgres_host },
77+ { name = " POSTGRES_USERNAME" , value = var.postgres_username },
78+ { name = " POSTGRES_DATABASE" , value = var.postgres_database },
79+ { name = " POSTGRES_PORT" , value = " 5432" },
80+ { name = " MONGO_URI" , value = var.mongo_uri },
81+ { name = " DJANGO_ALLOWED_HOSTS" , value = " ${ aws_lb . bwwc_lb . dns_name } ,localhost,127.0.0.1" },
82+ { name = " ALLOW_ALL_HOSTS" , value = " true" },
83+ { name = " DUMMY_TRIGGER" , value = timestamp () }
84+ ],
85+ secrets = [
86+ { name = " POSTGRES_PASSWORD" , valueFrom = " ${ var . postgres_password } :password::" }
87+ ],
88+ logConfiguration = {
89+ logDriver = " awslogs"
90+ options = {
91+ " awslogs-group" = aws_cloudwatch_log_group.ecs_log_group_backend.name
92+ " awslogs-region" = " us-east-1"
93+ " awslogs-stream-prefix" = " bwwc-backend"
94+ }
95+ }
96+ }
97+ ])
98+ }
99+
100+ # Create the ECS service to run the backend task
101+ resource "aws_ecs_service" "backend" {
102+ name = " bwwc-backend-service"
103+ cluster = aws_ecs_cluster. bwwc_cluster . id
104+ task_definition = aws_ecs_task_definition. backend . arn
105+ launch_type = " FARGATE"
106+ desired_count = 1
107+
108+ network_configuration {
109+ subnets = var. private_subnet_ids
110+ security_groups = [aws_security_group . fargate_sg . id ]
111+ assign_public_ip = false
112+ }
113+
114+ load_balancer {
115+ target_group_arn = aws_lb_target_group. backend . arn
116+ container_name = " bwwc-backend"
117+ container_port = 8000 # Must match container definition's port above
118+ }
119+
120+ # Grace period to allow the container to pass health checks before being marked unhealthy
121+ health_check_grace_period_seconds = 60
122+ }
123+
124+ resource "aws_security_group" "lb_sg" {
125+ name = " lb-sg"
126+ description = " Security group for the ALB"
127+ vpc_id = var. vpc_id
128+
129+ ingress {
130+ description = " Allow HTTP traffic"
131+ from_port = 80
132+ to_port = 80
133+ protocol = " tcp"
134+ cidr_blocks = [" 0.0.0.0/0" ]
135+ }
136+
137+ ingress {
138+ description = " Allow HTTPS traffic"
139+ from_port = 443
140+ to_port = 443
141+ protocol = " tcp"
142+ cidr_blocks = [" 0.0.0.0/0" ] # Allow traffic from anywhere
143+ }
144+
145+ egress {
146+ description = " Allow all outbound traffic"
147+ from_port = 0
148+ to_port = 0
149+ protocol = " -1"
150+ cidr_blocks = [" 0.0.0.0/0" ]
151+ }
152+ }
153+
154+ # Security group for the ALB to allow HTTP and HTTPS from the internet
155+ resource "aws_security_group" "fargate_sg" {
156+ name = " fargate-sg"
157+ description = " Allow inbound traffic to backend only from ALB"
158+ vpc_id = var. vpc_id
159+
160+ ingress {
161+ from_port = 8000
162+ to_port = 8000
163+ protocol = " tcp"
164+ security_groups = [aws_security_group . lb_sg . id ]
165+ }
166+
167+ egress {
168+ from_port = 0
169+ to_port = 0
170+ protocol = " -1"
171+ cidr_blocks = [" 0.0.0.0/0" ]
172+ }
173+ }
174+
175+ # Security group for the ECS tasks to allow traffic only from the ALB
176+ resource "aws_lb" "bwwc_lb" {
177+ name = " bwwc-lb"
178+ internal = false
179+ load_balancer_type = " application"
180+ security_groups = [aws_security_group . lb_sg . id ]
181+ subnets = var. public_subnet_ids
182+ }
183+
184+ # Application Load Balancer for routing traffic to the ECS service
185+ resource "aws_lb_target_group" "backend" {
186+ name = " bwwc-backend-tg"
187+ port = 8000 # must match container definition port
188+ protocol = " HTTP"
189+ vpc_id = var. vpc_id
190+ target_type = " ip"
191+
192+ health_check {
193+ path = " /api/bwwc/healthz"
194+ interval = 30
195+ timeout = 5
196+ healthy_threshold = 2
197+ unhealthy_threshold = 2
198+ matcher = " 200"
199+ }
200+
201+ lifecycle {
202+ create_before_destroy = true
203+ }
204+ }
205+
206+ # Listener to forward HTTP traffic from the ALB to the target group
207+ resource "aws_lb_listener" "backend" {
208+ load_balancer_arn = aws_lb. bwwc_lb . arn
209+ port = 80
210+ protocol = " HTTP"
211+ default_action {
212+ type = " forward"
213+ target_group_arn = aws_lb_target_group. backend . arn
214+ }
215+ }
216+
217+ # IAM policy allowing ECS tasks to retrieve secrets from Secrets Manager
218+ resource "aws_iam_policy" "secrets_access" {
219+ name = " ECSSecretsAccess"
220+ description = " Allow ECS tasks to retrieve secrets from AWS Secrets Manager"
221+ policy = jsonencode ({
222+ Version = " 2012-10-17" ,
223+ Statement = [
224+ {
225+ Effect = " Allow" ,
226+ Action = [" secretsmanager:GetSecretValue" ],
227+ Resource = " arn:aws:secretsmanager:us-east-1:135854645631:secret:*"
228+ }
229+ ]
230+ })
231+ }
232+
233+ # IAM role that ECS tasks assume to interact with AWS services
234+ resource "aws_iam_role" "ecs_task_execution_role" {
235+ name = " ecsTaskExecutionRole"
236+
237+ assume_role_policy = jsonencode ({
238+ Version = " 2012-10-17" ,
239+ Statement = [
240+ {
241+ Effect = " Allow" ,
242+ Principal = {
243+ Service = " ecs-tasks.amazonaws.com"
244+ },
245+ Action = " sts:AssumeRole"
246+ }
247+ ]
248+ })
249+ }
250+
251+ # Attach AWS-managed ECS task execution policy to the execution role
252+ resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy" {
253+ role = aws_iam_role. ecs_task_execution_role . name
254+ policy_arn = " arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
255+ }
256+
257+ # Attach custom secrets access policy to the execution role
258+ resource "aws_iam_role_policy_attachment" "ecs_task_secrets" {
259+ role = aws_iam_role. ecs_task_execution_role . name
260+ policy_arn = aws_iam_policy. secrets_access . arn
261+ }
0 commit comments