From dc4ea6168a80d2554769711c48211e6c5e820868 Mon Sep 17 00:00:00 2001 From: lukzhang Date: Fri, 7 Nov 2025 19:28:54 -0500 Subject: [PATCH 01/11] feat(container): Add support for credentialSpecs to enable Windows gMSA --- examples/windows-gmsa-service/main.tf | 58 +++++++++++++++++++++++ examples/windows-gmsa-service/outputs.tf | 4 ++ examples/windows-gmsa-service/versions.tf | 9 ++++ modules/container-definition/README.md | 1 + modules/container-definition/main.tf | 1 + modules/container-definition/variables.tf | 6 +++ modules/service/README.md | 2 +- modules/service/main.tf | 1 + modules/service/variables.tf | 5 +- 9 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 examples/windows-gmsa-service/main.tf create mode 100644 examples/windows-gmsa-service/outputs.tf create mode 100644 examples/windows-gmsa-service/versions.tf diff --git a/examples/windows-gmsa-service/main.tf b/examples/windows-gmsa-service/main.tf new file mode 100644 index 0000000..d3eb1c7 --- /dev/null +++ b/examples/windows-gmsa-service/main.tf @@ -0,0 +1,58 @@ +# This example demonstrates how to configure a Windows task to use gMSA + +# 1. Dummy Secrets Manager Secret (The credential spec ARN is stored here) +resource "aws_secretsmanager_secret" "gmsa_secret" { + name = "gmsa-credential-spec-example" +} + +# 2. Container Definition using the updated module +module "app_container" { + source = "../../modules/container-definition" # Relative path to the module you are modifying + + name = "windows-app" + image = "mcr.microsoft.com/windows/servercore:ltsc2022" + cpu = 512 + memory = 1024 + essential = true + + # IMPORTANT: The OS must be Windows for credentialSpecs to be valid + # Note: The 'operating_system_family' variable must also be present in the module's HCL + operating_system_family = "WINDOWS_SERVER_2022_CORE" + + # The new feature being demonstrated, using a known placeholder ARN + credentialSpecs = [ + aws_secretsmanager_secret.gmsa_secret.arn + ] +} + +# 3. Dummy Task Execution Role (Required for a runnable Task Definition) +resource "aws_iam_role" "ecs_task_execution_role" { + name = "ecs-gMSA-example-execution-role" + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "ecs-tasks.amazonaws.com" + } + }] + }) +} + +# 4. Task Definition that uses the container +resource "aws_ecs_task_definition" "windows_task" { + family = "windows-gmsa-task" + requires_compatibilities = ["FARGATE"] + cpu = 1024 + memory = 2048 + network_mode = "awsvpc" + execution_role_arn = aws_iam_role.ecs_task_execution_role.arn + + # The container definition must be JSON encoded + container_definitions = jsonencode([module.app_container.container_definition]) + + runtime_platform { + operating_system_family = "WINDOWS_SERVER_2022_CORE" + } +} \ No newline at end of file diff --git a/examples/windows-gmsa-service/outputs.tf b/examples/windows-gmsa-service/outputs.tf new file mode 100644 index 0000000..8c557a5 --- /dev/null +++ b/examples/windows-gmsa-service/outputs.tf @@ -0,0 +1,4 @@ +output "task_definition_arn" { + description = "The ARN of the ECS Task Definition created with gMSA credentials." + value = aws_ecs_task_definition.windows_task.arn +} \ No newline at end of file diff --git a/examples/windows-gmsa-service/versions.tf b/examples/windows-gmsa-service/versions.tf new file mode 100644 index 0000000..b51fb48 --- /dev/null +++ b/examples/windows-gmsa-service/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.0" + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 6.0" + } + } +} \ No newline at end of file diff --git a/modules/container-definition/README.md b/modules/container-definition/README.md index b5b994e..9f2722a 100644 --- a/modules/container-definition/README.md +++ b/modules/container-definition/README.md @@ -145,6 +145,7 @@ No modules. | [cloudwatch\_log\_group\_retention\_in\_days](#input\_cloudwatch\_log\_group\_retention\_in\_days) | Number of days to retain log events. Set to `0` to keep logs indefinitely | `number` | `14` | no | | [cloudwatch\_log\_group\_use\_name\_prefix](#input\_cloudwatch\_log\_group\_use\_name\_prefix) | Determines whether the log group name should be used as a prefix | `bool` | `false` | no | | [command](#input\_command) | The command that's passed to the container | `list(string)` | `null` | no | +| [credentialSpecs](#input\_credentialSpecs) | Specs for Credentials for gMSA (Windows containers) | `list(string)` | `null` | no | | [cpu](#input\_cpu) | The number of cpu units to reserve for the container. This is optional for tasks using Fargate launch type and the total amount of `cpu` of all containers in a task will need to be lower than the task-level cpu value | `number` | `null` | no | | [create\_cloudwatch\_log\_group](#input\_create\_cloudwatch\_log\_group) | Determines whether a log group is created by this module. If not, AWS will automatically create one if logging is enabled | `bool` | `true` | no | | [dependsOn](#input\_dependsOn) | The dependencies defined for container startup and shutdown. A container can contain multiple dependencies. When a dependency is defined for container startup, for container shutdown it is reversed. The condition can be one of START, COMPLETE, SUCCESS or HEALTHY |
list(object({
condition = string
containerName = string
}))
| `null` | no | diff --git a/modules/container-definition/main.tf b/modules/container-definition/main.tf index cf73471..7d4ceb4 100644 --- a/modules/container-definition/main.tf +++ b/modules/container-definition/main.tf @@ -39,6 +39,7 @@ locals { definition = { command = var.command cpu = var.cpu + credentialSpecs = var.credentialSpecs dependsOn = var.dependsOn disableNetworking = local.is_not_windows ? var.disableNetworking : null dnsSearchDomains = local.is_not_windows ? var.dnsSearchDomains : null diff --git a/modules/container-definition/variables.tf b/modules/container-definition/variables.tf index 0c7d229..d666942 100644 --- a/modules/container-definition/variables.tf +++ b/modules/container-definition/variables.tf @@ -34,6 +34,12 @@ variable "cpu" { default = null } +variable "credentialSpecs" { + description = "Specs for Credentials for gMSA (Windows containers)." + type = list(string) + default = [] +} + # tflint-ignore: terraform_naming_convention variable "dependsOn" { description = "The dependencies defined for container startup and shutdown. A container can contain multiple dependencies. When a dependency is defined for container startup, for container shutdown it is reversed. The condition can be one of START, COMPLETE, SUCCESS or HEALTHY" diff --git a/modules/service/README.md b/modules/service/README.md index 8891e50..2591492 100644 --- a/modules/service/README.md +++ b/modules/service/README.md @@ -238,7 +238,7 @@ module "ecs_service" { | [availability\_zone\_rebalancing](#input\_availability\_zone\_rebalancing) | ECS automatically redistributes tasks within a service across Availability Zones (AZs) to mitigate the risk of impaired application availability due to underlying infrastructure failures and task lifecycle activities. The valid values are `ENABLED` and `DISABLED`. Defaults to `DISABLED` | `string` | `null` | no | | [capacity\_provider\_strategy](#input\_capacity\_provider\_strategy) | Capacity provider strategies to use for the service. Can be one or more |
map(object({
base = optional(number)
capacity_provider = string
weight = optional(number)
}))
| `null` | no | | [cluster\_arn](#input\_cluster\_arn) | ARN of the ECS cluster where the resources will be provisioned | `string` | `""` | no | -| [container\_definitions](#input\_container\_definitions) | A map of valid [container definitions](http://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDefinition.html). Please note that you should only provide values that are part of the container definition document |
map(object({
create = optional(bool, true)
operating_system_family = optional(string)
tags = optional(map(string))

# Container definition
command = optional(list(string))
cpu = optional(number)
dependsOn = optional(list(object({
condition = string
containerName = string
})))
disableNetworking = optional(bool)
dnsSearchDomains = optional(list(string))
dnsServers = optional(list(string))
dockerLabels = optional(map(string))
dockerSecurityOptions = optional(list(string))
# enable_execute_command = optional(bool, false) Set in standalone variable
entrypoint = optional(list(string))
environment = optional(list(object({
name = string
value = string
})))
environmentFiles = optional(list(object({
type = string
value = string
})))
essential = optional(bool)
extraHosts = optional(list(object({
hostname = string
ipAddress = string
})))
firelensConfiguration = optional(object({
options = optional(map(string))
type = optional(string)
}))
healthCheck = optional(object({
command = optional(list(string), [])
interval = optional(number, 30)
retries = optional(number, 3)
startPeriod = optional(number)
timeout = optional(number, 5)
}))
hostname = optional(string)
image = optional(string)
interactive = optional(bool)
links = optional(list(string))
linuxParameters = optional(object({
capabilities = optional(object({
add = optional(list(string))
drop = optional(list(string))
}))
devices = optional(list(object({
containerPath = optional(string)
hostPath = optional(string)
permissions = optional(list(string))
})))
initProcessEnabled = optional(bool)
maxSwap = optional(number)
sharedMemorySize = optional(number)
swappiness = optional(number)
tmpfs = optional(list(object({
containerPath = string
mountOptions = optional(list(string))
size = number
})))
}))
logConfiguration = optional(object({
logDriver = optional(string)
options = optional(map(string))
secretOptions = optional(list(object({
name = string
valueFrom = string
})))
}))
memory = optional(number)
memoryReservation = optional(number)
mountPoints = optional(list(object({
containerPath = optional(string)
readOnly = optional(bool)
sourceVolume = optional(string)
})))
name = optional(string)
portMappings = optional(list(object({
appProtocol = optional(string)
containerPort = optional(number)
containerPortRange = optional(string)
hostPort = optional(number)
name = optional(string)
protocol = optional(string)
})))
privileged = optional(bool)
pseudoTerminal = optional(bool)
readonlyRootFilesystem = optional(bool)
repositoryCredentials = optional(object({
credentialsParameter = optional(string)
}))
resourceRequirements = optional(list(object({
type = string
value = string
})))
restartPolicy = optional(object({
enabled = optional(bool)
ignoredExitCodes = optional(list(number))
restartAttemptPeriod = optional(number)
})
)
secrets = optional(list(object({
name = string
valueFrom = string
})))
startTimeout = optional(number, 30)
stopTimeout = optional(number, 120)
systemControls = optional(list(object({
namespace = optional(string)
value = optional(string)
})))
ulimits = optional(list(object({
hardLimit = number
name = string
softLimit = number
})))
user = optional(string)
versionConsistency = optional(string)
volumesFrom = optional(list(object({
readOnly = optional(bool)
sourceContainer = optional(string)
})))
workingDirectory = optional(string)

# Cloudwatch Log Group
service = optional(string)
enable_cloudwatch_logging = optional(bool)
create_cloudwatch_log_group = optional(bool)
cloudwatch_log_group_name = optional(string)
cloudwatch_log_group_use_name_prefix = optional(bool)
cloudwatch_log_group_class = optional(string)
cloudwatch_log_group_retention_in_days = optional(number)
cloudwatch_log_group_kms_key_id = optional(string)
}))
| `{}` | no | +| [container\_definitions](#input\_container\_definitions) | A map of valid [container definitions](http://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDefinition.html). Please note that you should only provide values that are part of the container definition document |
map(object({
create = optional(bool, true)
operating_system_family = optional(string)
tags = optional(map(string))

# Container definition
command = optional(list(string))
cpu = optional(number)

credentialSpecs = optional(list(string))
dependsOn = optional(list(object({
condition = string
containerName = string
})))
disableNetworking = optional(bool)
dnsSearchDomains = optional(list(string))
dnsServers = optional(list(string))
dockerLabels = optional(map(string))
dockerSecurityOptions = optional(list(string))
# enable_execute_command = optional(bool, false) Set in standalone variable
entrypoint = optional(list(string))
environment = optional(list(object({
name = string
value = string
})))
environmentFiles = optional(list(object({
type = string
value = string
})))
essential = optional(bool)
extraHosts = optional(list(object({
hostname = string
ipAddress = string
})))
firelensConfiguration = optional(object({
options = optional(map(string))
type = optional(string)
}))
healthCheck = optional(object({
command = optional(list(string), [])
interval = optional(number, 30)
retries = optional(number, 3)
startPeriod = optional(number)
timeout = optional(number, 5)
}))
hostname = optional(string)
image = optional(string)
interactive = optional(bool)
links = optional(list(string))
linuxParameters = optional(object({
capabilities = optional(object({
add = optional(list(string))
drop = optional(list(string))
}))
devices = optional(list(object({
containerPath = optional(string)
hostPath = optional(string)
permissions = optional(list(string))
})))
initProcessEnabled = optional(bool)
maxSwap = optional(number)
sharedMemorySize = optional(number)
swappiness = optional(number)
tmpfs = optional(list(object({
containerPath = string
mountOptions = optional(list(string))
size = number
})))
}))
logConfiguration = optional(object({
logDriver = optional(string)
options = optional(map(string))
secretOptions = optional(list(object({
name = string
valueFrom = string
})))
}))
memory = optional(number)
memoryReservation = optional(number)
mountPoints = optional(list(object({
containerPath = optional(string)
readOnly = optional(bool)
sourceVolume = optional(string)
})))
name = optional(string)
portMappings = optional(list(object({
appProtocol = optional(string)
containerPort = optional(number)
containerPortRange = optional(string)
hostPort = optional(number)
name = optional(string)
protocol = optional(string)
})))
privileged = optional(bool)
pseudoTerminal = optional(bool)
readonlyRootFilesystem = optional(bool)
repositoryCredentials = optional(object({
credentialsParameter = optional(string)
}))
resourceRequirements = optional(list(object({
type = string
value = string
})))
restartPolicy = optional(object({
enabled = optional(bool)
ignoredExitCodes = optional(list(number))
restartAttemptPeriod = optional(number)
})
)
secrets = optional(list(object({
name = string
valueFrom = string
})))
startTimeout = optional(number, 30)
stopTimeout = optional(number, 120)
systemControls = optional(list(object({
namespace = optional(string)
value = optional(string)
})))
ulimits = optional(list(object({
hardLimit = number
name = string
softLimit = number
})))
user = optional(string)
versionConsistency = optional(string)
volumesFrom = optional(list(object({
readOnly = optional(bool)
sourceContainer = optional(string)
})))
workingDirectory = optional(string)

# Cloudwatch Log Group
service = optional(string)
enable_cloudwatch_logging = optional(bool)
create_cloudwatch_log_group = optional(bool)
cloudwatch_log_group_name = optional(string)
cloudwatch_log_group_use_name_prefix = optional(bool)
cloudwatch_log_group_class = optional(string)
cloudwatch_log_group_retention_in_days = optional(number)
cloudwatch_log_group_kms_key_id = optional(string)
}))
| `{}` | no | | [cpu](#input\_cpu) | Number of cpu units used by the task. If the `requires_compatibilities` is `FARGATE` this field is required | `number` | `1024` | no | | [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no | | [create\_iam\_role](#input\_create\_iam\_role) | Determines whether the ECS service IAM role should be created | `bool` | `true` | no | diff --git a/modules/service/main.tf b/modules/service/main.tf index f467f56..70b04ba 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -814,6 +814,7 @@ module "container_definition" { # Container Definition command = each.value.command cpu = each.value.cpu + credentialSpecs = each.value.credentialSpecs dependsOn = each.value.dependsOn disableNetworking = each.value.disableNetworking dnsSearchDomains = each.value.dnsSearchDomains diff --git a/modules/service/variables.tf b/modules/service/variables.tf index 42afafc..7948e31 100644 --- a/modules/service/variables.tf +++ b/modules/service/variables.tf @@ -475,8 +475,9 @@ variable "container_definitions" { tags = optional(map(string)) # Container definition - command = optional(list(string)) - cpu = optional(number) + command = optional(list(string)) + cpu = optional(number) + credentialSpecs = optional(list(string)) dependsOn = optional(list(object({ condition = string containerName = string From 198b3171eacd0f1f7a3e93c30aa5765316ea689e Mon Sep 17 00:00:00 2001 From: Luke Zhang <31868012+lukzhang@users.noreply.github.com> Date: Fri, 7 Nov 2025 19:50:35 -0500 Subject: [PATCH 02/11] Update modules/container-definition/variables.tf Co-authored-by: Bryant Biggs --- modules/container-definition/variables.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/container-definition/variables.tf b/modules/container-definition/variables.tf index d666942..82f411b 100644 --- a/modules/container-definition/variables.tf +++ b/modules/container-definition/variables.tf @@ -37,7 +37,7 @@ variable "cpu" { variable "credentialSpecs" { description = "Specs for Credentials for gMSA (Windows containers)." type = list(string) - default = [] + default = null } # tflint-ignore: terraform_naming_convention From 0a745b437f81ddf72d5a6c61624fd9df451c13e4 Mon Sep 17 00:00:00 2001 From: lukzhang Date: Fri, 7 Nov 2025 20:08:00 -0500 Subject: [PATCH 03/11] propogate to all instances from root variables.tf --- examples/windows-gmsa-service/main.tf | 58 ----------------------- examples/windows-gmsa-service/outputs.tf | 4 -- examples/windows-gmsa-service/versions.tf | 9 ---- variables.tf | 1 + 4 files changed, 1 insertion(+), 71 deletions(-) delete mode 100644 examples/windows-gmsa-service/main.tf delete mode 100644 examples/windows-gmsa-service/outputs.tf delete mode 100644 examples/windows-gmsa-service/versions.tf diff --git a/examples/windows-gmsa-service/main.tf b/examples/windows-gmsa-service/main.tf deleted file mode 100644 index d3eb1c7..0000000 --- a/examples/windows-gmsa-service/main.tf +++ /dev/null @@ -1,58 +0,0 @@ -# This example demonstrates how to configure a Windows task to use gMSA - -# 1. Dummy Secrets Manager Secret (The credential spec ARN is stored here) -resource "aws_secretsmanager_secret" "gmsa_secret" { - name = "gmsa-credential-spec-example" -} - -# 2. Container Definition using the updated module -module "app_container" { - source = "../../modules/container-definition" # Relative path to the module you are modifying - - name = "windows-app" - image = "mcr.microsoft.com/windows/servercore:ltsc2022" - cpu = 512 - memory = 1024 - essential = true - - # IMPORTANT: The OS must be Windows for credentialSpecs to be valid - # Note: The 'operating_system_family' variable must also be present in the module's HCL - operating_system_family = "WINDOWS_SERVER_2022_CORE" - - # The new feature being demonstrated, using a known placeholder ARN - credentialSpecs = [ - aws_secretsmanager_secret.gmsa_secret.arn - ] -} - -# 3. Dummy Task Execution Role (Required for a runnable Task Definition) -resource "aws_iam_role" "ecs_task_execution_role" { - name = "ecs-gMSA-example-execution-role" - assume_role_policy = jsonencode({ - Version = "2012-10-17" - Statement = [{ - Action = "sts:AssumeRole" - Effect = "Allow" - Principal = { - Service = "ecs-tasks.amazonaws.com" - } - }] - }) -} - -# 4. Task Definition that uses the container -resource "aws_ecs_task_definition" "windows_task" { - family = "windows-gmsa-task" - requires_compatibilities = ["FARGATE"] - cpu = 1024 - memory = 2048 - network_mode = "awsvpc" - execution_role_arn = aws_iam_role.ecs_task_execution_role.arn - - # The container definition must be JSON encoded - container_definitions = jsonencode([module.app_container.container_definition]) - - runtime_platform { - operating_system_family = "WINDOWS_SERVER_2022_CORE" - } -} \ No newline at end of file diff --git a/examples/windows-gmsa-service/outputs.tf b/examples/windows-gmsa-service/outputs.tf deleted file mode 100644 index 8c557a5..0000000 --- a/examples/windows-gmsa-service/outputs.tf +++ /dev/null @@ -1,4 +0,0 @@ -output "task_definition_arn" { - description = "The ARN of the ECS Task Definition created with gMSA credentials." - value = aws_ecs_task_definition.windows_task.arn -} \ No newline at end of file diff --git a/examples/windows-gmsa-service/versions.tf b/examples/windows-gmsa-service/versions.tf deleted file mode 100644 index b51fb48..0000000 --- a/examples/windows-gmsa-service/versions.tf +++ /dev/null @@ -1,9 +0,0 @@ -terraform { - required_version = ">= 1.0" - required_providers { - aws = { - source = "hashicorp/aws" - version = ">= 6.0" - } - } -} \ No newline at end of file diff --git a/variables.tf b/variables.tf index b537cb9..f943701 100644 --- a/variables.tf +++ b/variables.tf @@ -447,6 +447,7 @@ variable "services" { # Container definition command = optional(list(string)) cpu = optional(number) + credentialSpecs = each.value.credentialSpecs dependsOn = optional(list(object({ condition = string containerName = string From 762e7ff927a98135ec04c61d4f25f41ba421fb64 Mon Sep 17 00:00:00 2001 From: lukzhang Date: Fri, 7 Nov 2025 20:19:57 -0500 Subject: [PATCH 04/11] propogate to all instances from root variables.tf --- variables.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variables.tf b/variables.tf index f943701..045b517 100644 --- a/variables.tf +++ b/variables.tf @@ -447,7 +447,7 @@ variable "services" { # Container definition command = optional(list(string)) cpu = optional(number) - credentialSpecs = each.value.credentialSpecs + credentialSpecs = optional(list(string)) dependsOn = optional(list(object({ condition = string containerName = string From a30e4228e8f934c870321e55ce0674eadb4057e6 Mon Sep 17 00:00:00 2001 From: lukzhang Date: Fri, 7 Nov 2025 21:54:05 -0500 Subject: [PATCH 05/11] original format --- variables.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variables.tf b/variables.tf index 045b517..6f34423 100644 --- a/variables.tf +++ b/variables.tf @@ -445,7 +445,7 @@ variable "services" { tags = optional(map(string)) # Container definition - command = optional(list(string)) + command = optional(list(string)) #test cpu = optional(number) credentialSpecs = optional(list(string)) dependsOn = optional(list(object({ From fd4cf3b20171fa7b06ccdb664783e6a5ba24316d Mon Sep 17 00:00:00 2001 From: lukzhang Date: Fri, 7 Nov 2025 21:54:18 -0500 Subject: [PATCH 06/11] original format --- variables.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variables.tf b/variables.tf index 6f34423..045b517 100644 --- a/variables.tf +++ b/variables.tf @@ -445,7 +445,7 @@ variable "services" { tags = optional(map(string)) # Container definition - command = optional(list(string)) #test + command = optional(list(string)) cpu = optional(number) credentialSpecs = optional(list(string)) dependsOn = optional(list(object({ From 39c54280eabd2a12ca09334a16d74a8f77cc9954 Mon Sep 17 00:00:00 2001 From: lukzhang Date: Fri, 7 Nov 2025 21:55:20 -0500 Subject: [PATCH 07/11] original format --- variables.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/variables.tf b/variables.tf index 045b517..5231cd8 100644 --- a/variables.tf +++ b/variables.tf @@ -445,8 +445,8 @@ variable "services" { tags = optional(map(string)) # Container definition - command = optional(list(string)) - cpu = optional(number) + command = optional(list(string)) + cpu = optional(number) credentialSpecs = optional(list(string)) dependsOn = optional(list(object({ condition = string From 4faff869cb250c623c61f5ea17a66b506a00aa10 Mon Sep 17 00:00:00 2001 From: lukzhang Date: Fri, 7 Nov 2025 21:55:28 -0500 Subject: [PATCH 08/11] original format --- variables.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/variables.tf b/variables.tf index 5231cd8..045b517 100644 --- a/variables.tf +++ b/variables.tf @@ -445,8 +445,8 @@ variable "services" { tags = optional(map(string)) # Container definition - command = optional(list(string)) - cpu = optional(number) + command = optional(list(string)) + cpu = optional(number) credentialSpecs = optional(list(string)) dependsOn = optional(list(object({ condition = string From 6045d45cd88de3a6480d31580179fa2f3c241b56 Mon Sep 17 00:00:00 2001 From: lukzhang Date: Fri, 7 Nov 2025 22:02:46 -0500 Subject: [PATCH 09/11] reformat --- variables.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/variables.tf b/variables.tf index 045b517..5231cd8 100644 --- a/variables.tf +++ b/variables.tf @@ -445,8 +445,8 @@ variable "services" { tags = optional(map(string)) # Container definition - command = optional(list(string)) - cpu = optional(number) + command = optional(list(string)) + cpu = optional(number) credentialSpecs = optional(list(string)) dependsOn = optional(list(object({ condition = string From 216815a08e304790a0c9df75ddb307b07159f508 Mon Sep 17 00:00:00 2001 From: lukzhang Date: Fri, 7 Nov 2025 22:28:50 -0500 Subject: [PATCH 10/11] added wrapper main --- wrappers/container-definition/main.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/wrappers/container-definition/main.tf b/wrappers/container-definition/main.tf index c187ddd..776628c 100644 --- a/wrappers/container-definition/main.tf +++ b/wrappers/container-definition/main.tf @@ -10,6 +10,7 @@ module "wrapper" { cloudwatch_log_group_use_name_prefix = try(each.value.cloudwatch_log_group_use_name_prefix, var.defaults.cloudwatch_log_group_use_name_prefix, false) command = try(each.value.command, var.defaults.command, null) cpu = try(each.value.cpu, var.defaults.cpu, null) + credentialSpecs = try(each.value.credentialSpecs, var.defaults.credentialSpecs, null) create_cloudwatch_log_group = try(each.value.create_cloudwatch_log_group, var.defaults.create_cloudwatch_log_group, true) dependsOn = try(each.value.dependsOn, var.defaults.dependsOn, null) disableNetworking = try(each.value.disableNetworking, var.defaults.disableNetworking, null) From a3d490403ae0faf92810006871e2271c410a285b Mon Sep 17 00:00:00 2001 From: lukzhang Date: Fri, 7 Nov 2025 22:40:53 -0500 Subject: [PATCH 11/11] reorder alphabetical --- wrappers/container-definition/main.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wrappers/container-definition/main.tf b/wrappers/container-definition/main.tf index 776628c..5e027c3 100644 --- a/wrappers/container-definition/main.tf +++ b/wrappers/container-definition/main.tf @@ -9,9 +9,9 @@ module "wrapper" { cloudwatch_log_group_retention_in_days = try(each.value.cloudwatch_log_group_retention_in_days, var.defaults.cloudwatch_log_group_retention_in_days, 14) cloudwatch_log_group_use_name_prefix = try(each.value.cloudwatch_log_group_use_name_prefix, var.defaults.cloudwatch_log_group_use_name_prefix, false) command = try(each.value.command, var.defaults.command, null) - cpu = try(each.value.cpu, var.defaults.cpu, null) - credentialSpecs = try(each.value.credentialSpecs, var.defaults.credentialSpecs, null) + cpu = try(each.value.cpu, var.defaults.cpu, null) create_cloudwatch_log_group = try(each.value.create_cloudwatch_log_group, var.defaults.create_cloudwatch_log_group, true) + credentialSpecs = try(each.value.credentialSpecs, var.defaults.credentialSpecs, null) dependsOn = try(each.value.dependsOn, var.defaults.dependsOn, null) disableNetworking = try(each.value.disableNetworking, var.defaults.disableNetworking, null) dnsSearchDomains = try(each.value.dnsSearchDomains, var.defaults.dnsSearchDomains, null)