## Summary
This PR extends the Fleet ECS modules to support:
- configurable Fleet server private key delivery via ecs or iam
- optional fleet_config.command overrides for Fleet task definitions
- caller-managed Fleet server private key secrets via
fleet_config.private_key_secret_arn
It also updates the external vuln scans addon to follow the same
private-key delivery and command behavior, and refreshes the generated
module documentation.
## What changed
- Added fleet_config.private_key_delivery_method with supported values:
- ecs (default): inject the private key as FLEET_SERVER_PRIVATE_KEY
- iam: inject the secret ARN as FLEET_SERVER_PRIVATE_KEY_ARN
- Added validation so only ecs or iam are accepted
- Added fleet_config.command support so callers can override the Fleet
container command when needed
- Added fleet_config.private_key_secret_arn support so callers can
supply an existing Secrets Manager secret instead of having this module
create and populate one
- Updated IAM policy wiring so private-key secret access and private-key
KMS decrypt permissions are granted to the correct role based on the
selected delivery method
- Updated module outputs so fleet_server_private_key_secret_arn returns
the effective ARN whether the secret is module-managed or caller-managed
- Updated addons/external-vuln-scans to consume the same private-key
delivery mode and optional command behavior from the passed fleet_config
- Updated byo-ecs documentation and regenerated README files
## Behavior
### Private key delivery
- ecs mode injects the secret value into the container and uses the ECS
execution role for private-key secret access
- iam mode injects the secret ARN into the container environment and
uses the Fleet task role for private-key secret access
### Command override
- When fleet_config.command is unset, the task definition omits command
- When fleet_config.command is set, the provided command is passed
through to the Fleet container
- This behavior now applies consistently to both the main ECS service
and external vuln scans
### Caller-managed private key secret
- When fleet_config.private_key_secret_arn is unset, the module creates
and populates the Fleet private key secret
- When fleet_config.private_key_secret_arn is set, the module uses the
provided secret ARN and does not create the secret, secret version, or
generated random value
## KMS note for external secrets
If a caller-managed private-key secret uses a CMK, the caller must also
provide the existing private-key KMS ARN input so the correct role
receives decrypt permissions for the selected delivery mode.
## Validation
Validated successfully with:
- terraform validate -no-color at repo root
- terraform validate -no-color in byo-vpc
- terraform validate -no-color in byo-vpc/byo-db
- terraform validate -no-color in byo-vpc/byo-db/byo-ecs
Also verified that existing module-managed private-key resources plan as
non-destructive state-address moves when transitioning to the new
counted resources:
- 0 to add
- 0 to change
- 0 to destroy
174 lines
6.2 KiB
Terraform
174 lines
6.2 KiB
Terraform
data "aws_region" "current" {}
|
|
|
|
locals {
|
|
environment = [
|
|
// specifically overriding disable schedule here because the output of this module sets this to true
|
|
// and then we pull in the output of fleet ecs module
|
|
for k, v in merge(
|
|
var.fleet_config.extra_environment_variables,
|
|
{ FLEET_VULNERABILITIES_DISABLE_SCHEDULE = "false" }
|
|
) : {
|
|
name = k
|
|
value = v
|
|
}
|
|
]
|
|
secrets = [
|
|
for k, v in merge(var.fleet_config.extra_secrets, {
|
|
FLEET_MYSQL_PASSWORD = var.fleet_config.database.password_secret_arn
|
|
FLEET_MYSQL_READ_REPLICA_PASSWORD = var.fleet_config.database.password_secret_arn
|
|
}, var.fleet_config.private_key_delivery_method == "ecs" ? {
|
|
FLEET_SERVER_PRIVATE_KEY = var.fleet_server_private_key_secret_arn
|
|
} : {}) : {
|
|
name = k
|
|
valueFrom = v
|
|
}
|
|
]
|
|
repository_credentials = var.fleet_config.repository_credentials != "" ? {
|
|
repositoryCredentials = {
|
|
credentialsParameter = var.fleet_config.repository_credentials
|
|
}
|
|
} : null
|
|
}
|
|
|
|
resource "aws_ecs_service" "fleet" {
|
|
name = "${var.fleet_config.service.name}-vuln-processing"
|
|
launch_type = "FARGATE"
|
|
cluster = var.ecs_cluster
|
|
task_definition = aws_ecs_task_definition.vuln-processing.arn
|
|
desired_count = 1
|
|
deployment_minimum_healthy_percent = 100
|
|
deployment_maximum_percent = 200
|
|
|
|
lifecycle {
|
|
ignore_changes = [desired_count]
|
|
}
|
|
|
|
network_configuration {
|
|
subnets = var.subnets
|
|
security_groups = var.security_groups
|
|
}
|
|
}
|
|
|
|
resource "aws_ecs_task_definition" "vuln-processing" {
|
|
family = "${var.fleet_config.family}-vuln-processing"
|
|
cpu = var.vuln_processing_task_cpu
|
|
memory = var.vuln_processing_task_memory
|
|
execution_role_arn = var.execution_iam_role_arn
|
|
task_role_arn = var.task_role_arn
|
|
network_mode = "awsvpc"
|
|
pid_mode = var.fleet_config.pid_mode
|
|
requires_compatibilities = ["FARGATE"]
|
|
|
|
container_definitions = jsonencode(concat([
|
|
merge(
|
|
{
|
|
name = "fleet-vuln-processing"
|
|
image = var.fleet_config.image
|
|
cpu = var.vuln_processing_cpu
|
|
memory = var.vuln_processing_memory
|
|
essential = true
|
|
networkMode = "awsvpc"
|
|
secrets = local.secrets
|
|
repositoryCredentials = local.repository_credentials
|
|
mountPoints = var.fleet_config.mount_points
|
|
dependsOn = var.fleet_config.depends_on
|
|
ulimits = [
|
|
{
|
|
name = "nofile"
|
|
softLimit = 999999
|
|
hardLimit = 999999
|
|
}
|
|
]
|
|
environment = concat([
|
|
{
|
|
name = "FLEET_MYSQL_USERNAME"
|
|
value = var.fleet_config.database.user
|
|
},
|
|
{
|
|
name = "FLEET_MYSQL_DATABASE"
|
|
value = var.fleet_config.database.database
|
|
},
|
|
{
|
|
name = "FLEET_MYSQL_ADDRESS"
|
|
value = var.fleet_config.database.address
|
|
},
|
|
{
|
|
name = "FLEET_MYSQL_READ_REPLICA_USERNAME"
|
|
value = var.fleet_config.database.user
|
|
},
|
|
{
|
|
name = "FLEET_MYSQL_READ_REPLICA_DATABASE"
|
|
value = var.fleet_config.database.database
|
|
},
|
|
{
|
|
name = "FLEET_MYSQL_READ_REPLICA_ADDRESS"
|
|
value = var.fleet_config.database.rr_address == null ? var.fleet_config.database.address : var.fleet_config.database.rr_address
|
|
},
|
|
{
|
|
name = "FLEET_REDIS_ADDRESS"
|
|
value = var.fleet_config.redis.address
|
|
},
|
|
{
|
|
name = "FLEET_REDIS_USE_TLS"
|
|
value = tostring(var.fleet_config.redis.use_tls)
|
|
},
|
|
{
|
|
name = "FLEET_SERVER_TLS"
|
|
value = tostring(try(var.fleet_config.server_tls_enabled, false))
|
|
},
|
|
{
|
|
name = "FLEET_S3_SOFTWARE_INSTALLERS_BUCKET"
|
|
value = var.fleet_s3_software_installers_config.bucket_name
|
|
},
|
|
{
|
|
name = "FLEET_S3_SOFTWARE_INSTALLERS_PREFIX"
|
|
value = var.fleet_s3_software_installers_config.s3_object_prefix
|
|
}
|
|
], var.fleet_config.private_key_delivery_method == "iam" ? [{
|
|
name = "FLEET_SERVER_PRIVATE_KEY_ARN"
|
|
value = var.fleet_server_private_key_secret_arn
|
|
}] : [], local.environment)
|
|
logConfiguration = {
|
|
logDriver = "awslogs"
|
|
options = {
|
|
awslogs-group = var.awslogs_config.group
|
|
awslogs-region = var.awslogs_config.region == null ? data.aws_region.current.region : var.awslogs_config.region
|
|
awslogs-stream-prefix = "${var.awslogs_config.prefix}-vuln-processing"
|
|
}
|
|
}
|
|
},
|
|
var.fleet_config.command != null ? {
|
|
command = var.fleet_config.command
|
|
} : {}
|
|
)]
|
|
, var.fleet_config.sidecars))
|
|
|
|
dynamic "volume" {
|
|
for_each = var.fleet_config.volumes
|
|
content {
|
|
name = volume.value.name
|
|
host_path = lookup(volume.value, "host_path", null)
|
|
|
|
dynamic "docker_volume_configuration" {
|
|
for_each = lookup(volume.value, "docker_volume_configuration", [])
|
|
content {
|
|
scope = lookup(docker_volume_configuration.value, "scope", null)
|
|
autoprovision = lookup(docker_volume_configuration.value, "autoprovision", null)
|
|
driver = lookup(docker_volume_configuration.value, "driver", null)
|
|
driver_opts = lookup(docker_volume_configuration.value, "driver_opts", null)
|
|
labels = lookup(docker_volume_configuration.value, "labels", null)
|
|
}
|
|
}
|
|
|
|
dynamic "efs_volume_configuration" {
|
|
for_each = lookup(volume.value, "efs_volume_configuration", [])
|
|
content {
|
|
file_system_id = lookup(efs_volume_configuration.value, "file_system_id", null)
|
|
root_directory = lookup(efs_volume_configuration.value, "root_directory", null)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|