Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/terraform-checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,27 @@ jobs:
id: fmt
run: terraform test

validateExamples:
name: Terraform Validate Examples
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.6.0"

- name: Validate all example folders
run: |
for dir in examples/*/; do
echo "Validating $dir"
terraform -chdir="$dir" init -input=false > /dev/null
terraform -chdir="$dir" validate
done

collectInputs:
name: Collect workflow inputs
needs: test
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ Terraform module to deploy production-ready applications and services on an exis
| <a name="input_create_s3_bucket_for_alb_logging"></a> [create\_s3\_bucket\_for\_alb\_logging](#input\_create\_s3\_bucket\_for\_alb\_logging) | (Optional) Creates S3 bucket for storing ALB Access and Connection Logs. | `bool` | `true` | no |
| <a name="input_default_capacity_providers_strategies"></a> [default\_capacity\_providers\_strategies](#input\_default\_capacity\_providers\_strategies) | (Optional) Set of capacity provider strategies to use by default for the cluster. | `any` | `[]` | no |
| <a name="input_load_balancer"></a> [load\_balancer](#input\_load\_balancer) | Configuration for the Application Load Balancer. | <pre>object({<br/> name = optional(string)<br/> internal = optional(bool, false)<br/> subnets_ids = optional(list(string), [])<br/> security_groups_ids = optional(list(string), [])<br/> preserve_host_header = optional(bool)<br/> enable_deletion_protection = optional(bool, false)<br/> access_logs = optional(any, null)<br/> connection_logs = optional(any, null)<br/> target_groups = optional(any, {})<br/> listeners = optional(any, {})<br/> listener_rules = optional(any, {})<br/> tags = optional(map(string), {})<br/> })</pre> | `{}` | no |
| <a name="input_region"></a> [region](#input\_region) | (Optional) AWS region to create resources in. | `string` | `null` | no |
| <a name="input_route53_assume_role_arn"></a> [route53\_assume\_role\_arn](#input\_route53\_assume\_role\_arn) | (Optional) ARN of the role to assume for Route53 operations. | `string` | `null` | no |
| <a name="input_s3_bucket_force_destroy"></a> [s3\_bucket\_force\_destroy](#input\_s3\_bucket\_force\_destroy) | (Optional, Default:false) Boolean that indicates all objects (including any locked objects) should be deleted from the bucket when the bucket is destroyed so that the bucket can be destroyed without error. | `bool` | `false` | no |
| <a name="input_s3_bucket_name"></a> [s3\_bucket\_name](#input\_s3\_bucket\_name) | (Optional, Forces new resource) Name of the bucket. | `string` | `null` | no |
Expand Down
67 changes: 67 additions & 0 deletions examples/cross-account/.header.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# ECS Deployment Complete

Configuration in this directory creates:

- ECS Service in a pre-configured ECS Cluster and corresponding ECS Capacity Providers
- Internet-facing Application Load Balancer to access the deployed services with S3 bucket for storing access and connection logs, and
- ACM to generate and validate an Amazon-issued certificate for a base domain

## Example `tfvars` Configuration

```tf
vpc_id = "vpc-0123456789abcdefg"
service_network_configuration_security_groups = ["sg-0123456789abcdefg"]
private_subnets = ["subnet-0123456789abcdefg", "subnet-0123456789abcdefg"]
public_subnets = ["subnet-0123456789abcdefg", "subnet-0123456789abcdefg"]
cluster_name = "your-cluster-name"
container_name = "your-container-name"
service_desired_count = 123
container_image = "your-container-image:version"
container_port = 123
container_cpu = 123
container_memory = 123
container_essential = true
container_port_mappings = [
{
name = "your-port-mapping-name"
containerPort = 123
hostPort = 123
protocol = "your-port-mapping-protocol"
}
]
container_readonly_root_filesystem = false
asg_arn = "arn:aws:autoscaling:your-region:01234567890:autoScalingGroup:abcdefgh-ijkl-mnop-qrst-uvwxyz012345:autoScalingGroupName/your-autoscaling-group-name"
capacity_provider_name = "your-capacity-provider-name"
capacity_provider_managed_scaling = {
status = "ENABLED"
target_capacity = 123
minimum_scaling_step_size = 123
maximum_scaling_step_size = 123
}
alb_name = "your-alb-name"
target_group_name = "your-alb-target-group-name"
target_group_protocol = "HTTP"
target_group_health_check = {
path = "/path/to/health/check"
}
listener_port = 123
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
security_group_alb = "your-alb-sg-name"
s3_bucket_force_destroy = true
base_domain = "example.com"
domain_name = "your-service.example.com"
region = "us-east-1"
route53_assume_role_arn = "arn:aws:iam::123456789012:role/Route53CrossAccountRole"
```

## Usage

To run this example, you will need to execute the commands:

```bash
terraform init
terraform plan
terraform apply
```

Please note that this example may create resources that can incur monetary charges on your AWS bill. You can run `terraform destroy` when you no longer need the resources.
170 changes: 170 additions & 0 deletions examples/cross-account/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
<!-- BEGIN_TF_DOCS -->
# ECS Deployment Complete



Configuration in this directory creates:

- ECS Service in a pre-configured ECS Cluster and corresponding ECS Capacity Providers
- Internet-facing Application Load Balancer to access the deployed services with S3 bucket for storing access and connection logs, and
- ACM to generate and validate an Amazon-issued certificate for a base domain


For cross-account Route53 validation, configure the alias provider with assume_role and pass it to the module as:
providers = { aws = aws, aws.cross_account_provider = aws.cross_account_provider }.
Ensure the cross_account_provider includes the assume_role block pointing to the Route53 account role.
provider "aws" { alias = "cross_account_provider" ... assume_role { role_arn = "<role>" } }

## Prerequisites

**Create an IAM Role in the Hosted Zone Account (Account B)**
If you want to validate ACM certificates across accounts, ensure that an IAM role exists in Account B (Route53 Hosted Zone account) that grants cross-account access to manage Route53 DNS records.
This role must allow Account A (where ACM and your application resources are created) to assume it.
It should include permissions such as:

route53:ChangeResourceRecordSets
route53:ListHostedZonesByName
route53:ListResourceRecordSets

And a trust policy allowing Account A to assume the role.


## Example `tfvars` Configuration

```tf
vpc_id = "vpc-0123456789abcdefg"
service_network_configuration_security_groups = ["sg-0123456789abcdefg"]
private_subnets = ["subnet-0123456789abcdefg", "subnet-0123456789abcdefg"]
public_subnets = ["subnet-0123456789abcdefg", "subnet-0123456789abcdefg"]

cluster_name = "your-cluster-name"
container_name = "your-container-name"
service_desired_count = 123
container_image = "your-container-image:version"
container_port = 123
container_cpu = 123
container_memory = 123
container_essential = true
container_port_mappings = [
{
name = "your-port-mapping-name"
containerPort = 123
hostPort = 123
protocol = "your-port-mapping-protocol"
}
]
container_readonly_root_filesystem = false

asg_arn = "arn:aws:autoscaling:your-region:01234567890:autoScalingGroup:abcdefgh-ijkl-mnop-qrst-uvwxyz012345:autoScalingGroupName/your-autoscaling-group-name"
capacity_provider_name = "your-capacity-provider-name"
capacity_provider_managed_scaling = {
status = "ENABLED"
target_capacity = 123
minimum_scaling_step_size = 123
maximum_scaling_step_size = 123
}

alb_name = "your-alb-name"
target_group_name = "your-alb-target-group-name"
target_group_protocol = "HTTP"
target_group_health_check = {
path = "/path/to/health/check"
}
listener_port = 123
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
security_group_alb = "your-alb-sg-name"

s3_bucket_force_destroy = true

base_domain = "example.com"
domain_name = "your-service.example.com"
region = "us-east-1"
route53_assume_role_arn = "arn:aws:iam::123456789012:role/Route53CrossAccountRole"
```

## Usage

To run this example, you will need to execute the commands:

```bash
terraform init
terraform plan
terraform apply
```

Please note that this example may create resources that can incur monetary charges on your AWS bill. You can run `terraform destroy` when you no longer need the resources.

## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.6.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | 5.62.0 |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_ecs_deployment"></a> [ecs\_deployment](#module\_ecs\_deployment) | ../../ | n/a |

## Resources

| Name | Type |
|------|------|
| [aws_security_group.alb_allow_all](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
| [aws_route53_zone.base_domain](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_alb_name"></a> [alb\_name](#input\_alb\_name) | Name of the application load balancer | `string` | n/a | yes |
| <a name="input_asg_arn"></a> [asg\_arn](#input\_asg\_arn) | ARN of the Auto Scaling group | `string` | n/a | yes |
| <a name="input_base_domain"></a> [base\_domain](#input\_base\_domain) | Base domain for ACM | `string` | n/a | yes |
| <a name="input_capacity_provider_managed_scaling"></a> [capacity\_provider\_managed\_scaling](#input\_capacity\_provider\_managed\_scaling) | Managed scaling configuration for the Capacity Provider | `any` | n/a | yes |
| <a name="input_capacity_provider_name"></a> [capacity\_provider\_name](#input\_capacity\_provider\_name) | Name of the Capacity Provider | `string` | n/a | yes |
| <a name="input_cluster_name"></a> [cluster\_name](#input\_cluster\_name) | Name of the ECS cluster | `string` | n/a | yes |
| <a name="input_container_cpu"></a> [container\_cpu](#input\_container\_cpu) | CPU units to allocate to the container | `number` | n/a | yes |
| <a name="input_container_essential"></a> [container\_essential](#input\_container\_essential) | Essential flag for the container | `bool` | n/a | yes |
| <a name="input_container_image"></a> [container\_image](#input\_container\_image) | Image of the container | `string` | n/a | yes |
| <a name="input_container_memory"></a> [container\_memory](#input\_container\_memory) | Memory in MB to allocate to the container | `number` | n/a | yes |
| <a name="input_container_name"></a> [container\_name](#input\_container\_name) | Name of the container | `string` | n/a | yes |
| <a name="input_container_port"></a> [container\_port](#input\_container\_port) | Port on which the container will listen | `number` | n/a | yes |
| <a name="input_container_port_mappings"></a> [container\_port\_mappings](#input\_container\_port\_mappings) | Port mappings for the container | `any` | n/a | yes |
| <a name="input_container_readonly_root_filesystem"></a> [container\_readonly\_root\_filesystem](#input\_container\_readonly\_root\_filesystem) | Whether the root filesystem is readonly for the container | `bool` | n/a | yes |
| <a name="input_domain_name"></a> [domain\_name](#input\_domain\_name) | Domain name for ACM | `string` | n/a | yes |
| <a name="input_listener_port"></a> [listener\_port](#input\_listener\_port) | Port for the ALB listener | `number` | n/a | yes |
| <a name="input_private_subnets"></a> [private\_subnets](#input\_private\_subnets) | List of private subnet IDs | `list(string)` | n/a | yes |
| <a name="input_public_subnets"></a> [public\_subnets](#input\_public\_subnets) | List of public subnet IDs | `list(string)` | n/a | yes |
| <a name="input_s3_bucket_force_destroy"></a> [s3\_bucket\_force\_destroy](#input\_s3\_bucket\_force\_destroy) | (Optional, Default:false) Boolean that indicates all objects (including any locked objects) should be deleted from the bucket when the bucket is destroyed so that the bucket can be destroyed without error. | `bool` | n/a | yes |
| <a name="input_security_group_alb"></a> [security\_group\_alb](#input\_security\_group\_alb) | Name of the security group for ALB | `string` | n/a | yes |
| <a name="input_service_desired_count"></a> [service\_desired\_count](#input\_service\_desired\_count) | Desired count for the ECS Service | `number` | n/a | yes |
| <a name="input_service_network_configuration_security_groups"></a> [service\_network\_configuration\_security\_groups](#input\_service\_network\_configuration\_security\_groups) | Security Groups for the ECS Service's Network Configuration | `list(string)` | n/a | yes |
| <a name="input_ssl_policy"></a> [ssl\_policy](#input\_ssl\_policy) | SSL policy for the ALB | `string` | n/a | yes |
| <a name="input_target_group_health_check"></a> [target\_group\_health\_check](#input\_target\_group\_health\_check) | Health check configuration for the target group | `any` | n/a | yes |
| <a name="input_target_group_name"></a> [target\_group\_name](#input\_target\_group\_name) | Name of the target group | `string` | n/a | yes |
| <a name="input_target_group_protocol"></a> [target\_group\_protocol](#input\_target\_group\_protocol) | Protocol to use with the target group | `string` | n/a | yes |
| <a name="input_vpc_id"></a> [vpc\_id](#input\_vpc\_id) | VPC ID where the resources will be deployed | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_acm_amazon_issued_certificate_arn"></a> [acm\_amazon\_issued\_certificate\_arn](#output\_acm\_amazon\_issued\_certificate\_arn) | ARN of the ACM Amazon-issued certificate for the base domain |
| <a name="output_alb_allow_all_sg_id"></a> [alb\_allow\_all\_sg\_id](#output\_alb\_allow\_all\_sg\_id) | ID of the Security Group for Application Load Balancer to allow all traffic from any source |
| <a name="output_alb_arn"></a> [alb\_arn](#output\_alb\_arn) | ARN of the Application Load Balancer ECS Service |
| <a name="output_ecs_capacity_provider_arn"></a> [ecs\_capacity\_provider\_arn](#output\_ecs\_capacity\_provider\_arn) | ARN of the ECS Capacity Provider |
| <a name="output_ecs_capacity_provider_id"></a> [ecs\_capacity\_provider\_id](#output\_ecs\_capacity\_provider\_id) | Identifier of the ECS Capacity Provider |
| <a name="output_ecs_cluster_capacity_providers_id"></a> [ecs\_cluster\_capacity\_providers\_id](#output\_ecs\_cluster\_capacity\_providers\_id) | Identifier of the ECS Cluster Capacity Providers |
| <a name="output_ecs_service_arn"></a> [ecs\_service\_arn](#output\_ecs\_service\_arn) | ARN of the ECS Service |
| <a name="output_listener_arn"></a> [listener\_arn](#output\_listener\_arn) | ARN of the ALB Listener forwarding to container instances |
| <a name="output_listener_id"></a> [listener\_id](#output\_listener\_id) | Identifier of the ALB Listener forwarding to container instances |
| <a name="output_target_group_arn"></a> [target\_group\_arn](#output\_target\_group\_arn) | ARN of the Target Group instances |
| <a name="output_target_group_id"></a> [target\_group\_id](#output\_target\_group\_id) | Identifier of the Target Group instances |
| <a name="output_task_definition_arn"></a> [task\_definition\_arn](#output\_task\_definition\_arn) | ARN of the ECS Task Definition |
<!-- END_TF_DOCS -->
Loading