Terraform module to create AWS ECS resources 🇺🇦
See the codeTerraform module which creates ECS (Elastic Container Service) resources on AWS.
For more details see the design doc
This project supports creating resources through individual sub-modules, or through a single module that creates both the cluster and service resources. See the respective sub-module directory for more details and example usage.
module "ecs" {
source = "terraform-aws-modules/ecs/aws"
cluster_name = "ecs-integrated"
cluster_configuration = {
execute_command_configuration = {
logging = "OVERRIDE"
log_configuration = {
cloud_watch_log_group_name = "/aws/ecs/aws-ec2"
}
}
}
# Cluster capacity providers
cluster_capacity_providers = ["FARGATE", "FARGATE_SPOT"]
default_capacity_provider_strategy = {
FARGATE = {
weight = 50
base = 20
}
FARGATE_SPOT = {
weight = 50
}
}
services = {
ecsdemo-frontend = {
cpu = 1024
memory = 4096
# Container definition(s)
container_definitions = {
fluent-bit = {
cpu = 512
memory = 1024
essential = true
image = "906394416424.dkr.ecr.us-west-2.amazonaws.com/aws-for-fluent-bit:stable"
firelensConfiguration = {
type = "fluentbit"
}
memoryReservation = 50
}
ecs-sample = {
cpu = 512
memory = 1024
essential = true
image = "public.ecr.aws/aws-containers/ecsdemo-frontend:776fd50"
portMappings = [
{
name = "ecs-sample"
containerPort = 80
protocol = "tcp"
}
]
# Example image used requires access to write to root filesystem
readonlyRootFilesystem = false
dependsOn = [{
containerName = "fluent-bit"
condition = "START"
}]
enable_cloudwatch_logging = false
logConfiguration = {
logDriver = "awsfirelens"
options = {
Name = "firehose"
region = "eu-west-1"
delivery_stream = "my-stream"
log-driver-buffer-limit = "2097152"
}
}
memoryReservation = 100
}
}
service_connect_configuration = {
namespace = "example"
service = [{
client_alias = {
port = 80
dns_name = "ecs-sample"
}
port_name = "ecs-sample"
discovery_name = "ecs-sample"
}]
}
load_balancer = {
service = {
target_group_arn = "arn:aws:elasticloadbalancing:eu-west-1:1234567890:targetgroup/bluegreentarget1/209a844cd01825a4"
container_name = "ecs-sample"
container_port = 80
}
}
subnet_ids = ["subnet-abcde012", "subnet-bcde012a", "subnet-fghi345a"]
security_group_ingress_rules = {
alb_3000 = {
description = "Service port"
from_port = local.container_port
ip_protocol = "tcp"
referenced_security_group_id = "sg-12345678"
}
}
security_group_egress_rules = {
all = {
ip_protocol = "-1"
cidr_ipv4 = "0.0.0.0/0"
}
}
}
}
tags = {
Environment = "Development"
Project = "Example"
}
}
A few requests come up again and again and cannot be implemented by this
module, or by any module: Terraform requires lifecycle arguments to be
literal values inside the resource block.
hashicorp/terraform#18367
has been open since 2018,
#22544 since 2019, and
opentofu/opentofu#1329 is
the same request for OpenTofu.
ignore_task_definition_changes = true (an existing service
moves to a new state address, so add a moved block), or have the pipeline
update the Terraform configuration instead of the ECS API.Compliance.tf serves this module with
these rules applied at download time, on top of whatever your organization
already has enabled there. Inputs and outputs do not change; the source line
does. Drop the version argument and pin the release you use by adding
&version= and that release number to the URL. To get started, register a free
compliance.tf account and configure an access token:
source = "https://registry.compliance.tf/terraform-aws-modules/ecs/aws?add_rules=lifecycle_ignore_deployed_artifacts"
The full workaround for each item above, and the exact diff each rule makes, are in the compliance.tf docs for this module.
Disclosure: written by this module's maintainer, who also builds compliance.tf.
No providers.
No resources.
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| capacity_providers | Map of capacity provider definitions to create for the cluster | map(object({ | null | no |
| cloudwatch_log_group_class | Specified the log class of the log group. Possible values are: STANDARD or INFREQUENT_ACCESS | string | null | no |
| cloudwatch_log_group_kms_key_id | If a KMS Key ARN is set, this key will be used to encrypt the corresponding log group. Please be sure that the KMS Key has an appropriate key policy (https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/encrypt-log-data-kms.html) | string | null | no |
| cloudwatch_log_group_name | Custom name of CloudWatch Log Group for ECS cluster | string | null | no |
| cloudwatch_log_group_retention_in_days | Number of days to retain log events | number | 90 | no |
| cloudwatch_log_group_tags | A map of additional tags to add to the log group created | map(string) | {} | no |
| cluster_capacity_providers | List of capacity provider names to associate with the ECS cluster. Note: any capacity providers created by this module will be automatically added | list(string) | [] | no |
| cluster_configuration | The execute command configuration for the cluster | object({ | { | no |
| cluster_name | Name of the cluster (up to 255 letters, numbers, hyphens, and underscores) | string | "" | no |
| cluster_service_connect_defaults | Configures a default Service Connect namespace | object({ | null | no |
| cluster_setting | List of configuration block(s) with cluster settings. For example, this can be used to enable CloudWatch Container Insights for a cluster | list(object({ | [ | no |
| cluster_tags | A map of additional tags to add to the cluster | map(string) | {} | no |
| create | Determines whether resources will be created (affects all resources) | bool | true | no |
| create_cloudwatch_log_group | Determines whether a log group is created by this module for the cluster logs. If not, AWS will automatically create one if logging is enabled | bool | true | no |
| create_infrastructure_iam_role | Determines whether the ECS infrastructure IAM role should be created | bool | true | no |
| create_node_iam_instance_profile | Determines whether an IAM instance profile is created or to use an existing IAM instance profile | bool | true | no |
| create_security_group | Determines if a security group is created | bool | true | no |
| create_task_exec_iam_role | Determines whether the ECS task definition IAM role should be created | bool | false | no |
| create_task_exec_policy | Determines whether the ECS task definition IAM policy should be created. This includes permissions included in AmazonECSTaskExecutionRolePolicy as well as access to secrets and SSM parameters | bool | true | no |
| default_capacity_provider_strategy | Map of default capacity provider strategy definitions to use for the cluster | map(object({ | null | no |
| disable_v7_default_name_description | [DEPRECATED - will be removed in v8.0] Determines whether to disable the default postfix added to resource names and descriptions added in v7.0 | bool | false | no |
| infrastructure_iam_role_description | Description of the role | string | null | no |
| infrastructure_iam_role_name | Name to use on IAM role created | string | null | no |
| infrastructure_iam_role_override_policy_documents | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank sids will override statements with the same sid | list(string) | [] | no |
| infrastructure_iam_role_path | IAM role path | string | null | no |
| infrastructure_iam_role_permissions_boundary | ARN of the policy that is used to set the permissions boundary for the IAM role | string | null | no |
| infrastructure_iam_role_source_policy_documents | List of IAM policy documents that are merged together into the exported document. Statements must have unique sids | list(string) | [] | no |
| infrastructure_iam_role_statements | A map of IAM policy statements for custom permission usage | map(object({ | null | no |
| infrastructure_iam_role_tags | A map of additional tags to add to the IAM role created | map(string) | {} | no |
| infrastructure_iam_role_use_name_prefix | Determines whether the IAM role name (iam_role_name) is used as a prefix | bool | true | no |
| node_iam_role_additional_policies | Additional policies to be added to the IAM role | map(string) | {} | no |
| node_iam_role_description | Description of the role | string | "ECS Managed Instances node IAM role" | no |
| node_iam_role_name | Name to use on IAM role/instance profile created | string | null | no |
| node_iam_role_override_policy_documents | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank sids will override statements with the same sid | list(string) | [] | no |
| node_iam_role_path | IAM role/instance profile path | string | null | no |
| node_iam_role_permissions_boundary | ARN of the policy that is used to set the permissions boundary for the IAM role | string | null | no |
| node_iam_role_source_policy_documents | List of IAM policy documents that are merged together into the exported document. Statements must have unique sids | list(string) | [] | no |
| node_iam_role_statements | A map of IAM policy statements for custom permission usage | map(object({ | null | no |
| node_iam_role_tags | A map of additional tags to add to the IAM role/instance profile created | map(string) | {} | no |
| node_iam_role_use_name_prefix | Determines whether the IAM role/instance profile name (node_iam_role_name) is used as a prefix | bool | true | no |
| region | Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration | string | null | no |
| security_group_description | Description of the security group created | string | null | no |
| security_group_egress_rules | Security group egress rules to add to the security group created | map(object({ | { | no |
| security_group_ingress_rules | Security group ingress rules to add to the security group created | map(object({ | {} | no |
| security_group_name | Name to use on security group created | string | null | no |
| security_group_tags | A map of additional tags to add to the security group created | map(string) | {} | no |
| security_group_use_name_prefix | Determines whether the security group name (security_group_name) is used as a prefix | bool | true | no |
| services | Map of service definitions to create | map(object({ | null | no |
| tags | A map of tags to add to all resources | map(string) | {} | no |
| task_exec_iam_role_description | Description of the role | string | null | no |
| task_exec_iam_role_name | Name to use on IAM role created | string | null | no |
| task_exec_iam_role_path | IAM role path | string | null | no |
| task_exec_iam_role_permissions_boundary | ARN of the policy that is used to set the permissions boundary for the IAM role | string | null | no |
| task_exec_iam_role_policies | Map of IAM role policy ARNs to attach to the IAM role | map(string) | {} | no |
| task_exec_iam_role_tags | A map of additional tags to add to the IAM role created | map(string) | {} | no |
| task_exec_iam_role_use_name_prefix | Determines whether the IAM role name (task_exec_iam_role_name) is used as a prefix | bool | true | no |
| task_exec_iam_statements | A map of IAM policy statements for custom permission usage | map(object({ | null | no |
| task_exec_secret_arns | List of SecretsManager secret ARNs the task execution role will be permitted to get/read | list(string) | [] | no |
| task_exec_ssm_param_arns | List of SSM parameter ARNs the task execution role will be permitted to get/read | list(string) | [] | no |
| vpc_id | The ID of the VPC where the security group will be created | string | null | no |
| Name | Description |
|---|---|
| capacity_providers | Map of autoscaling capacity providers created and their attributes |
| cloudwatch_log_group_arn | ARN of CloudWatch log group created |
| cloudwatch_log_group_name | Name of CloudWatch log group created |
| cluster_arn | ARN that identifies the cluster |
| cluster_capacity_providers | Map of cluster capacity providers attributes |
| cluster_id | ID that identifies the cluster |
| cluster_name | Name that identifies the cluster |
| infrastructure_iam_role_arn | The Amazon Resource Name (ARN) specifying the IAM role |
| infrastructure_iam_role_name | IAM role name |
| infrastructure_iam_role_unique_id | Stable and unique string identifying the IAM role |
| node_iam_instance_profile_arn | ARN assigned by AWS to the instance profile |
| node_iam_instance_profile_id | Instance profile's ID |
| node_iam_instance_profile_unique | Stable and unique string identifying the IAM instance profile |
| node_iam_role_arn | The Amazon Resource Name (ARN) specifying the IAM role |
| node_iam_role_name | IAM role name |
| node_iam_role_unique_id | Stable and unique string identifying the IAM role |
| services | Map of services created and their attributes |
| task_exec_iam_role_arn | Task execution IAM role ARN |
| task_exec_iam_role_name | Task execution IAM role name |
| task_exec_iam_role_unique_id | Stable and unique string identifying the task execution IAM role |
Module is maintained by Anton Babenko with help from these awesome contributors.
Apache-2.0 Licensed. See LICENSE.
208 followers · starred Jan 2026
151 followers · starred Feb 2021
359 followers · starred Jul 2021
65 followers · starred Dec 2022
Terraform module to create AWS ECS resources 🇺🇦
See the codeTerraform module which creates ECS (Elastic Container Service) resources on AWS.
For more details see the design doc
This project supports creating resources through individual sub-modules, or through a single module that creates both the cluster and service resources. See the respective sub-module directory for more details and example usage.
module "ecs" {
source = "terraform-aws-modules/ecs/aws"
cluster_name = "ecs-integrated"
cluster_configuration = {
execute_command_configuration = {
logging = "OVERRIDE"
log_configuration = {
cloud_watch_log_group_name = "/aws/ecs/aws-ec2"
}
}
}
# Cluster capacity providers
cluster_capacity_providers = ["FARGATE", "FARGATE_SPOT"]
default_capacity_provider_strategy = {
FARGATE = {
weight = 50
base = 20
}
FARGATE_SPOT = {
weight = 50
}
}
services = {
ecsdemo-frontend = {
cpu = 1024
memory = 4096
# Container definition(s)
container_definitions = {
fluent-bit = {
cpu = 512
memory = 1024
essential = true
image = "906394416424.dkr.ecr.us-west-2.amazonaws.com/aws-for-fluent-bit:stable"
firelensConfiguration = {
type = "fluentbit"
}
memoryReservation = 50
}
ecs-sample = {
cpu = 512
memory = 1024
essential = true
image = "public.ecr.aws/aws-containers/ecsdemo-frontend:776fd50"
portMappings = [
{
name = "ecs-sample"
containerPort = 80
protocol = "tcp"
}
]
# Example image used requires access to write to root filesystem
readonlyRootFilesystem = false
dependsOn = [{
containerName = "fluent-bit"
condition = "START"
}]
enable_cloudwatch_logging = false
logConfiguration = {
logDriver = "awsfirelens"
options = {
Name = "firehose"
region = "eu-west-1"
delivery_stream = "my-stream"
log-driver-buffer-limit = "2097152"
}
}
memoryReservation = 100
}
}
service_connect_configuration = {
namespace = "example"
service = [{
client_alias = {
port = 80
dns_name = "ecs-sample"
}
port_name = "ecs-sample"
discovery_name = "ecs-sample"
}]
}
load_balancer = {
service = {
target_group_arn = "arn:aws:elasticloadbalancing:eu-west-1:1234567890:targetgroup/bluegreentarget1/209a844cd01825a4"
container_name = "ecs-sample"
container_port = 80
}
}
subnet_ids = ["subnet-abcde012", "subnet-bcde012a", "subnet-fghi345a"]
security_group_ingress_rules = {
alb_3000 = {
description = "Service port"
from_port = local.container_port
ip_protocol = "tcp"
referenced_security_group_id = "sg-12345678"
}
}
security_group_egress_rules = {
all = {
ip_protocol = "-1"
cidr_ipv4 = "0.0.0.0/0"
}
}
}
}
tags = {
Environment = "Development"
Project = "Example"
}
}
A few requests come up again and again and cannot be implemented by this
module, or by any module: Terraform requires lifecycle arguments to be
literal values inside the resource block.
hashicorp/terraform#18367
has been open since 2018,
#22544 since 2019, and
opentofu/opentofu#1329 is
the same request for OpenTofu.
ignore_task_definition_changes = true (an existing service
moves to a new state address, so add a moved block), or have the pipeline
update the Terraform configuration instead of the ECS API.Compliance.tf serves this module with
these rules applied at download time, on top of whatever your organization
already has enabled there. Inputs and outputs do not change; the source line
does. Drop the version argument and pin the release you use by adding
&version= and that release number to the URL. To get started, register a free
compliance.tf account and configure an access token:
source = "https://registry.compliance.tf/terraform-aws-modules/ecs/aws?add_rules=lifecycle_ignore_deployed_artifacts"
The full workaround for each item above, and the exact diff each rule makes, are in the compliance.tf docs for this module.
Disclosure: written by this module's maintainer, who also builds compliance.tf.
No providers.
No resources.
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| capacity_providers | Map of capacity provider definitions to create for the cluster | map(object({ | null | no |
| cloudwatch_log_group_class | Specified the log class of the log group. Possible values are: STANDARD or INFREQUENT_ACCESS | string | null | no |
| cloudwatch_log_group_kms_key_id | If a KMS Key ARN is set, this key will be used to encrypt the corresponding log group. Please be sure that the KMS Key has an appropriate key policy (https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/encrypt-log-data-kms.html) | string | null | no |
| cloudwatch_log_group_name | Custom name of CloudWatch Log Group for ECS cluster | string | null | no |
| cloudwatch_log_group_retention_in_days | Number of days to retain log events | number | 90 | no |
| cloudwatch_log_group_tags | A map of additional tags to add to the log group created | map(string) | {} | no |
| cluster_capacity_providers | List of capacity provider names to associate with the ECS cluster. Note: any capacity providers created by this module will be automatically added | list(string) | [] | no |
| cluster_configuration | The execute command configuration for the cluster | object({ | { | no |
| cluster_name | Name of the cluster (up to 255 letters, numbers, hyphens, and underscores) | string | "" | no |
| cluster_service_connect_defaults | Configures a default Service Connect namespace | object({ | null | no |
| cluster_setting | List of configuration block(s) with cluster settings. For example, this can be used to enable CloudWatch Container Insights for a cluster | list(object({ | [ | no |
| cluster_tags | A map of additional tags to add to the cluster | map(string) | {} | no |
| create | Determines whether resources will be created (affects all resources) | bool | true | no |
| create_cloudwatch_log_group | Determines whether a log group is created by this module for the cluster logs. If not, AWS will automatically create one if logging is enabled | bool | true | no |
| create_infrastructure_iam_role | Determines whether the ECS infrastructure IAM role should be created | bool | true | no |
| create_node_iam_instance_profile | Determines whether an IAM instance profile is created or to use an existing IAM instance profile | bool | true | no |
| create_security_group | Determines if a security group is created | bool | true | no |
| create_task_exec_iam_role | Determines whether the ECS task definition IAM role should be created | bool | false | no |
| create_task_exec_policy | Determines whether the ECS task definition IAM policy should be created. This includes permissions included in AmazonECSTaskExecutionRolePolicy as well as access to secrets and SSM parameters | bool | true | no |
| default_capacity_provider_strategy | Map of default capacity provider strategy definitions to use for the cluster | map(object({ | null | no |
| disable_v7_default_name_description | [DEPRECATED - will be removed in v8.0] Determines whether to disable the default postfix added to resource names and descriptions added in v7.0 | bool | false | no |
| infrastructure_iam_role_description | Description of the role | string | null | no |
| infrastructure_iam_role_name | Name to use on IAM role created | string | null | no |
| infrastructure_iam_role_override_policy_documents | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank sids will override statements with the same sid | list(string) | [] | no |
| infrastructure_iam_role_path | IAM role path | string | null | no |
| infrastructure_iam_role_permissions_boundary | ARN of the policy that is used to set the permissions boundary for the IAM role | string | null | no |
| infrastructure_iam_role_source_policy_documents | List of IAM policy documents that are merged together into the exported document. Statements must have unique sids | list(string) | [] | no |
| infrastructure_iam_role_statements | A map of IAM policy statements for custom permission usage | map(object({ | null | no |
| infrastructure_iam_role_tags | A map of additional tags to add to the IAM role created | map(string) | {} | no |
| infrastructure_iam_role_use_name_prefix | Determines whether the IAM role name (iam_role_name) is used as a prefix | bool | true | no |
| node_iam_role_additional_policies | Additional policies to be added to the IAM role | map(string) | {} | no |
| node_iam_role_description | Description of the role | string | "ECS Managed Instances node IAM role" | no |
| node_iam_role_name | Name to use on IAM role/instance profile created | string | null | no |
| node_iam_role_override_policy_documents | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank sids will override statements with the same sid | list(string) | [] | no |
| node_iam_role_path | IAM role/instance profile path | string | null | no |
| node_iam_role_permissions_boundary | ARN of the policy that is used to set the permissions boundary for the IAM role | string | null | no |
| node_iam_role_source_policy_documents | List of IAM policy documents that are merged together into the exported document. Statements must have unique sids | list(string) | [] | no |
| node_iam_role_statements | A map of IAM policy statements for custom permission usage | map(object({ | null | no |
| node_iam_role_tags | A map of additional tags to add to the IAM role/instance profile created | map(string) | {} | no |
| node_iam_role_use_name_prefix | Determines whether the IAM role/instance profile name (node_iam_role_name) is used as a prefix | bool | true | no |
| region | Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration | string | null | no |
| security_group_description | Description of the security group created | string | null | no |
| security_group_egress_rules | Security group egress rules to add to the security group created | map(object({ | { | no |
| security_group_ingress_rules | Security group ingress rules to add to the security group created | map(object({ | {} | no |
| security_group_name | Name to use on security group created | string | null | no |
| security_group_tags | A map of additional tags to add to the security group created | map(string) | {} | no |
| security_group_use_name_prefix | Determines whether the security group name (security_group_name) is used as a prefix | bool | true | no |
| services | Map of service definitions to create | map(object({ | null | no |
| tags | A map of tags to add to all resources | map(string) | {} | no |
| task_exec_iam_role_description | Description of the role | string | null | no |
| task_exec_iam_role_name | Name to use on IAM role created | string | null | no |
| task_exec_iam_role_path | IAM role path | string | null | no |
| task_exec_iam_role_permissions_boundary | ARN of the policy that is used to set the permissions boundary for the IAM role | string | null | no |
| task_exec_iam_role_policies | Map of IAM role policy ARNs to attach to the IAM role | map(string) | {} | no |
| task_exec_iam_role_tags | A map of additional tags to add to the IAM role created | map(string) | {} | no |
| task_exec_iam_role_use_name_prefix | Determines whether the IAM role name (task_exec_iam_role_name) is used as a prefix | bool | true | no |
| task_exec_iam_statements | A map of IAM policy statements for custom permission usage | map(object({ | null | no |
| task_exec_secret_arns | List of SecretsManager secret ARNs the task execution role will be permitted to get/read | list(string) | [] | no |
| task_exec_ssm_param_arns | List of SSM parameter ARNs the task execution role will be permitted to get/read | list(string) | [] | no |
| vpc_id | The ID of the VPC where the security group will be created | string | null | no |
| Name | Description |
|---|---|
| capacity_providers | Map of autoscaling capacity providers created and their attributes |
| cloudwatch_log_group_arn | ARN of CloudWatch log group created |
| cloudwatch_log_group_name | Name of CloudWatch log group created |
| cluster_arn | ARN that identifies the cluster |
| cluster_capacity_providers | Map of cluster capacity providers attributes |
| cluster_id | ID that identifies the cluster |
| cluster_name | Name that identifies the cluster |
| infrastructure_iam_role_arn | The Amazon Resource Name (ARN) specifying the IAM role |
| infrastructure_iam_role_name | IAM role name |
| infrastructure_iam_role_unique_id | Stable and unique string identifying the IAM role |
| node_iam_instance_profile_arn | ARN assigned by AWS to the instance profile |
| node_iam_instance_profile_id | Instance profile's ID |
| node_iam_instance_profile_unique | Stable and unique string identifying the IAM instance profile |
| node_iam_role_arn | The Amazon Resource Name (ARN) specifying the IAM role |
| node_iam_role_name | IAM role name |
| node_iam_role_unique_id | Stable and unique string identifying the IAM role |
| services | Map of services created and their attributes |
| task_exec_iam_role_arn | Task execution IAM role ARN |
| task_exec_iam_role_name | Task execution IAM role name |
| task_exec_iam_role_unique_id | Stable and unique string identifying the task execution IAM role |
Module is maintained by Anton Babenko with help from these awesome contributors.
Apache-2.0 Licensed. See LICENSE.
208 followers · starred Jan 2026
151 followers · starred Feb 2021
359 followers · starred Jul 2021
65 followers · starred Dec 2022