From e3f936b768e5b0e3d6469b6d6a2af42b39496a89 Mon Sep 17 00:00:00 2001
From: Rodrigo Torres <rlinstorres@gmail.com>
Date: Tue, 18 Jun 2024 15:26:58 +0200
Subject: [PATCH 1/5] feat: Adding support for EBS volumes

---
 modules/service/main.tf      | 107 +++++++++++++++++++++++++++++++++--
 modules/service/variables.tf |  92 ++++++++++++++++++++++++++++++
 2 files changed, 195 insertions(+), 4 deletions(-)

diff --git a/modules/service/main.tf b/modules/service/main.tf
index a5e00761..b5e966b6 100644
--- a/modules/service/main.tf
+++ b/modules/service/main.tf
@@ -197,6 +197,30 @@ resource "aws_ecs_service" "this" {
     }
   }
 
+  dynamic "volume_configuration" {
+    for_each = var.volume_configuration
+
+    content {
+      name = try(volume_configuration.value.name, volume_configuration.key)
+
+      dynamic "managed_ebs_volume" {
+        for_each = try([volume_configuration.value.managed_ebs_volume], [])
+
+        content {
+          role_arn         = try(aws_iam_role.infrastructure_iam_role[0].arn, var.infrastructure_iam_role_arn)
+          encrypted        = try(managed_ebs_volume.value.encrypted, null)
+          file_system_type = try(managed_ebs_volume.value.file_system_type, null)
+          iops             = try(managed_ebs_volume.value.iops, null)
+          kms_key_id       = try(managed_ebs_volume.value.kms_key_id, null)
+          size_in_gb       = try(managed_ebs_volume.value.size_in_gb, null)
+          snapshot_id      = try(managed_ebs_volume.value.snapshot_id, null)
+          throughput       = try(managed_ebs_volume.value.throughput, null)
+          volume_type      = try(managed_ebs_volume.value.volume_type, null)
+        }
+      }
+    }
+  }
+
   task_definition       = local.task_definition
   triggers              = var.triggers
   wait_for_steady_state = var.wait_for_steady_state
@@ -211,7 +235,8 @@ resource "aws_ecs_service" "this" {
   }
 
   depends_on = [
-    aws_iam_role_policy_attachment.service
+    aws_iam_role_policy_attachment.service,
+    aws_iam_role_policy_attachment.infrastructure_iam_role_ebs_policy
   ]
 
   lifecycle {
@@ -394,6 +419,30 @@ resource "aws_ecs_service" "ignore_task_definition" {
     }
   }
 
+  dynamic "volume_configuration" {
+    for_each = var.volume_configuration
+
+    content {
+      name = try(volume_configuration.value.name, volume_configuration.key)
+
+      dynamic "managed_ebs_volume" {
+        for_each = try([volume_configuration.value.managed_ebs_volume], [])
+
+        content {
+          role_arn         = try(aws_iam_role.infrastructure_iam_role[0].arn, var.infrastructure_iam_role_arn)
+          encrypted        = try(managed_ebs_volume.value.encrypted, null)
+          file_system_type = try(managed_ebs_volume.value.file_system_type, null)
+          iops             = try(managed_ebs_volume.value.iops, null)
+          kms_key_id       = try(managed_ebs_volume.value.kms_key_id, null)
+          size_in_gb       = try(managed_ebs_volume.value.size_in_gb, null)
+          snapshot_id      = try(managed_ebs_volume.value.snapshot_id, null)
+          throughput       = try(managed_ebs_volume.value.throughput, null)
+          volume_type      = try(managed_ebs_volume.value.volume_type, null)
+        }
+      }
+    }
+  }
+
   task_definition       = local.task_definition
   triggers              = var.triggers
   wait_for_steady_state = var.wait_for_steady_state
@@ -408,7 +457,8 @@ resource "aws_ecs_service" "ignore_task_definition" {
   }
 
   depends_on = [
-    aws_iam_role_policy_attachment.service
+    aws_iam_role_policy_attachment.service,
+    aws_iam_role_policy_attachment.infrastructure_iam_role_ebs_policy
   ]
 
   lifecycle {
@@ -751,8 +801,9 @@ resource "aws_ecs_task_definition" "this" {
         }
       }
 
-      host_path = try(volume.value.host_path, null)
-      name      = try(volume.value.name, volume.key)
+      host_path           = try(volume.value.host_path, null)
+      configure_at_launch = try(volume.value.configure_at_launch, null)
+      name                = try(volume.value.name, volume.key)
     }
   }
 
@@ -1411,3 +1462,51 @@ resource "aws_security_group_rule" "this" {
   self                     = lookup(each.value, "self", null)
   source_security_group_id = lookup(each.value, "source_security_group_id", null)
 }
+
+############################################################################################
+# ECS infrastructure IAM role
+# https://docs.aws.amazon.com/AmazonECS/latest/developerguide/infrastructure_IAM_role.html
+############################################################################################
+
+locals {
+  needs_infrastructure_iam_role  = var.create_infrastructure_iam_role && var.volume_configuration != null
+  create_infrastructure_iam_role = var.create && local.needs_infrastructure_iam_role
+  infrastructure_iam_role_name   = try(coalesce(var.infrastructure_iam_role_name, var.name), "")
+}
+
+data "aws_iam_policy_document" "infrastructure_iam_role" {
+  count = local.create_infrastructure_iam_role ? 1 : 0
+
+  statement {
+    sid     = "ECSServiceAssumeRole"
+    actions = ["sts:AssumeRole"]
+
+    principals {
+      type        = "Service"
+      identifiers = ["ecs.amazonaws.com"]
+    }
+  }
+}
+
+resource "aws_iam_role" "infrastructure_iam_role" {
+  count = local.create_infrastructure_iam_role ? 1 : 0
+
+  name        = var.infrastructure_iam_role_use_name_prefix ? null : local.infrastructure_iam_role_name
+  name_prefix = var.infrastructure_iam_role_use_name_prefix ? "${local.infrastructure_iam_role_name}-" : null
+  path        = var.infrastructure_iam_role_path
+  description = coalesce(var.infrastructure_iam_role_description, "Amazon ECS infrastructure IAM role that is used to manage your infrastructure")
+
+  assume_role_policy    = data.aws_iam_policy_document.ecs_infrastructure_iam_role[0].json
+  permissions_boundary  = var.infrastructure_iam_role_permissions_boundary
+  force_detach_policies = true
+
+  tags = merge(var.tags, var.infrastructure_iam_role_tags)
+}
+
+# https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ebs-volumes.html#ebs-volume-considerations/
+resource "aws_iam_role_policy_attachment" "infrastructure_iam_role_ebs_policy" {
+  count = local.create_infrastructure_iam_role ? 1 : 0
+
+  role       = aws_iam_role.infrastructure_iam_role[0].name
+  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVolumes"
+}
diff --git a/modules/service/variables.tf b/modules/service/variables.tf
index 1c542e15..a5a820b0 100644
--- a/modules/service/variables.tf
+++ b/modules/service/variables.tf
@@ -659,3 +659,95 @@ variable "security_group_tags" {
   type        = map(string)
   default     = {}
 }
