-
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.
- Loading branch information
Showing
13 changed files
with
585 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,57 @@ | ||
on: | ||
workflow_call: | ||
inputs: | ||
aws_region: | ||
description: The AWS region target for deployment | ||
required: true | ||
type: string | ||
aws_replication_region: | ||
description: The AWS replication region target for deployment | ||
required: true | ||
type: string | ||
aws_s3_terraform_state_object_key: | ||
description: The key of the Terraform .tfstate file in AWS S3 | ||
required: true | ||
type: string | ||
environment_name: | ||
description: The name of the environment configured in Github repository settings | ||
required: true | ||
type: string | ||
secrets: | ||
aws_assume_role_arn: | ||
description: The AWS IAM role assumed by Github Actions | ||
aws_s3_terraform_state_bucket_name: | ||
description: The AWS S3 bucket name containing Terraform backends, configured in Github repository settings | ||
required: true | ||
|
||
jobs: | ||
deploy: | ||
name: Deploy | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Clone the Git repository | ||
uses: actions/checkout@v3 | ||
- name: Configure AWS credentials | ||
uses: aws-actions/[email protected] | ||
with: | ||
role-to-assume: ${{ secrets.aws_assume_role_arn }} | ||
aws-region: ${{ inputs.aws_region }} | ||
- name: Setup Terraform | ||
uses: hashicorp/setup-terraform@v2 | ||
- name: Terraform Format | ||
run: terraform fmt -check | ||
working-directory: ./terraform | ||
- name: Terraform Init | ||
run: | | ||
terraform init \ | ||
-backend-config="bucket=${{ secrets.aws_s3_terraform_state_bucket_name }}" \ | ||
-backend-config="key=${{ inputs.aws_s3_terraform_state_object_key }}" \ | ||
-backend-config="region=${{ inputs.aws_region }}" | ||
working-directory: ./terraform | ||
- name: Terraform Apply | ||
run: | | ||
terraform apply -auto-approve \ | ||
-var="aws_region=${{ inputs.aws_region }}" \ | ||
-var="aws_replication_region=${{ inputs.aws_replication_region }}" \ | ||
-var="environment=${{ inputs.environment_name }}" | ||
working-directory: ./terraform |
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,33 @@ | ||
name: Deploy development | ||
|
||
on: | ||
push: | ||
branches: | ||
- develop | ||
- feature/* | ||
|
||
permissions: | ||
id-token: write # This is required for requesting the JWT | ||
contents: read # This is required for actions/checkout | ||
|
||
jobs: | ||
deploy: | ||
name: Deploy to development | ||
uses: ./.github/workflows/deploy.yml | ||
# Originally the workflow implementation was setup to use environment | ||
# variables configured in the Github repository settings. However, | ||
# after moving to a reusable action, it became ugly to pass those values | ||
# into the called action due to this bug: | ||
# | ||
# https://github.com/orgs/community/discussions/26671#discussioncomment-4295807 | ||
# | ||
# So now we're hardcoding the values here and using it as a manifest. Please see | ||
# commit 1ec7a0346abc04b73c03e35c0e228e9dba14300c for the previous implementation. | ||
with: | ||
aws_region: us-east-1 | ||
aws_replication_region: us-west-2 | ||
aws_s3_terraform_state_object_key: development.tfstate | ||
environment_name: dev | ||
secrets: | ||
aws_assume_role_arn: ${{ secrets.AWS_ASSUME_ROLE_ARN }} | ||
aws_s3_terraform_state_bucket_name: ${{ secrets.AWS_S3_TERRAFORM_STATE_BUCKET_NAME }} |
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,32 @@ | ||
name: Deploy production | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
|
||
permissions: | ||
id-token: write # This is required for requesting the JWT | ||
contents: read # This is required for actions/checkout | ||
|
||
jobs: | ||
deploy: | ||
name: Deploy to production | ||
uses: ./.github/workflows/deploy.yml | ||
# Originally the workflow implementation was setup to use environment | ||
# variables configured in the Github repository settings. However, | ||
# after moving to a reusable action, it became ugly to pass those values | ||
# into the called action due to this bug: | ||
# | ||
# https://github.com/orgs/community/discussions/26671#discussioncomment-4295807 | ||
# | ||
# So now we're hardcoding the values here and using it as a manifest. Please see | ||
# commit 1ec7a0346abc04b73c03e35c0e228e9dba14300c for the previous implementation. | ||
with: | ||
aws_region: us-east-1 | ||
aws_replication_region: us-west-2 | ||
aws_s3_terraform_state_object_key: production.tfstate | ||
environment_name: prod | ||
secrets: | ||
aws_assume_role_arn: ${{ secrets.AWS_ASSUME_ROLE_ARN }} | ||
aws_s3_terraform_state_bucket_name: ${{ secrets.AWS_S3_TERRAFORM_STATE_BUCKET_NAME }} |
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 @@ | ||
1.6.4 |
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,10 @@ | ||
# Unreleased | ||
|
||
# 0.1.0 | ||
|
||
* CloudWatch log group encryption using KMS CMK | ||
* Build improvements to leverage callable deployment workflow and explicity manifests for development and production environments | ||
* ECS cluster, service, task and ALB running vanilla nginx image | ||
* KMS customer managed key provisioning with multi-region replication | ||
* VPC network provisioning | ||
* Github Actions Terraform workflow definition and integration |
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 @@ | ||
data "aws_caller_identity" "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,65 @@ | ||
# Security group for the ALB accepting HTTP connections on port 80 | ||
# | ||
# TODO: implement SSL encrypted traffic and redirect HTTP to HTTPS | ||
resource "aws_security_group" "alb" { | ||
name = "${local.namespace}-alb" | ||
vpc_id = aws_vpc.vpc.id | ||
} | ||
|
||
resource "aws_security_group_rule" "alb_ingress_http" { | ||
cidr_blocks = ["0.0.0.0/0"] | ||
description = "Allow public HTTP traffic" | ||
from_port = 80 | ||
ipv6_cidr_blocks = ["::/0"] | ||
protocol = "tcp" | ||
security_group_id = aws_security_group.alb.id | ||
to_port = 80 | ||
type = "ingress" | ||
} | ||
|
||
resource "aws_security_group_rule" "alb_egress_all" { | ||
cidr_blocks = ["0.0.0.0/0"] | ||
description = "Allow all outbound traffic" | ||
from_port = 0 | ||
ipv6_cidr_blocks = ["::/0"] | ||
protocol = -1 | ||
security_group_id = aws_security_group.alb.id | ||
to_port = 0 | ||
type = "egress" | ||
} | ||
|
||
resource "aws_lb_target_group" "alb" { | ||
name = local.namespace | ||
port = 80 | ||
protocol = "HTTP" | ||
target_type = "ip" | ||
|
||
health_check { | ||
# TODO: review health check | ||
enabled = true | ||
path = "/" | ||
port = 80 | ||
protocol = "HTTP" | ||
} | ||
|
||
vpc_id = aws_vpc.vpc.id | ||
} | ||
|
||
resource "aws_lb" "alb" { | ||
name = local.namespace | ||
internal = false | ||
load_balancer_type = "application" | ||
security_groups = [aws_security_group.alb.id] | ||
subnets = local.public_subnet_ids | ||
} | ||
|
||
resource "aws_lb_listener" "alb" { | ||
load_balancer_arn = aws_lb.alb.id | ||
port = 80 | ||
protocol = "HTTP" | ||
|
||
default_action { | ||
target_group_arn = aws_lb_target_group.alb.id | ||
type = "forward" | ||
} | ||
} |
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,128 @@ | ||
# Encrypt log data with KMS CMK: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/encrypt-log-data-kms.html | ||
resource "aws_cloudwatch_log_group" "hello_world" { | ||
kms_key_id = aws_kms_key.primary.arn | ||
name = "/ecs/${local.namespace}/hello-world" | ||
retention_in_days = 30 | ||
} | ||
|
||
resource "aws_ecs_cluster" "cluster" { | ||
name = local.namespace | ||
} | ||
|
||
# Task execution assumed role | ||
data "aws_iam_policy_document" "ecs_task_assume_role" { | ||
statement { | ||
actions = ["sts:AssumeRole"] | ||
effect = "Allow" | ||
principals { | ||
identifiers = ["ecs-tasks.amazonaws.com"] | ||
type = "Service" | ||
} | ||
} | ||
} | ||
|
||
resource "aws_iam_role" "ecs_task_execution" { | ||
name = "${local.namespace}_ecs_task_execution" | ||
assume_role_policy = data.aws_iam_policy_document.ecs_task_assume_role.json | ||
} | ||
|
||
# Use the AWS-provided managed role for basic logging and ECR repository permissions | ||
resource "aws_iam_role_policy_attachment" "legacy_listener_aws_task_execution_role_policy" { | ||
role = aws_iam_role.ecs_task_execution.name | ||
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" | ||
} | ||
|
||
# Task definition featuring | ||
# * CloudWatch logs integration | ||
resource "aws_ecs_task_definition" "hello_world" { | ||
container_definitions = jsonencode([ | ||
{ | ||
# TODO: parameterize cpu, or remove this value because it is not required | ||
# for Fargate containers when assigned at the task level and we only have one task | ||
cpu = 256 | ||
# TODO: specify image tag and eventually parameterize | ||
image = "nginx" | ||
logConfiguration = { | ||
logDriver = "awslogs" | ||
options = { | ||
"awslogs-group" : aws_cloudwatch_log_group.hello_world.name | ||
"awslogs-region" : var.aws_region | ||
"awslogs-stream-prefix" : local.namespace | ||
} | ||
}, | ||
# TODO: parameterize memory, or remove this value because it is not required | ||
# for Fargate containers when assigned at the task level and we only have one task | ||
memory = 512 | ||
name = "hello-world" | ||
networkMode = "FARGATE" | ||
portMappings = [ | ||
{ | ||
hostPort = 80, | ||
containerPort = 80, | ||
protocol = "tcp" | ||
} | ||
] | ||
} | ||
]) | ||
|
||
# TODO: parameterize cpu | ||
cpu = 256 | ||
execution_role_arn = aws_iam_role.ecs_task_execution.arn | ||
family = "${local.namespace}-hello-world" | ||
# TODO: parameterize memory | ||
memory = 512 | ||
network_mode = "awsvpc" | ||
requires_compatibilities = ["FARGATE"] | ||
} | ||
|
||
# Security group for the hello-world ECS service accepts HTTP | ||
# connections from the ALB security group | ||
resource "aws_security_group" "app" { | ||
name = "${local.namespace}-app" | ||
vpc_id = aws_vpc.vpc.id | ||
} | ||
|
||
resource "aws_security_group_rule" "app_ingress_http" { | ||
description = "Allow HTTP from ALB" | ||
from_port = 80 | ||
protocol = "tcp" | ||
security_group_id = aws_security_group.app.id | ||
source_security_group_id = aws_security_group.alb.id | ||
to_port = 80 | ||
type = "ingress" | ||
} | ||
|
||
resource "aws_security_group_rule" "app_egress_all" { | ||
cidr_blocks = ["0.0.0.0/0"] | ||
description = "Allow all outbound traffic" | ||
from_port = 0 | ||
ipv6_cidr_blocks = ["::/0"] | ||
protocol = -1 | ||
security_group_id = aws_security_group.app.id | ||
to_port = 0 | ||
type = "egress" | ||
} | ||
|
||
# Hello World ECS service | ||
resource "aws_ecs_service" "hello_world" { | ||
name = "${local.namespace}-hello-world" | ||
|
||
cluster = aws_ecs_cluster.cluster.id | ||
desired_count = 1 | ||
launch_type = "FARGATE" | ||
|
||
# TODO: consider service encrypted internal traffic between | ||
# ALB and ECS container on 443 - requires self-signed cert | ||
load_balancer { | ||
target_group_arn = aws_lb_target_group.alb.arn | ||
container_name = "hello-world" | ||
container_port = 80 | ||
} | ||
|
||
network_configuration { | ||
security_groups = [aws_security_group.app.id] | ||
subnets = local.private_subnet_ids | ||
} | ||
|
||
task_definition = aws_ecs_task_definition.hello_world.arn | ||
} |
Oops, something went wrong.