-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from silinternational/develop
Release
- Loading branch information
Showing
10 changed files
with
791 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# This workflow installs the latest version of Terraform CLI. On pull request events, this workflow will run | ||
# `terraform init`, `terraform fmt`, and `terraform plan`. | ||
# | ||
# Documentation for `hashicorp/setup-terraform` is located here: https://github.com/hashicorp/setup-terraform | ||
|
||
name: 'Terraform' | ||
|
||
on: | ||
push: | ||
|
||
permissions: | ||
contents: read | ||
|
||
jobs: | ||
terraform: | ||
name: 'Terraform' | ||
runs-on: ubuntu-latest | ||
|
||
# Use the Bash shell regardless whether the GitHub Actions runner is ubuntu-latest, macos-latest, or windows-latest | ||
defaults: | ||
run: | ||
shell: bash | ||
|
||
steps: | ||
# Checkout the repository to the GitHub Actions runner | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
|
||
# Install the latest version of Terraform CLI | ||
- name: Setup Terraform | ||
uses: hashicorp/setup-terraform@v2 | ||
|
||
# Checks that all Terraform configuration files adhere to a canonical format | ||
- name: Terraform Format | ||
run: terraform fmt -check -diff -recursive | ||
|
||
# Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc. | ||
- name: Terraform Init | ||
run: terraform -chdir=test init | ||
|
||
# Validate the files, referring only to the configuration and not accessing any remote services | ||
- name: Terraform Validate | ||
run: terraform -chdir=test validate |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,3 +32,6 @@ override.tf.json | |
# Ignore CLI configuration files | ||
.terraformrc | ||
terraform.rc | ||
|
||
# IDE configuration | ||
.idea/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,14 @@ | ||
# terraform-aws-ecs-app | ||
Terraform module to host an app on AWS ECS | ||
|
||
Includes: | ||
|
||
* VPC - Virtual Private Cloud | ||
* ALB - Application Load Balancer | ||
* ASG - Autoscaling Group | ||
* ECS (Elastic Container Service) Cluster and Service | ||
* ECR - Elastic Container Registry | ||
* RDS (Relational Database Service) Instance | ||
* CloudWatch Dashboard (optional) | ||
* Cloudflare DNS Record (optional) | ||
* Adminer database manager (optional) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
locals { | ||
app_name_and_env = "${var.app_name}-${local.app_env}" | ||
app_env = var.app_env | ||
|
||
db_host = module.rds.address | ||
db_password = random_password.db_root.result | ||
|
||
account = data.aws_caller_identity.this.account_id | ||
region = data.aws_region.current.name | ||
} | ||
|
||
/* | ||
* Create user for CI/CD to perform ECS actions | ||
*/ | ||
resource "aws_iam_user" "cd" { | ||
count = var.create_cd_user ? 1 : 0 | ||
|
||
name = "cd-${local.app_name_and_env}" | ||
} | ||
|
||
resource "aws_iam_access_key" "cd" { | ||
count = var.create_cd_user ? 1 : 0 | ||
|
||
user = aws_iam_user.cd[0].name | ||
} | ||
|
||
resource "aws_iam_user_policy" "cd" { | ||
count = var.create_cd_user ? 1 : 0 | ||
|
||
name = "ecs_deployment" | ||
user = aws_iam_user.cd[0].name | ||
|
||
policy = jsonencode({ | ||
Version = "2012-10-17" | ||
Statement = [ | ||
{ | ||
Effect = "Allow" | ||
Action = [ | ||
"ecr:GetAuthorizationToken", | ||
"ecs:DeregisterTaskDefinition", | ||
"ecs:DescribeTaskDefinition", | ||
"ecs:ListTaskDefinitions", | ||
"ecs:RegisterTaskDefinition", | ||
], | ||
Resource = "*" | ||
}, | ||
{ | ||
Effect = "Allow" | ||
Action = [ | ||
"ecs:DescribeServices", | ||
"ecs:UpdateService", | ||
] | ||
Resource = "arn:aws:ecs:${local.region}:${local.account}:service/${module.ecsasg.ecs_cluster_name}/${module.ecs.service_name}" | ||
}, | ||
{ | ||
Effect = "Allow" | ||
Action = [ | ||
"ecs:DescribeTasks", | ||
"ecs:StopTask", | ||
] | ||
Resource = "arn:aws:ecs:${local.region}:${local.account}:task/${module.ecsasg.ecs_cluster_name}/*" | ||
}, | ||
{ | ||
Effect = "Allow" | ||
Action = [ | ||
"ecs:ListTasks", | ||
] | ||
"Effect" : "Allow", | ||
"Condition" : { | ||
"ArnEquals" : { | ||
"ecs:cluster" : "arn:aws:ecs:${local.region}:${local.account}:cluster/${module.ecsasg.ecs_cluster_name}" | ||
} | ||
} | ||
Resource = "*" | ||
}, | ||
{ | ||
Effect = "Allow" | ||
Action = [ | ||
"ecs:StartTask", | ||
] | ||
Resource = "arn:aws:ecs:${local.region}:${local.account}:task-definition/${module.ecs.task_def_family}:*" | ||
}, | ||
{ | ||
Effect = "Allow" | ||
Action = [ | ||
"iam:PassRole", | ||
] | ||
Resource = module.ecsasg.ecsServiceRole_arn | ||
}, | ||
] | ||
}) | ||
} | ||
|
||
/* | ||
* Create Cloudwatch log group | ||
*/ | ||
resource "aws_cloudwatch_log_group" "logs" { | ||
name = local.app_name_and_env | ||
retention_in_days = 30 | ||
} | ||
|
||
/* | ||
* Create target group for ALB | ||
*/ | ||
resource "aws_alb_target_group" "tg" { | ||
name = substr("tg-${local.app_name_and_env}", 0, 32) | ||
port = "80" | ||
protocol = "HTTP" | ||
vpc_id = module.vpc.id | ||
deregistration_delay = "30" | ||
|
||
stickiness { | ||
type = "lb_cookie" | ||
} | ||
|
||
health_check { | ||
path = "/" | ||
matcher = "302" | ||
} | ||
} | ||
|
||
/* | ||
* Create listener rule for hostname routing to new target group | ||
*/ | ||
resource "aws_alb_listener_rule" "tg" { | ||
listener_arn = module.alb.https_listener_arn | ||
priority = "218" | ||
|
||
action { | ||
type = "forward" | ||
target_group_arn = aws_alb_target_group.tg.arn | ||
} | ||
|
||
condition { | ||
host_header { | ||
values = ["${var.subdomain}.${var.domain_name}"] | ||
} | ||
} | ||
} | ||
|
||
/* | ||
* Create cloudwatch dashboard for service | ||
*/ | ||
module "ecs-service-cloudwatch-dashboard" { | ||
count = var.create_dashboard ? 1 : 0 | ||
|
||
source = "silinternational/ecs-service-cloudwatch-dashboard/aws" | ||
version = "~> 3.0.1" | ||
|
||
cluster_name = module.ecsasg.ecs_cluster_name | ||
dashboard_name = local.app_name_and_env | ||
service_names = [var.app_name] | ||
} | ||
|
||
/* | ||
* Create RDS root password | ||
*/ | ||
resource "random_password" "db_root" { | ||
length = 16 | ||
} | ||
|
||
/* | ||
* Create an RDS database | ||
*/ | ||
module "rds" { | ||
source = "github.com/silinternational/terraform-modules//aws/rds/mariadb?ref=8.2.1" | ||
|
||
app_name = var.app_name | ||
app_env = local.app_env | ||
db_name = var.database_name | ||
db_root_user = var.database_user | ||
db_root_pass = random_password.db_root.result | ||
subnet_group_name = module.vpc.db_subnet_group_name | ||
security_groups = [module.vpc.vpc_default_sg_id] | ||
|
||
allocated_storage = 20 // 20 gibibyte | ||
instance_class = "db.t3.micro" | ||
multi_az = true | ||
} | ||
|
||
/* | ||
* Optional Adminer database manager | ||
*/ | ||
module "adminer" { | ||
count = var.create_adminer ? 1 : 0 | ||
source = "silinternational/adminer/aws" | ||
version = "1.0.2" | ||
|
||
adminer_default_server = module.rds.address | ||
app_name = var.app_name | ||
app_env = var.app_env | ||
vpc_id = module.vpc.id | ||
alb_https_listener_arn = module.alb.https_listener_arn | ||
subdomain = "adminer" | ||
cloudflare_domain = var.domain_name | ||
ecs_cluster_id = module.ecsasg.ecs_cluster_id | ||
ecsServiceRole_arn = module.ecsasg.ecsServiceRole_arn | ||
alb_dns_name = module.alb.dns_name | ||
enable = var.enable_adminer | ||
} | ||
|
||
/* | ||
* Create new ecs service | ||
*/ | ||
module "ecs" { | ||
source = "github.com/silinternational/terraform-modules//aws/ecs/service-only?ref=8.2.1" | ||
cluster_id = module.ecsasg.ecs_cluster_id | ||
service_name = var.app_name | ||
service_env = local.app_env | ||
container_def_json = var.container_def_json | ||
desired_count = var.desired_count | ||
tg_arn = aws_alb_target_group.tg.arn | ||
lb_container_name = "hub" | ||
lb_container_port = "80" | ||
ecsServiceRole_arn = module.ecsasg.ecsServiceRole_arn | ||
} | ||
|
||
/* | ||
* Create Cloudflare DNS record | ||
*/ | ||
resource "cloudflare_record" "dns" { | ||
count = var.create_dns_record ? 1 : 0 | ||
|
||
zone_id = data.cloudflare_zones.domain.zones[0].id | ||
name = var.subdomain | ||
value = module.alb.dns_name | ||
type = "CNAME" | ||
proxied = true | ||
} | ||
|
||
data "cloudflare_zones" "domain" { | ||
filter { | ||
name = var.domain_name | ||
lookup_type = "exact" | ||
status = "active" | ||
} | ||
} | ||
|
||
|
||
/* | ||
* AWS data | ||
*/ | ||
|
||
data "aws_caller_identity" "this" {} | ||
|
||
data "aws_region" "current" {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
|
||
output "app_url" { | ||
value = "https://${var.subdomain}.${var.domain_name}" | ||
} | ||
|
||
output "cloudwatch_log_group_name" { | ||
value = aws_cloudwatch_log_group.logs.name | ||
} | ||
|
||
output "database_host" { | ||
value = module.rds.address | ||
} | ||
|
||
output "database_password" { | ||
value = random_password.db_root.result | ||
sensitive = true | ||
} | ||
|
||
output "adminer_url" { | ||
value = one(module.adminer[*].adminer_url) | ||
} | ||
|
||
output "ecsInstanceRole_arn" { | ||
value = module.ecsasg.ecsInstanceRole_arn | ||
} | ||
|
||
output "ecsServiceRole_arn" { | ||
value = module.ecsasg.ecsServiceRole_arn | ||
} | ||
|
||
output "cd_user_arn" { | ||
value = one(aws_iam_user.cd[*].arn) | ||
} | ||
|
||
output "cd_user_access_key_id" { | ||
value = one(aws_iam_access_key.cd[*].id) | ||
} | ||
|
||
output "cd_user_secret_access_key_id" { | ||
value = one(aws_iam_access_key.cd[*].secret) | ||
sensitive = true | ||
} |
Oops, something went wrong.