+
+################################################################################
+# Security Group
+################################################################################
+
+variable "create_security_group" {
+  description = "Determines if a security group is created"
+  type        = bool
+  default     = true
+}
+
+variable "security_group_name" {
+  description = "Name to use on security group created"
+  type        = string
+  default     = null
+}
+
+variable "security_group_use_name_prefix" {
+  description = "Determines whether the security group name (`security_group_name`) is used as a prefix"
+  type        = bool
+  default     = true
+}
+
+variable "security_group_description" {
+  description = "Description of the security group created"
+  type        = string
+  default     = null
+}
+
+variable "security_group_rules" {
+  description = "Security group rules to add to the security group created"
+  type        = any
+  default     = {}
+}
+
+variable "security_group_tags" {
+  description = "A map of additional tags to add to the security group created"
+  type        = map(string)
+  default     = {}
+}
+
+############################################################################################
+# ECS infrastructure IAM role
+############################################################################################
+
+variable "create_infrastructure_iam_role" {
+  description = "Determines whether the ECS infrastructure IAM role should be created"
+  type        = bool
+  default     = false
+}
+
+variable "infrastructure_iam_role_arn" {
+  description = "Existing IAM role ARN"
+  type        = string
+  default     = null
+}
+
+variable "infrastructure_iam_role_name" {
+  description = "Name to use on IAM role created"
+  type        = string
+  default     = null
+}
+
+variable "infrastructure_iam_role_use_name_prefix" {
+  description = "Determines whether the IAM role name (`iam_role_name`) is used as a prefix"
+  type        = bool
+  default     = true
+}
+
+variable "infrastructure_iam_role_path" {
+  description = "IAM role path"
+  type        = string
+  default     = null
+}
+
+variable "infrastructure_iam_role_description" {
+  description = "Description of the role"
+  type        = string
+  default     = null
+}
+
+variable "infrastructure_iam_role_permissions_boundary" {
+  description = "ARN of the policy that is used to set the permissions boundary for the IAM role"
+  type        = string
+  default     = null
+}
+
+variable "infrastructure_iam_role_tags" {
+  description = "A map of additional tags to add to the IAM role created"
+  type        = map(string)
+  default     = {}
+}

From 0239f013feea10a37cf3df66a59e7d8d8ca9d57b Mon Sep 17 00:00:00 2001
From: Rodrigo Torres <rlinstorres@gmail.com>
Date: Tue, 18 Jun 2024 15:41:14 +0200
Subject: [PATCH 2/5] feat: Adding support for EBS volumes

---
 modules/service/README.md    |  12 ++++
 modules/service/main.tf      |   2 +-
 modules/service/variables.tf |  46 ++-------------
 wrappers/service/main.tf     | 111 +++++++++++++++++++----------------
 4 files changed, 79 insertions(+), 92 deletions(-)

