Skip to content

Commit 72c71f4

Browse files
converting cloudformation template to terraform (#1260)
* creating TF code from the existing CFn template * refactoring * fixed sg id + lint * ignore tf state file * first steps to remove CF stack * changed deploy command to use TF * installing tf cli * moved secret env vars into AWS SM * created custom role for ecs exec (able to read newly created secret) * reusing redis hostname * imported acm cert * using snake case on app vars
1 parent b9846fb commit 72c71f4

18 files changed

+876
-39
lines changed

.github/workflows/deploy.yml

+8-2
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,16 @@ jobs:
3636
aws --profile $AWS_PROFILE configure set aws_access_key_id $AWS_ACCESS_KEY_ID
3737
aws --profile $AWS_PROFILE configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY
3838
39+
- name: Configure Terraform
40+
uses: hashicorp/setup-terraform@v3
41+
3942
- name: Prepare settings
4043
env:
41-
PARAM_JSON: ${{ secrets.PARAM_JSON }}
42-
run: echo "$PARAM_JSON" > sys/cloudformation/parameters.secrets.prod.json
44+
PARAM_TFVARS: ${{ secrets.PARAM_TFVARS }}
45+
run: echo "$PARAM_TFVARS" > sys/terraform/terraform.tfvars
46+
47+
- name: Terraform init
48+
run: terraform init
4349

4450
- name: Deploy
4551
env:

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,7 @@ sys/nginx/certs/ca-key.pem
4545
sys/nginx/certs/server.csr
4646
sys/nginx/certs/server.key
4747
sys/nginx/certs/server.pem
48+
sys/terraform/.terraform
49+
sys/terraform/terraform.tfvars
50+
sys/terraform/terraform.tfstate
4851
###< custom ###

Makefile

+3-17
Original file line numberDiff line numberDiff line change
@@ -80,23 +80,9 @@ PREVIOUS_TAG=$(shell git ls-remote --tags 2>&1 | awk '{print $$2}' | sort -r | h
8080
ECR_REGISTRY = $(AWS_ACCOUNT_ID).dkr.ecr.$(AWS_REGION).amazonaws.com
8181

8282
deploy_prod: build_prod_images push_prod_images ## deploy to prod
83-
cat sys/cloudformation/parameters.prod.json \
84-
| sed -e 's/{"ParameterKey": "EcrImageTagNginx", "ParameterValue": ".*"}/{"ParameterKey": "EcrImageTagNginx", "ParameterValue": "'$(VER)'"}/' \
85-
-e 's/{"ParameterKey": "EcrImageTagPhp", "ParameterValue": ".*"}/{"ParameterKey": "EcrImageTagPhp", "ParameterValue": "'$(VER)'"}/' \
86-
| tee sys/cloudformation/parameters.prod.json.new; \
87-
mv sys/cloudformation/parameters.prod.json sys/cloudformation/parameters.prod.json.bak; \
88-
mv sys/cloudformation/parameters.prod.json.new sys/cloudformation/parameters.prod.json; \
89-
cat sys/cloudformation/parameters.secrets.prod.json \
90-
| sed -e 's/{"ParameterKey": "EcrImageTagNginx", "ParameterValue": ".*"}/{"ParameterKey": "EcrImageTagNginx", "ParameterValue": "'$(VER)'"}/' \
91-
-e 's/{"ParameterKey": "EcrImageTagPhp", "ParameterValue": ".*"}/{"ParameterKey": "EcrImageTagPhp", "ParameterValue": "'$(VER)'"}/' \
92-
| tee sys/cloudformation/parameters.secrets.prod.json.new; \
93-
mv sys/cloudformation/parameters.secrets.prod.json sys/cloudformation/parameters.secrets.prod.json.bak; \
94-
mv sys/cloudformation/parameters.secrets.prod.json.new sys/cloudformation/parameters.secrets.prod.json; \
95-
aws --profile=$(AWS_PROFILE) cloudformation create-change-set --capabilities CAPABILITY_NAMED_IAM \
96-
--stack=poser-ecs \
97-
--change-set-name=poser-ecs-$(VER) \
98-
--template-body=file://$$PWD/sys/cloudformation/stack.yaml \
99-
--parameters=file://sys/cloudformation/parameters.secrets.prod.json
83+
# TODO: convert to terraform apply
84+
# TODO: modify IAM policy to allow only the creation of ECS tasks via pipelines
85+
terraform plan -var="ecr_image_tag_nginx=$(VER)" -var="ecr_image_tag_php=$(VER)"
10086

10187
build_%: export BADGE_POSER_REGISTRY = $(ECR_REGISTRY)/badge-poser
10288
build_%: export DOCKER_BUILDKIT = 1

sys/cloudformation/parameters.prod.json

-19
This file was deleted.

sys/cloudformation/stack.png

-247 KB
Binary file not shown.

sys/cloudformation/stack.yaml

+17-1
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ Resources:
187187

188188
# SECURITY GROUP
189189
sgelb:
190+
DeletionPolicy: Retain
190191
Type: AWS::EC2::SecurityGroup
191192
Properties:
192193
GroupDescription: !Sub '${ServiceName}-elb'
@@ -210,6 +211,7 @@ Resources:
210211
- Key: env
211212
Value: !Ref ServiceName
212213
sgecs:
214+
DeletionPolicy: Retain
213215
Type: AWS::EC2::SecurityGroup
214216
Properties:
215217
GroupDescription: !Sub '${ServiceName}-ecs'
@@ -233,6 +235,7 @@ Resources:
233235
- Key: env
234236
Value: !Ref ServiceName
235237
sgredis:
238+
DeletionPolicy: Retain
236239
Type: AWS::EC2::SecurityGroup
237240
Properties:
238241
GroupDescription: !Sub '${ServiceName}-redis'
@@ -254,13 +257,15 @@ Resources:
254257

255258
# CLOUDWATCH LOGS
256259
cloudwatchloggroup:
260+
DeletionPolicy: Retain
257261
Type: AWS::Logs::LogGroup
258262
Properties:
259263
LogGroupName: !Sub '${ServiceName}-logs'
260264
RetentionInDays: 30
261265

262266
# ELB
263267
elb:
268+
DeletionPolicy: Retain
264269
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
265270
Properties:
266271
Name: !Sub '${ServiceName}-elb'
@@ -273,6 +278,7 @@ Resources:
273278

274279
# ELB LISTENER
275280
elblistener80:
281+
DeletionPolicy: Retain
276282
Type: AWS::ElasticLoadBalancingV2::Listener
277283
Properties:
278284
DefaultActions:
@@ -286,6 +292,7 @@ Resources:
286292
Protocol: HTTP
287293

288294
elblistener443:
295+
DeletionPolicy: Retain
289296
Type: AWS::ElasticLoadBalancingV2::Listener
290297
Properties:
291298
DefaultActions:
@@ -303,6 +310,7 @@ Resources:
303310

304311
# ECS CLUSTER
305312
ecscluster:
313+
DeletionPolicy: Retain
306314
Type: AWS::ECS::Cluster
307315
Properties:
308316
ClusterName: !Sub '${ServiceName}-cluster-${Environment}'
@@ -318,6 +326,7 @@ Resources:
318326

319327
# ECS SERVICE
320328
ecsservice:
329+
DeletionPolicy: Retain
321330
Type: AWS::ECS::Service
322331
Properties:
323332
Cluster: !Ref ecscluster
@@ -342,8 +351,8 @@ Resources:
342351

343352
# ECS TASK DEFINITION
344353
ecstask:
345-
Type: AWS::ECS::TaskDefinition
346354
DeletionPolicy: Retain
355+
Type: AWS::ECS::TaskDefinition
347356
UpdateReplacePolicy: Retain
348357
Properties:
349358
ExecutionRoleArn: !Ref ExecRoleArn
@@ -430,6 +439,7 @@ Resources:
430439

431440
# AUTO SCALING
432441
asscalabletarget:
442+
DeletionPolicy: Retain
433443
Type: AWS::ApplicationAutoScaling::ScalableTarget
434444
DependsOn:
435445
- ecsservice
@@ -443,6 +453,7 @@ Resources:
443453

444454
# ELB TARGET GROUP
445455
elbtargetgroup:
456+
DeletionPolicy: Retain
446457
Type: AWS::ElasticLoadBalancingV2::TargetGroup
447458
DependsOn:
448459
- elb
@@ -468,6 +479,7 @@ Resources:
468479

469480
# ELB LISTENER RULE
470481
elblistenerrule80:
482+
DeletionPolicy: Retain
471483
Type: AWS::ElasticLoadBalancingV2::ListenerRule
472484
Properties:
473485
Actions:
@@ -485,6 +497,7 @@ Resources:
485497
ListenerArn: !Ref elblistener80
486498
Priority: 1
487499
elblistenerrule443:
500+
DeletionPolicy: Retain
488501
Type: AWS::ElasticLoadBalancingV2::ListenerRule
489502
Properties:
490503
Actions:
@@ -501,6 +514,7 @@ Resources:
501514

502515
# SCHEDULED TASK
503516
eventrulecontributorsupdate:
517+
DeletionPolicy: Retain
504518
Type: AWS::Events::Rule
505519
Properties:
506520
Name: 'app-contributors-update'
@@ -522,6 +536,7 @@ Resources:
522536

523537
# IAM USER
524538
iamusergithubactions:
539+
DeletionPolicy: Retain
525540
Type: AWS::IAM::User
526541
Properties:
527542
Policies:
@@ -576,6 +591,7 @@ Resources:
576591

577592
# IAM ACCESS-KEY
578593
iamkey:
594+
DeletionPolicy: Retain
579595
Type: AWS::IAM::AccessKey
580596
Properties:
581597
UserName: !Ref iamusergithubactions

sys/terraform/.terraform.lock.hcl

+25
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sys/terraform/cloudwatch.tf

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# TODO: import dashboard
2+
3+
resource "aws_cloudwatch_event_rule" "eventrulecontributorsupdate" {
4+
name = "app-contributors-update"
5+
schedule_expression = "rate(24 hours)"
6+
state = "DISABLED"
7+
// CF Property(Targets) = [
8+
// {
9+
// Id = "phpfpm"
10+
// Arn = aws_ecs_cluster.ecscluster.arn
11+
// RoleArn = aws_iam_role.ecs_task_role.arn
12+
// Input = "{"containerOverrides":[{"name":"phpfpm","command":["./bin/console","app:contributors:update"]}]}"
13+
// EcsParameters = {
14+
// TaskDefinitionArn = aws_ecs_task_definition.ecstask.arn
15+
// LaunchType = "FARGATE"
16+
// NetworkConfiguration = {
17+
// AwsVpcConfiguration = {
18+
// SecurityGroups = [
19+
// aws_security_group.sgecs.arn
20+
// ]
21+
// Subnets = var.subnets
22+
// }
23+
// }
24+
// }
25+
// }
26+
// ]
27+
}

sys/terraform/data.tf

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
data "aws_region" "current" {}
2+
3+
data "aws_caller_identity" "current" {}

sys/terraform/ecs.tf

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
resource "aws_security_group" "sgecs" {
2+
description = "${var.service_name}-ecs"
3+
name = "${var.service_name}-ecs"
4+
egress {
5+
cidr_blocks = ["0.0.0.0/0"]
6+
protocol = "-1"
7+
from_port = 0
8+
to_port = 0
9+
}
10+
vpc_id = var.vpc_id
11+
}
12+
13+
resource "aws_security_group_rule" "sgecs_ingress_http" {
14+
type = "ingress"
15+
security_group_id = aws_security_group.sgecs.id
16+
cidr_blocks = ["0.0.0.0/0"]
17+
from_port = 80
18+
protocol = "tcp"
19+
to_port = 80
20+
}
21+
resource "aws_security_group_rule" "sgecs_ingress_https" {
22+
type = "ingress"
23+
security_group_id = aws_security_group.sgecs.id
24+
cidr_blocks = ["0.0.0.0/0"]
25+
from_port = 443
26+
protocol = "tcp"
27+
to_port = 443
28+
}
29+
30+
resource "aws_cloudwatch_log_group" "cloudwatchloggroup" {
31+
name = "${var.service_name}-logs"
32+
retention_in_days = 14
33+
}
34+
35+
resource "aws_ecs_cluster" "ecscluster" {
36+
name = "${var.service_name}-cluster-${var.environment}"
37+
// CF Property(CapacityProviders) = [
38+
// "FARGATE",
39+
// "FARGATE_SPOT"
40+
// ]
41+
setting {
42+
name = "containerInsights"
43+
value = "disabled"
44+
}
45+
}
46+
47+
resource "aws_ecs_service" "ecsservice" {
48+
cluster = aws_ecs_cluster.ecscluster.arn
49+
desired_count = 1
50+
health_check_grace_period_seconds = 15
51+
52+
capacity_provider_strategy {
53+
base = 0
54+
capacity_provider = "FARGATE_SPOT"
55+
weight = 2
56+
}
57+
capacity_provider_strategy {
58+
base = 1
59+
capacity_provider = "FARGATE"
60+
weight = 1
61+
}
62+
63+
load_balancer {
64+
container_name = "nginx"
65+
container_port = 80
66+
target_group_arn = aws_lb_target_group.elbtargetgroup.id
67+
}
68+
name = var.service_name
69+
task_definition = "${var.service_name}:${aws_ecs_task_definition.ecstask.revision}"
70+
network_configuration {
71+
assign_public_ip = true
72+
security_groups = [aws_security_group.sgecs.id]
73+
subnets = var.subnets
74+
}
75+
}
76+
77+
resource "aws_ecs_task_definition" "ecstask" {
78+
execution_role_arn = aws_iam_role.ecs_task_role.arn
79+
container_definitions = templatefile("ecs/task-definition.json", {
80+
account_id = data.aws_caller_identity.current.account_id
81+
aws_region = data.aws_region.current.name
82+
service_name = var.service_name
83+
ecr_image_tag_nginx = var.ecr_image_tag_nginx
84+
ecr_image_tag_php = var.ecr_image_tag_php
85+
cloudwatch_log_group = aws_cloudwatch_log_group.cloudwatchloggroup.name
86+
env_app_debug = var.env_app_debug
87+
env_app_env = var.env_app_env
88+
env_app_xdebug = var.env_app_xdebug
89+
env_app_xdebug_host = var.env_app_xdebug_host
90+
env_bitbucket_auth_method = var.env_bitbucket_auth_method
91+
env_github_auth_method = var.env_github_auth_method
92+
env_phpfpm_host = var.env_phpfpm_host
93+
env_redis_host = aws_elasticache_cluster.rediscluster.cache_nodes[0].address
94+
env_resolver_ip = var.env_resolver_ip
95+
env_sentry_dsn = var.env_sentry_dsn
96+
env_trusted_proxies = var.env_trusted_proxies
97+
})
98+
memory = "2048"
99+
family = var.service_name
100+
requires_compatibilities = [
101+
"FARGATE"
102+
]
103+
network_mode = "awsvpc"
104+
cpu = "1024"
105+
skip_destroy = true
106+
}

0 commit comments

Comments
 (0)