diff --git a/modules/service/README.md b/modules/service/README.md
index b24f2b2c..b1fa813d 100644
--- a/modules/service/README.md
+++ b/modules/service/README.md
@@ -195,10 +195,12 @@ module "ecs_service" {
 | [aws_ecs_task_set.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_set) | resource |
 | [aws_iam_policy.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
 | [aws_iam_policy.task_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [aws_iam_role.infrastructure_iam_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
 | [aws_iam_role.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
 | [aws_iam_role.task_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
 | [aws_iam_role.tasks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
 | [aws_iam_role_policy.tasks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
+| [aws_iam_role_policy_attachment.infrastructure_iam_role_ebs_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
 | [aws_iam_role_policy_attachment.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
 | [aws_iam_role_policy_attachment.task_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
 | [aws_iam_role_policy_attachment.task_exec_additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
@@ -207,6 +209,7 @@ module "ecs_service" {
 | [aws_security_group_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
 | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
 | [aws_ecs_task_definition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ecs_task_definition) | data source |
+| [aws_iam_policy_document.infrastructure_iam_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
 | [aws_iam_policy_document.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
 | [aws_iam_policy_document.service_assume](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
 | [aws_iam_policy_document.task_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
@@ -234,6 +237,7 @@ module "ecs_service" {
 | <a name="input_cpu"></a> [cpu](#input\_cpu) | Number of cpu units used by the task. If the `requires_compatibilities` is `FARGATE` this field is required | `number` | `1024` | no |
 | <a name="input_create"></a> [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no |
 | <a name="input_create_iam_role"></a> [create\_iam\_role](#input\_create\_iam\_role) | Determines whether the ECS service IAM role should be created | `bool` | `true` | no |
+| <a name="input_create_infrastructure_iam_role"></a> [create\_infrastructure\_iam\_role](#input\_create\_infrastructure\_iam\_role) | Determines whether the ECS infrastructure IAM role should be created | `bool` | `false` | no |
 | <a name="input_create_security_group"></a> [create\_security\_group](#input\_create\_security\_group) | Determines if a security group is created | `bool` | `true` | no |
 | <a name="input_create_service"></a> [create\_service](#input\_create\_service) | Determines whether service resource will be created (set to `false` in case you want to create task definition only) | `bool` | `true` | no |
 | <a name="input_create_task_definition"></a> [create\_task\_definition](#input\_create\_task\_definition) | Determines whether to create a task definition or use existing/provided | `bool` | `true` | no |
@@ -264,6 +268,13 @@ module "ecs_service" {
 | <a name="input_iam_role_use_name_prefix"></a> [iam\_role\_use\_name\_prefix](#input\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`iam_role_name`) is used as a prefix | `bool` | `true` | no |
 | <a name="input_ignore_task_definition_changes"></a> [ignore\_task\_definition\_changes](#input\_ignore\_task\_definition\_changes) | Whether changes to service `task_definition` changes should be ignored | `bool` | `false` | no |
 | <a name="input_inference_accelerator"></a> [inference\_accelerator](#input\_inference\_accelerator) | Configuration block(s) with Inference Accelerators settings | `any` | `{}` | no |
+| <a name="input_infrastructure_iam_role_arn"></a> [infrastructure\_iam\_role\_arn](#input\_infrastructure\_iam\_role\_arn) | Existing IAM role ARN | `string` | `null` | no |
+| <a name="input_infrastructure_iam_role_description"></a> [infrastructure\_iam\_role\_description](#input\_infrastructure\_iam\_role\_description) | Description of the role | `string` | `null` | no |
+| <a name="input_infrastructure_iam_role_name"></a> [infrastructure\_iam\_role\_name](#input\_infrastructure\_iam\_role\_name) | Name to use on IAM role created | `string` | `null` | no |
+| <a name="input_infrastructure_iam_role_path"></a> [infrastructure\_iam\_role\_path](#input\_infrastructure\_iam\_role\_path) | IAM role path | `string` | `null` | no |
+| <a name="input_infrastructure_iam_role_permissions_boundary"></a> [infrastructure\_iam\_role\_permissions\_boundary](#input\_infrastructure\_iam\_role\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the IAM role | `string` | `null` | no |
+| <a name="input_infrastructure_iam_role_tags"></a> [infrastructure\_iam\_role\_tags](#input\_infrastructure\_iam\_role\_tags) | A map of additional tags to add to the IAM role created | `map(string)` | `{}` | no |
+| <a name="input_infrastructure_iam_role_use_name_prefix"></a> [infrastructure\_iam\_role\_use\_name\_prefix](#input\_infrastructure\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`iam_role_name`) is used as a prefix | `bool` | `true` | no |
 | <a name="input_ipc_mode"></a> [ipc\_mode](#input\_ipc\_mode) | IPC resource namespace to be used for the containers in the task The valid values are `host`, `task`, and `none` | `string` | `null` | no |
 | <a name="input_launch_type"></a> [launch\_type](#input\_launch\_type) | Launch type on which to run your service. The valid values are `EC2`, `FARGATE`, and `EXTERNAL`. Defaults to `FARGATE` | `string` | `"FARGATE"` | no |
 | <a name="input_load_balancer"></a> [load\_balancer](#input\_load\_balancer) | Configuration block for load balancers | `any` | `{}` | no |
@@ -319,6 +330,7 @@ module "ecs_service" {
 | <a name="input_timeouts"></a> [timeouts](#input\_timeouts) | Create, update, and delete timeout configurations for the service | `map(string)` | `{}` | no |
 | <a name="input_triggers"></a> [triggers](#input\_triggers) | Map of arbitrary keys and values that, when changed, will trigger an in-place update (redeployment). Useful with `timestamp()` | `any` | `{}` | no |
 | <a name="input_volume"></a> [volume](#input\_volume) | Configuration block for volumes that containers in your task may use | `any` | `{}` | no |
+| <a name="input_volume_configuration"></a> [volume\_configuration](#input\_volume\_configuration) | Configuration for a volume specified in the task definition as a volume that is configured at launch time. Currently, the only supported volume type is an Amazon EBS volume | `any` | `{}` | no |
 | <a name="input_wait_for_steady_state"></a> [wait\_for\_steady\_state](#input\_wait\_for\_steady\_state) | If true, Terraform will wait for the service to reach a steady state before continuing. Default is `false` | `bool` | `null` | no |
 | <a name="input_wait_until_stable"></a> [wait\_until\_stable](#input\_wait\_until\_stable) | Whether terraform should wait until the task set has reached `STEADY_STATE` | `bool` | `null` | no |
 | <a name="input_wait_until_stable_timeout"></a> [wait\_until\_stable\_timeout](#input\_wait\_until\_stable\_timeout) | Wait timeout for task set to reach `STEADY_STATE`. Valid time units include `ns`, `us` (or µs), `ms`, `s`, `m`, and `h`. Default `10m` | `string` | `null` | no |
diff --git a/modules/service/main.tf b/modules/service/main.tf
index b5e966b6..248bf75b 100644
--- a/modules/service/main.tf
+++ b/modules/service/main.tf
@@ -1496,7 +1496,7 @@ resource "aws_iam_role" "infrastructure_iam_role" {
   path        = var.infrastructure_iam_role_path
   description = coalesce(var.infrastructure_iam_role_description, "Amazon ECS infrastructure IAM role that is used to manage your infrastructure")
 
-  assume_role_policy    = data.aws_iam_policy_document.ecs_infrastructure_iam_role[0].json
+  assume_role_policy    = data.aws_iam_policy_document.infrastructure_iam_role[0].json
   permissions_boundary  = var.infrastructure_iam_role_permissions_boundary
   force_detach_policies = true
 
diff --git a/modules/service/variables.tf b/modules/service/variables.tf
index a5a820b0..c516013b 100644
--- a/modules/service/variables.tf
+++ b/modules/service/variables.tf
@@ -373,6 +373,12 @@ variable "volume" {
   default     = {}
 }
 
+variable "volume_configuration" {
+  description = "Configuration for a volume specified in the task definition as a volume that is configured at launch time. Currently, the only supported volume type is an Amazon EBS volume"
+  type        = any
+  default     = {}
+}
+
 variable "task_tags" {
   description = "A map of additional tags to add to the task definition/set created"
   type        = map(string)
@@ -660,46 +666,6 @@ variable "security_group_tags" {
   default     = {}
 }
 
-################################################################################
-# Security Group
-################################################################################
-
-variable "create_security_group" {
-  description = "Determines if a security group is created"
-  type        = bool
-  default     = true
-}
-
-variable "security_group_name" {
-  description = "Name to use on security group created"
-  type        = string
-  default     = null
-}
-
-variable "security_group_use_name_prefix" {
-  description = "Determines whether the security group name (`security_group_name`) is used as a prefix"
-  type        = bool
-  default     = true
-}
-
-variable "security_group_description" {
-  description = "Description of the security group created"
-  type        = string
-  default     = null
-}
-
-variable "security_group_rules" {
-  description = "Security group rules to add to the security group created"
-  type        = any
-  default     = {}
-}
-
-variable "security_group_tags" {
-  description = "A map of additional tags to add to the security group created"
-  type        = map(string)
-  default     = {}
-}
-
 ############################################################################################
 # ECS infrastructure IAM role
 ############################################################################################
diff --git a/wrappers/service/main.tf b/wrappers/service/main.tf
index 3dbd9e46..aaf8941a 100644
--- a/wrappers/service/main.tf
+++ b/wrappers/service/main.tf
@@ -27,57 +27,65 @@ module "wrapper" {
       }
     }
   })
-  autoscaling_scheduled_actions      = try(each.value.autoscaling_scheduled_actions, var.defaults.autoscaling_scheduled_actions, {})
-  capacity_provider_strategy         = try(each.value.capacity_provider_strategy, var.defaults.capacity_provider_strategy, {})
-  cluster_arn                        = try(each.value.cluster_arn, var.defaults.cluster_arn, "")
-  container_definition_defaults      = try(each.value.container_definition_defaults, var.defaults.container_definition_defaults, {})
-  container_definitions              = try(each.value.container_definitions, var.defaults.container_definitions, {})
-  cpu                                = try(each.value.cpu, var.defaults.cpu, 1024)
-  create                             = try(each.value.create, var.defaults.create, true)
-  create_iam_role                    = try(each.value.create_iam_role, var.defaults.create_iam_role, true)
-  create_security_group              = try(each.value.create_security_group, var.defaults.create_security_group, true)
-  create_service                     = try(each.value.create_service, var.defaults.create_service, true)
-  create_task_definition             = try(each.value.create_task_definition, var.defaults.create_task_definition, true)
-  create_task_exec_iam_role          = try(each.value.create_task_exec_iam_role, var.defaults.create_task_exec_iam_role, true)
-  create_task_exec_policy            = try(each.value.create_task_exec_policy, var.defaults.create_task_exec_policy, true)
-  create_tasks_iam_role              = try(each.value.create_tasks_iam_role, var.defaults.create_tasks_iam_role, true)
-  deployment_circuit_breaker         = try(each.value.deployment_circuit_breaker, var.defaults.deployment_circuit_breaker, {})
-  deployment_controller              = try(each.value.deployment_controller, var.defaults.deployment_controller, {})
-  deployment_maximum_percent         = try(each.value.deployment_maximum_percent, var.defaults.deployment_maximum_percent, 200)
-  deployment_minimum_healthy_percent = try(each.value.deployment_minimum_healthy_percent, var.defaults.deployment_minimum_healthy_percent, 66)
-  desired_count                      = try(each.value.desired_count, var.defaults.desired_count, 1)
-  enable_autoscaling                 = try(each.value.enable_autoscaling, var.defaults.enable_autoscaling, true)
-  enable_ecs_managed_tags            = try(each.value.enable_ecs_managed_tags, var.defaults.enable_ecs_managed_tags, true)
-  enable_execute_command             = try(each.value.enable_execute_command, var.defaults.enable_execute_command, false)
-  ephemeral_storage                  = try(each.value.ephemeral_storage, var.defaults.ephemeral_storage, {})
-  external_id                        = try(each.value.external_id, var.defaults.external_id, null)
-  family                             = try(each.value.family, var.defaults.family, null)
-  force_delete                       = try(each.value.force_delete, var.defaults.force_delete, null)
-  force_new_deployment               = try(each.value.force_new_deployment, var.defaults.force_new_deployment, true)
-  health_check_grace_period_seconds  = try(each.value.health_check_grace_period_seconds, var.defaults.health_check_grace_period_seconds, null)
-  iam_role_arn                       = try(each.value.iam_role_arn, var.defaults.iam_role_arn, null)
-  iam_role_description               = try(each.value.iam_role_description, var.defaults.iam_role_description, null)
-  iam_role_name                      = try(each.value.iam_role_name, var.defaults.iam_role_name, null)
-  iam_role_path                      = try(each.value.iam_role_path, var.defaults.iam_role_path, null)
-  iam_role_permissions_boundary      = try(each.value.iam_role_permissions_boundary, var.defaults.iam_role_permissions_boundary, null)
-  iam_role_statements                = try(each.value.iam_role_statements, var.defaults.iam_role_statements, {})
-  iam_role_tags                      = try(each.value.iam_role_tags, var.defaults.iam_role_tags, {})
-  iam_role_use_name_prefix           = try(each.value.iam_role_use_name_prefix, var.defaults.iam_role_use_name_prefix, true)
-  ignore_task_definition_changes     = try(each.value.ignore_task_definition_changes, var.defaults.ignore_task_definition_changes, false)
-  inference_accelerator              = try(each.value.inference_accelerator, var.defaults.inference_accelerator, {})
-  ipc_mode                           = try(each.value.ipc_mode, var.defaults.ipc_mode, null)
-  launch_type                        = try(each.value.launch_type, var.defaults.launch_type, "FARGATE")
-  load_balancer                      = try(each.value.load_balancer, var.defaults.load_balancer, {})
-  memory                             = try(each.value.memory, var.defaults.memory, 2048)
-  name                               = try(each.value.name, var.defaults.name, null)
-  network_mode                       = try(each.value.network_mode, var.defaults.network_mode, "awsvpc")
-  ordered_placement_strategy         = try(each.value.ordered_placement_strategy, var.defaults.ordered_placement_strategy, {})
-  pid_mode                           = try(each.value.pid_mode, var.defaults.pid_mode, null)
-  placement_constraints              = try(each.value.placement_constraints, var.defaults.placement_constraints, {})
-  platform_version                   = try(each.value.platform_version, var.defaults.platform_version, null)
-  propagate_tags                     = try(each.value.propagate_tags, var.defaults.propagate_tags, null)
-  proxy_configuration                = try(each.value.proxy_configuration, var.defaults.proxy_configuration, {})
-  requires_compatibilities           = try(each.value.requires_compatibilities, var.defaults.requires_compatibilities, ["FARGATE"])
+  autoscaling_scheduled_actions                = try(each.value.autoscaling_scheduled_actions, var.defaults.autoscaling_scheduled_actions, {})
+  capacity_provider_strategy                   = try(each.value.capacity_provider_strategy, var.defaults.capacity_provider_strategy, {})
+  cluster_arn                                  = try(each.value.cluster_arn, var.defaults.cluster_arn, "")
+  container_definition_defaults                = try(each.value.container_definition_defaults, var.defaults.container_definition_defaults, {})
+  container_definitions                        = try(each.value.container_definitions, var.defaults.container_definitions, {})
+  cpu                                          = try(each.value.cpu, var.defaults.cpu, 1024)
+  create                                       = try(each.value.create, var.defaults.create, true)
+  create_iam_role                              = try(each.value.create_iam_role, var.defaults.create_iam_role, true)
+  create_infrastructure_iam_role               = try(each.value.create_infrastructure_iam_role, var.defaults.create_infrastructure_iam_role, false)
+  create_security_group                        = try(each.value.create_security_group, var.defaults.create_security_group, true)
+  create_service                               = try(each.value.create_service, var.defaults.create_service, true)
+  create_task_definition                       = try(each.value.create_task_definition, var.defaults.create_task_definition, true)
+  create_task_exec_iam_role                    = try(each.value.create_task_exec_iam_role, var.defaults.create_task_exec_iam_role, true)
+  create_task_exec_policy                      = try(each.value.create_task_exec_policy, var.defaults.create_task_exec_policy, true)
+  create_tasks_iam_role                        = try(each.value.create_tasks_iam_role, var.defaults.create_tasks_iam_role, true)
+  deployment_circuit_breaker                   = try(each.value.deployment_circuit_breaker, var.defaults.deployment_circuit_breaker, {})
+  deployment_controller                        = try(each.value.deployment_controller, var.defaults.deployment_controller, {})
+  deployment_maximum_percent                   = try(each.value.deployment_maximum_percent, var.defaults.deployment_maximum_percent, 200)
+  deployment_minimum_healthy_percent           = try(each.value.deployment_minimum_healthy_percent, var.defaults.deployment_minimum_healthy_percent, 66)
+  desired_count                                = try(each.value.desired_count, var.defaults.desired_count, 1)
+  enable_autoscaling                           = try(each.value.enable_autoscaling, var.defaults.enable_autoscaling, true)
+  enable_ecs_managed_tags                      = try(each.value.enable_ecs_managed_tags, var.defaults.enable_ecs_managed_tags, true)
+  enable_execute_command                       = try(each.value.enable_execute_command, var.defaults.enable_execute_command, false)
+  ephemeral_storage                            = try(each.value.ephemeral_storage, var.defaults.ephemeral_storage, {})
+  external_id                                  = try(each.value.external_id, var.defaults.external_id, null)
+  family                                       = try(each.value.family, var.defaults.family, null)
+  force_delete                                 = try(each.value.force_delete, var.defaults.force_delete, null)
+  force_new_deployment                         = try(each.value.force_new_deployment, var.defaults.force_new_deployment, true)
+  health_check_grace_period_seconds            = try(each.value.health_check_grace_period_seconds, var.defaults.health_check_grace_period_seconds, null)
+  iam_role_arn                                 = try(each.value.iam_role_arn, var.defaults.iam_role_arn, null)
+  iam_role_description                         = try(each.value.iam_role_description, var.defaults.iam_role_description, null)
+  iam_role_name                                = try(each.value.iam_role_name, var.defaults.iam_role_name, null)
+  iam_role_path                                = try(each.value.iam_role_path, var.defaults.iam_role_path, null)
+  iam_role_permissions_boundary                = try(each.value.iam_role_permissions_boundary, var.defaults.iam_role_permissions_boundary, null)
+  iam_role_statements                          = try(each.value.iam_role_statements, var.defaults.iam_role_statements, {})
+  iam_role_tags                                = try(each.value.iam_role_tags, var.defaults.iam_role_tags, {})
+  iam_role_use_name_prefix                     = try(each.value.iam_role_use_name_prefix, var.defaults.iam_role_use_name_prefix, true)
+  ignore_task_definition_changes               = try(each.value.ignore_task_definition_changes, var.defaults.ignore_task_definition_changes, false)
+  inference_accelerator                        = try(each.value.inference_accelerator, var.defaults.inference_accelerator, {})
+  infrastructure_iam_role_arn                  = try(each.value.infrastructure_iam_role_arn, var.defaults.infrastructure_iam_role_arn, null)
+  infrastructure_iam_role_description          = try(each.value.infrastructure_iam_role_description, var.defaults.infrastructure_iam_role_description, null)
+  infrastructure_iam_role_name                 = try(each.value.infrastructure_iam_role_name, var.defaults.infrastructure_iam_role_name, null)
+  infrastructure_iam_role_path                 = try(each.value.infrastructure_iam_role_path, var.defaults.infrastructure_iam_role_path, null)
+  infrastructure_iam_role_permissions_boundary = try(each.value.infrastructure_iam_role_permissions_boundary, var.defaults.infrastructure_iam_role_permissions_boundary, null)
+  infrastructure_iam_role_tags                 = try(each.value.infrastructure_iam_role_tags, var.defaults.infrastructure_iam_role_tags, {})
+  infrastructure_iam_role_use_name_prefix      = try(each.value.infrastructure_iam_role_use_name_prefix, var.defaults.infrastructure_iam_role_use_name_prefix, true)
+  ipc_mode                                     = try(each.value.ipc_mode, var.defaults.ipc_mode, null)
+  launch_type                                  = try(each.value.launch_type, var.defaults.launch_type, "FARGATE")
+  load_balancer                                = try(each.value.load_balancer, var.defaults.load_balancer, {})
+  memory                                       = try(each.value.memory, var.defaults.memory, 2048)
+  name                                         = try(each.value.name, var.defaults.name, null)
+  network_mode                                 = try(each.value.network_mode, var.defaults.network_mode, "awsvpc")
+  ordered_placement_strategy                   = try(each.value.ordered_placement_strategy, var.defaults.ordered_placement_strategy, {})
+  pid_mode                                     = try(each.value.pid_mode, var.defaults.pid_mode, null)
+  placement_constraints                        = try(each.value.placement_constraints, var.defaults.placement_constraints, {})
+  platform_version                             = try(each.value.platform_version, var.defaults.platform_version, null)
+  propagate_tags                               = try(each.value.propagate_tags, var.defaults.propagate_tags, null)
+  proxy_configuration                          = try(each.value.proxy_configuration, var.defaults.proxy_configuration, {})
+  requires_compatibilities                     = try(each.value.requires_compatibilities, var.defaults.requires_compatibilities, ["FARGATE"])
   runtime_platform = try(each.value.runtime_platform, var.defaults.runtime_platform, {
     operating_system_family = "LINUX"
     cpu_architecture        = "X86_64"
@@ -123,6 +131,7 @@ module "wrapper" {
   timeouts                                = try(each.value.timeouts, var.defaults.timeouts, {})
   triggers                                = try(each.value.triggers, var.defaults.triggers, {})
   volume                                  = try(each.value.volume, var.defaults.volume, {})
+  volume_configuration                    = try(each.value.volume_configuration, var.defaults.volume_configuration, {})
   wait_for_steady_state                   = try(each.value.wait_for_steady_state, var.defaults.wait_for_steady_state, null)
   wait_until_stable                       = try(each.value.wait_until_stable, var.defaults.wait_until_stable, null)
   wait_until_stable_timeout               = try(each.value.wait_until_stable_timeout, var.defaults.wait_until_stable_timeout, null)

From 25efac1739958c7fe73cf9d5040e46a02a200c60 Mon Sep 17 00:00:00 2001
From: Rodrigo Torres <rlinstorres@gmail.com>
Date: Wed, 19 Jun 2024 17:06:38 +0200
Subject: [PATCH 3/5] feat: Add support for EBS volumes

---
 examples/ec2-autoscaling/main.tf | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/examples/ec2-autoscaling/main.tf b/examples/ec2-autoscaling/main.tf
index 35e6249f..30bcb6ad 100644
--- a/examples/ec2-autoscaling/main.tf
+++ b/examples/ec2-autoscaling/main.tf
@@ -95,8 +95,24 @@ module "ecs_service" {
     }
   }
 
+  create_infrastructure_iam_role = true
+  volume_configuration = {
+    ebs-volume = {
+      managed_ebs_volume = {
+        encrypted        = true
+        file_system_type = "xfs"
+        size_in_gb       = 5
+        volume_type      = "gp3"
+      }
+    }
+  }
+
   volume = {
-    my-vol = {}
+    my-vol = {},
+    ebs-volume = {
+      name                = "ebs-volume"
+      configure_at_launch = true
+    }
   }
 
   # Container definition(s)
@@ -115,6 +131,10 @@ module "ecs_service" {
         {
           sourceVolume  = "my-vol",
           containerPath = "/var/www/my-vol"
+        },
+        {
+          containerPath = "/ebs/data"
+          sourceVolume  = "ebs-volume"
         }
       ]
 

From 6c52d9bd8ff8483e9e440f479d3c9ed614c9ac30 Mon Sep 17 00:00:00 2001
From: Rodrigo Torres <rlinstorres@gmail.com>
Date: Wed, 19 Jun 2024 17:36:28 +0200
Subject: [PATCH 4/5] feat: Add support for EBS volumes

---
 examples/ec2-autoscaling/README.md  |  2 ++
 examples/ec2-autoscaling/outputs.tf | 10 ++++++++++
 modules/service/README.md           |  2 ++
 modules/service/outputs.tf          | 14 ++++++++++++++
 4 files changed, 28 insertions(+)

diff --git a/examples/ec2-autoscaling/README.md b/examples/ec2-autoscaling/README.md
index d5288ec5..c95634c1 100644
--- a/examples/ec2-autoscaling/README.md
+++ b/examples/ec2-autoscaling/README.md
@@ -73,6 +73,8 @@ No inputs.
 | <a name="output_service_iam_role_name"></a> [service\_iam\_role\_name](#output\_service\_iam\_role\_name) | Service IAM role name |
 | <a name="output_service_iam_role_unique_id"></a> [service\_iam\_role\_unique\_id](#output\_service\_iam\_role\_unique\_id) | Stable and unique string identifying the service IAM role |
 | <a name="output_service_id"></a> [service\_id](#output\_service\_id) | ARN that identifies the service |
+| <a name="output_service_infrastructure_iam_role_arn"></a> [service\_infrastructure\_iam\_role\_arn](#output\_service\_infrastructure\_iam\_role\_arn) | Infrastructure IAM role ARN |
+| <a name="output_service_infrastructure_iam_role_name"></a> [service\_infrastructure\_iam\_role\_name](#output\_service\_infrastructure\_iam\_role\_name) | Infrastructure IAM role name |
 | <a name="output_service_name"></a> [service\_name](#output\_service\_name) | Name of the service |
 | <a name="output_service_task_definition_arn"></a> [service\_task\_definition\_arn](#output\_service\_task\_definition\_arn) | Full ARN of the Task Definition (including both `family` and `revision`) |
 | <a name="output_service_task_definition_revision"></a> [service\_task\_definition\_revision](#output\_service\_task\_definition\_revision) | Revision of the task in a particular family |
diff --git a/examples/ec2-autoscaling/outputs.tf b/examples/ec2-autoscaling/outputs.tf
index 2f6f85a7..128fd2f7 100644
--- a/examples/ec2-autoscaling/outputs.tf
+++ b/examples/ec2-autoscaling/outputs.tf
@@ -130,3 +130,13 @@ output "service_autoscaling_scheduled_actions" {
   description = "Map of autoscaling scheduled actions and their attributes"
   value       = module.ecs_service.autoscaling_scheduled_actions
 }
+
+output "service_infrastructure_iam_role_arn" {
+  description = "Infrastructure IAM role ARN"
+  value       = module.ecs_service.infrastructure_iam_role_arn
+}
+
+output "service_infrastructure_iam_role_name" {
+  description = "Infrastructure IAM role name"
+  value       = module.ecs_service.infrastructure_iam_role_name
+}
diff --git a/modules/service/README.md b/modules/service/README.md
index b1fa813d..63d29d7f 100644
--- a/modules/service/README.md
+++ b/modules/service/README.md
@@ -346,6 +346,8 @@ module "ecs_service" {
 | <a name="output_iam_role_name"></a> [iam\_role\_name](#output\_iam\_role\_name) | Service IAM role name |
 | <a name="output_iam_role_unique_id"></a> [iam\_role\_unique\_id](#output\_iam\_role\_unique\_id) | Stable and unique string identifying the service IAM role |
 | <a name="output_id"></a> [id](#output\_id) | ARN that identifies the service |
+| <a name="output_infrastructure_iam_role_arn"></a> [infrastructure\_iam\_role\_arn](#output\_infrastructure\_iam\_role\_arn) | Infrastructure IAM role ARN |
+| <a name="output_infrastructure_iam_role_name"></a> [infrastructure\_iam\_role\_name](#output\_infrastructure\_iam\_role\_name) | Infrastructure IAM role name |
 | <a name="output_name"></a> [name](#output\_name) | Name of the service |
 | <a name="output_security_group_arn"></a> [security\_group\_arn](#output\_security\_group\_arn) | Amazon Resource Name (ARN) of the security group |
 | <a name="output_security_group_id"></a> [security\_group\_id](#output\_security\_group\_id) | ID of the security group |
diff --git a/modules/service/outputs.tf b/modules/service/outputs.tf
index 1eaa8510..2ca89ce8 100644
--- a/modules/service/outputs.tf
+++ b/modules/service/outputs.tf
@@ -155,3 +155,17 @@ output "security_group_id" {
   description = "ID of the security group"
   value       = try(aws_security_group.this[0].id, null)
 }
+
+############################################################################################
+# ECS infrastructure IAM role
+############################################################################################
+
+output "infrastructure_iam_role_arn" {
+  description = "Infrastructure IAM role ARN"
+  value       = try(aws_iam_role.infrastructure_iam_role[0].arn, null)
+}
+
+output "infrastructure_iam_role_name" {
+  description = "Infrastructure IAM role name"
+  value       = try(aws_iam_role.infrastructure_iam_role[0].name, null)
+}

From 42bac0f5548b4cf447ac776dac87fd5579407a06 Mon Sep 17 00:00:00 2001
From: Bryant Biggs <bryantbiggs@gmail.com>
Date: Wed, 24 Jul 2024 19:41:57 -0400
Subject: [PATCH 5/5] chore: Update min required AWS provider version

---
 README.md                                 | 2 +-
 examples/complete/README.md               | 4 ++--
 examples/complete/versions.tf             | 2 +-
 examples/ec2-autoscaling/README.md        | 4 ++--
 examples/ec2-autoscaling/versions.tf      | 2 +-
 examples/fargate/README.md                | 4 ++--
 examples/fargate/versions.tf              | 2 +-
 modules/cluster/README.md                 | 4 ++--
 modules/cluster/versions.tf               | 2 +-
 modules/container-definition/README.md    | 4 ++--
 modules/container-definition/versions.tf  | 2 +-
 modules/service/README.md                 | 4 ++--
 modules/service/versions.tf               | 2 +-
 versions.tf                               | 2 +-
 wrappers/README.md                        | 6 +++---
 wrappers/cluster/README.md                | 6 +++---
 wrappers/cluster/versions.tf              | 2 +-
 wrappers/container-definition/README.md   | 6 +++---
 wrappers/container-definition/versions.tf | 2 +-
 wrappers/service/README.md                | 6 +++---
 wrappers/service/versions.tf              | 2 +-
 wrappers/versions.tf                      | 2 +-
 22 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/README.md b/README.md
index 301a713b..b2cbef86 100644
--- a/README.md
+++ b/README.md
@@ -160,7 +160,7 @@ module "ecs" {
 | Name | Version |
 |------|---------|
 | <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3 |
-| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.37 |
+| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.59 |
 
 ## Providers
 
diff --git a/examples/complete/README.md b/examples/complete/README.md
index a3de37cf..edffba88 100644
--- a/examples/complete/README.md
+++ b/examples/complete/README.md
@@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on
 | Name | Version |
 |------|---------|
 | <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3 |
-| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.37 |
+| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.59 |
 
 ## Providers
 
 | Name | Version |
 |------|---------|
-| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.37 |
+| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.59 |
 
 ## Modules
 
diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf
index 5f6e023e..dc999065 100644
--- a/examples/complete/versions.tf
+++ b/examples/complete/versions.tf
@@ -4,7 +4,7 @@ terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
-      version = ">= 5.37"
+      version = ">= 5.59"
     }
   }
 }
diff --git a/examples/ec2-autoscaling/README.md b/examples/ec2-autoscaling/README.md
index c95634c1..1ca87e47 100644
--- a/examples/ec2-autoscaling/README.md
+++ b/examples/ec2-autoscaling/README.md
@@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on
 | Name | Version |
 |------|---------|
 | <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3 |
-| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.37 |
+| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.59 |
 
 ## Providers
 
 | Name | Version |
 |------|---------|
-| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.37 |
+| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.59 |
 
 ## Modules
 
diff --git a/examples/ec2-autoscaling/versions.tf b/examples/ec2-autoscaling/versions.tf
index 5f6e023e..dc999065 100644
--- a/examples/ec2-autoscaling/versions.tf
+++ b/examples/ec2-autoscaling/versions.tf
@@ -4,7 +4,7 @@ terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
-      version = ">= 5.37"
+      version = ">= 5.59"
     }
   }
 }
diff --git a/examples/fargate/README.md b/examples/fargate/README.md
index deb8f958..183616e9 100644
--- a/examples/fargate/README.md
+++ b/examples/fargate/README.md
@@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on
 | Name | Version |
 |------|---------|
 | <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3 |
-| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.37 |
+| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.59 |
 
 ## Providers
 
 | Name | Version |
 |------|---------|
-| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.37 |
+| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.59 |
 
 ## Modules
 
diff --git a/examples/fargate/versions.tf b/examples/fargate/versions.tf
index 5f6e023e..dc999065 100644
--- a/examples/fargate/versions.tf
+++ b/examples/fargate/versions.tf
@@ -4,7 +4,7 @@ terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
-      version = ">= 5.37"
+      version = ">= 5.59"
     }
   }
 }
diff --git a/modules/cluster/README.md b/modules/cluster/README.md
index 27e5217c..5f1d8289 100644
--- a/modules/cluster/README.md
+++ b/modules/cluster/README.md
@@ -137,13 +137,13 @@ module "ecs_cluster" {
 | Name | Version |
 |------|---------|
 | <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3 |
-| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.37 |
+| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.59 |
 
 ## Providers
 
 | Name | Version |
 |------|---------|
-| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.37 |
+| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.59 |
 
 ## Modules
 
diff --git a/modules/cluster/versions.tf b/modules/cluster/versions.tf
index 5f6e023e..dc999065 100644
--- a/modules/cluster/versions.tf
+++ b/modules/cluster/versions.tf
@@ -4,7 +4,7 @@ terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
-      version = ">= 5.37"
+      version = ">= 5.59"
     }
   }
 }
diff --git a/modules/container-definition/README.md b/modules/container-definition/README.md
index 2b7cc211..48aa292e 100644
--- a/modules/container-definition/README.md
+++ b/modules/container-definition/README.md
@@ -116,13 +116,13 @@ module "example_ecs_container_definition" {
 | Name | Version |
 |------|---------|
 | <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3 |
-| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.37 |
+| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.59 |
 
 ## Providers
 
 | Name | Version |
 |------|---------|
-| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.37 |
+| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.59 |
 
 ## Modules
 
diff --git a/modules/container-definition/versions.tf b/modules/container-definition/versions.tf
index 5f6e023e..dc999065 100644
--- a/modules/container-definition/versions.tf
+++ b/modules/container-definition/versions.tf
@@ -4,7 +4,7 @@ terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
-      version = ">= 5.37"
+      version = ">= 5.59"
     }
   }
 }
diff --git a/modules/service/README.md b/modules/service/README.md
index 63d29d7f..365791df 100644
--- a/modules/service/README.md
+++ b/modules/service/README.md
@@ -167,13 +167,13 @@ module "ecs_service" {
 | Name | Version |
 |------|---------|
 | <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3 |
-| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.37 |
+| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.59 |
 
 ## Providers
 
 | Name | Version |
 |------|---------|
-| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.37 |
+| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.59 |
 
 ## Modules
 
diff --git a/modules/service/versions.tf b/modules/service/versions.tf
index 5f6e023e..dc999065 100644
--- a/modules/service/versions.tf
+++ b/modules/service/versions.tf
@@ -4,7 +4,7 @@ terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
-      version = ">= 5.37"
+      version = ">= 5.59"
     }
   }
 }
diff --git a/versions.tf b/versions.tf
index 5f6e023e..dc999065 100644
--- a/versions.tf
+++ b/versions.tf
@@ -4,7 +4,7 @@ terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
-      version = ">= 5.37"
+      version = ">= 5.59"
     }
   }
 }
diff --git a/wrappers/README.md b/wrappers/README.md
index 4d232b92..449acd8a 100644
--- a/wrappers/README.md
+++ b/wrappers/README.md
@@ -12,9 +12,9 @@ This wrapper does not implement any extra functionality.
 
 ```hcl
 terraform {
-  source = "tfr:///terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers"
+  source = "tfr:///terraform-aws-modules/ecs/aws//wrappers"
   # Alternative source:
-  # source = "git::git@github.com:terraform-aws-modules/terraform-aws-feature-svc-connect-timeout.git//wrappers?ref=master"
+  # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecs.git//wrappers?ref=master"
 }
 
 inputs = {
@@ -42,7 +42,7 @@ inputs = {
 
 ```hcl
 module "wrapper" {
-  source = "terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers"
+  source = "terraform-aws-modules/ecs/aws//wrappers"
 
   defaults = { # Default values
     create = true
diff --git a/wrappers/cluster/README.md b/wrappers/cluster/README.md
index 724fc78d..1a795281 100644
--- a/wrappers/cluster/README.md
+++ b/wrappers/cluster/README.md
@@ -12,9 +12,9 @@ This wrapper does not implement any extra functionality.
 
 ```hcl
 terraform {
-  source = "tfr:///terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/cluster"
+  source = "tfr:///terraform-aws-modules/ecs/aws//wrappers/cluster"
   # Alternative source:
-  # source = "git::git@github.com:terraform-aws-modules/terraform-aws-feature-svc-connect-timeout.git//wrappers/cluster?ref=master"
+  # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecs.git//wrappers/cluster?ref=master"
 }
 
 inputs = {
@@ -42,7 +42,7 @@ inputs = {
 
 ```hcl
 module "wrapper" {
-  source = "terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/cluster"
+  source = "terraform-aws-modules/ecs/aws//wrappers/cluster"
 
   defaults = { # Default values
     create = true
diff --git a/wrappers/cluster/versions.tf b/wrappers/cluster/versions.tf
index 5f6e023e..dc999065 100644
--- a/wrappers/cluster/versions.tf
+++ b/wrappers/cluster/versions.tf
@@ -4,7 +4,7 @@ terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
-      version = ">= 5.37"
+      version = ">= 5.59"
     }
   }
 }
diff --git a/wrappers/container-definition/README.md b/wrappers/container-definition/README.md
index 7fec4239..4731aa9a 100644
--- a/wrappers/container-definition/README.md
+++ b/wrappers/container-definition/README.md
@@ -12,9 +12,9 @@ This wrapper does not implement any extra functionality.
 
 ```hcl
 terraform {
-  source = "tfr:///terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/container-definition"
+  source = "tfr:///terraform-aws-modules/ecs/aws//wrappers/container-definition"
   # Alternative source:
-  # source = "git::git@github.com:terraform-aws-modules/terraform-aws-feature-svc-connect-timeout.git//wrappers/container-definition?ref=master"
+  # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecs.git//wrappers/container-definition?ref=master"
 }
 
 inputs = {
@@ -42,7 +42,7 @@ inputs = {
 
 ```hcl
 module "wrapper" {
-  source = "terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/container-definition"
+  source = "terraform-aws-modules/ecs/aws//wrappers/container-definition"
 
   defaults = { # Default values
     create = true
diff --git a/wrappers/container-definition/versions.tf b/wrappers/container-definition/versions.tf
index 5f6e023e..dc999065 100644
--- a/wrappers/container-definition/versions.tf
+++ b/wrappers/container-definition/versions.tf
@@ -4,7 +4,7 @@ terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
-      version = ">= 5.37"
+      version = ">= 5.59"
     }
   }
 }
diff --git a/wrappers/service/README.md b/wrappers/service/README.md
index 0704f3ba..219da916 100644
--- a/wrappers/service/README.md
+++ b/wrappers/service/README.md
@@ -12,9 +12,9 @@ This wrapper does not implement any extra functionality.
 
 ```hcl
 terraform {
-  source = "tfr:///terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/service"
+  source = "tfr:///terraform-aws-modules/ecs/aws//wrappers/service"
   # Alternative source:
-  # source = "git::git@github.com:terraform-aws-modules/terraform-aws-feature-svc-connect-timeout.git//wrappers/service?ref=master"
+  # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecs.git//wrappers/service?ref=master"
 }
 
 inputs = {
@@ -42,7 +42,7 @@ inputs = {
 
 ```hcl
 module "wrapper" {
-  source = "terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/service"
+  source = "terraform-aws-modules/ecs/aws//wrappers/service"
 
   defaults = { # Default values
     create = true
diff --git a/wrappers/service/versions.tf b/wrappers/service/versions.tf
index 5f6e023e..dc999065 100644
--- a/wrappers/service/versions.tf
+++ b/wrappers/service/versions.tf
@@ -4,7 +4,7 @@ terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
-      version = ">= 5.37"
+      version = ">= 5.59"
     }
   }
 }
diff --git a/wrappers/versions.tf b/wrappers/versions.tf
index 5f6e023e..dc999065 100644
--- a/wrappers/versions.tf
+++ b/wrappers/versions.tf
@@ -4,7 +4,7 @@ terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
-      version = ">= 5.37"
+      version = ">= 5.59"
     }
   }
 }