Files

This module deploys Fleet into an existing VPC while still provisioning the supporting AWS services that Fleet needs, including Aurora, ElastiCache, ECS, and the ALB.

Aurora Blue-Green Restore Cutovers

Module shape

rds_config remains available for existing callers. New callers can manage multiple named Aurora clusters with rds_configs and select the cluster used by Fleet with active_rds_config_name:

rds_configs = {
  current = {
    name = "fleet"
  }

  restored = {
    name                = "fleet-restored"
    snapshot_identifier = "fleet-cutover-snapshot"
  }
}

active_rds_config_name = "current"

The default selector is "current". Each entry creates its own Aurora cluster, password, password secret, optional CMKs, parameter groups, and final-snapshot identifier. Cluster name values must be unique. Any module-created KMS aliases must also be unique across simultaneously managed clusters.

The root module accepts the same interface and supplies its database subnets to every entry. Direct byo-vpc callers must continue to provide subnets in each entry.

Backward-compatible migration

When rds_configs is null, the module normalizes the legacy input to:

{
  current = var.rds_config
}

Moved blocks map the existing singleton cluster and its wrapper-owned resources to the "current" instances. Upgrade with the existing configuration first and review the plan before adding another cluster. The migration should show address moves, not replacement of the current Aurora cluster, password, parameter groups, or optional KMS keys.

The existing rds, rds_password_secret_kms_key_arn, byo-db, and byo-ecs interfaces continue to describe only the selected cluster. rds_clusters and rds_password_secret_kms_key_arns expose the complete maps for callers that need them.

Restore and cutover

  1. Replace rds_config with an equivalent rds_configs.current entry and apply the address-only migration.
  2. Create or choose the snapshot or point-in-time source for the restored cluster.
  3. Add a second entry with a unique name, restore settings, and unique aliases for every module-created CMK. Keep active_rds_config_name = "current" and apply.
  4. Validate the restored cluster. A snapshot or point-in-time restore is not ongoing replication, so quiesce writes or provide a separate data-synchronization step before cutover if the source remains writable.
  5. Change active_rds_config_name to the restored entry and apply. This updates the unchanged byo-db/byo-ecs contract to use the selected endpoint, credentials secret, and password-secret KMS key.
  6. Redeploy or restart Fleet tasks as required, validate the application, and retain the old entry for the desired rollback window.
  7. Remove the retired entry only after its rollback and backup retention requirements have been met.

This workflow keeps both clusters in Terraform state throughout the cutover. The historical rds_storage_kms_migration.sh helper remains documented below for deployments that need it.

KMS Coverage

This module adds optional CMK support for:

  • Aurora storage encryption
  • Aurora database password secret encryption in Secrets Manager
  • Aurora observability encryption for Performance Insights / Database Insights
  • Aurora exported CloudWatch log groups
  • ElastiCache at-rest encryption
  • ElastiCache CloudWatch log groups for cloudwatch-logs delivery targets
  • Nested ECS cluster, Fleet service, application logs, and Fleet secrets through child-module passthroughs

For each feature:

  • cmk_enabled = true means "use a customer-managed KMS key here."
  • Set cmk_enabled = false or omit it to keep using the service-managed key.
  • For KMS options that existed in published releases before this change, legacy enabled is deprecated but still accepted. Terraform plan/apply warns when it is used, and cmk_enabled takes precedence if both are set.
  • Set cmk_enabled = true without a key ARN to have the module create a CMK and alias.
  • Set kms_key_arn to use an existing CMK.

Provided CMKs must already allow the relevant AWS service in their key policy.

Aurora Database Insights

rds_config.observability manages Aurora observability behavior:

  • database_insights_mode = null leaves Standard vs Advanced unmanaged.
  • database_insights_mode = "standard" enforces Standard Database Insights.
  • database_insights_mode = "advanced" requires:
    • performance_insights_enabled = true
    • monitoring_interval > 0
    • retention_period >= 465

AWS has announced the Performance Insights console end of life for June 30, 2026. Standard Database Insights is a clean forward path for existing clusters that are already using Standard outside Terraform.

Aurora Backtrack

rds_config.backtrack_window is optional and passes Aurora MySQL backtracking through to the upstream rds-aurora module.

  • Set it to a value between 0 and 259200 seconds.
  • Set 0 to disable backtracking explicitly.
  • Leave it null to keep the default upstream behavior.

Aurora Final Snapshot Naming

rds_config.final_snapshot_identifier is optional.

  • Set it explicitly if you want a fixed final snapshot name.
  • Leave it null to preserve the legacy generated naming pattern: final-<rds_config.name>-<8-digit-hex>.

Monitoring Addon Secret KMS Wiring

If you enable rds_config.password_secret_kms, the byo-vpc module also exposes rds_password_secret_kms_key_arn.

That output is intended to be passed through to the monitoring addon so the cron-monitoring Lambda can decrypt the Fleet database password secret when it is encrypted with a CMK.

When the module creates the password secret CMK, the key policy automatically grants kms:Decrypt and kms:DescribeKey to the Fleet ECS execution role. However, the cron-monitoring Lambda role is created by the monitoring addon, which is applied after the byo-vpc module. If you supply a custom kms_base_policy that does not grant kms:* to the account root (for example, a least-privilege policy that only allows specific principals), you must also add the Lambda role to rds_config.password_secret_kms.extra_kms_policies so the key policy permits the Lambda to decrypt. Because the Lambda role name is predictable, you can construct the ARN before the role exists.

Example:

locals {
  cron_monitoring_lambda_role_arn = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:role/${local.customer}-cron-monitoring-lambda"
}

module "fleet_byo_vpc" {
  source = "github.com/fleetdm/fleet-terraform//byo-vpc?depth=1&ref=tf-mod-byo-vpc-v1.31.0"

  kms_base_policy = local.kms_base_policy_statements # your restrictive policy

  rds_config = {
    # ...
    password_secret_kms = {
      cmk_enabled = true
      extra_kms_policies = [
        {
          sid    = "AllowCronMonitoringLambdaDecrypt"
          effect = "Allow"
          principals = {
            type        = "AWS"
            identifiers = [local.cron_monitoring_lambda_role_arn]
          }
          actions    = ["kms:Decrypt", "kms:DescribeKey"]
          resources  = ["*"]
          conditions = []
        }
      ]
    }
  }

  # ...
}

module "monitoring" {
  source = "github.com/fleetdm/fleet-terraform//addons/monitoring?ref=tf-mod-addon-monitoring-v1.14.0"

  # ...
  cron_monitoring = {
    # ...
    mysql_password_secret_name        = "${local.customer}-database-password"
    mysql_password_secret_kms_key_arn = module.fleet_byo_vpc.rds_password_secret_kms_key_arn
  }
}

If your kms_base_policy grants kms:* to the account root (the default), the Lambda's IAM policy alone is sufficient and extra_kms_policies is not needed.

Example

module "fleet_byo_vpc" {
  source = "github.com/fleetdm/fleet-terraform//byo-vpc?depth=1&ref=tf-mod-byo-vpc-v1.31.0"

  vpc_config = {
    vpc_id = "vpc-1234567890abcdef0"
    networking = {
      subnets = ["subnet-aaa", "subnet-bbb"]
    }
  }

  rds_config = {
    observability = {
      database_insights_mode = "standard"
      kms = {
        cmk_enabled = true
      }
    }
    storage_kms = {
      cmk_enabled = true
    }
    password_secret_kms = {
      cmk_enabled = true
    }
  }

  redis_config = {
    at_rest_kms = {
      cmk_enabled = true
    }
  }
}

Migration Notes

  • Existing deployments are unchanged until you enable new KMS settings.
  • Upgrading from tf-mod-byo-vpc-v1.27.0 to any newer version may plan an in-place Aurora cluster update setting cluster-level performance_insights_enabled = true. Older versions already enabled Performance Insights at the instance level; newer versions also manage it at the cluster level to align with Aurora Database Insights support.
  • Aurora storage and some observability changes may still be sensitive changes; review your maintenance and restore strategy before applying them in production.
  • If your goal is routine key rotation, prefer AWS KMS automatic rotation on the existing CMK when possible. Switching a resource to a different CMK is a separate migration with service-specific behavior.

KMS Migration Guidance

Aurora storage encryption (rds_config.storage_kms)

Changing the Aurora storage CMK is not an in-place re-key.

AWS documents that you can't change the KMS key of an existing encrypted Aurora DB cluster in place. To move to a different CMK, treat the change as a backup-and-restore migration:

  1. Confirm you have a recent automated backup or create a fresh manual DB cluster snapshot before making changes.
  2. Keep the current CMK enabled for the entire migration. Aurora and old snapshots still need it for decryption.
  3. If the source cluster is already encrypted, create a copy of the manual snapshot using the target CMK.
  4. Restore the copied snapshot as a new Aurora cluster. Aurora restores snapshots into a new cluster, not into the existing one.
  5. Recreate or verify the expected instances, parameter groups, subnet/security settings, and any cluster endpoints on the restored cluster.
  6. Validate Fleet connectivity and application behavior against the restored cluster before cutover.
  7. Cut traffic over during a maintenance window, then keep the old cluster and old CMK until you are satisfied with rollback and retention requirements.

Operationally, this means enabling a new storage CMK should be planned like a cluster replacement, not a normal in-place Terraform apply.

If you want to automate the snapshot/copy/restore cutover for a byo-vpc deployment that defines rds_config inline in its Terraform, use the byo-vpc helper:

./byo-vpc/scripts/rds_storage_kms_migration.sh \
  --terraform-dir . \
  --config-file main.tf \
  --storage-kms-alias fleet-rds-storage-2026

or:

./byo-vpc/scripts/rds_storage_kms_migration.sh \
  --terraform-dir . \
  --config-file main.tf \
  --storage-kms-key-arn arn:aws:kms:us-east-2:123456789012:key/00000000-0000-0000-0000-000000000000

The helper script:

  1. edits the caller's inline rds_config object in main.tf by default
  2. pre-creates the wrapper-managed storage CMK with a targeted Terraform apply when --storage-kms-alias is used
  3. creates a manual Aurora cluster snapshot and an encrypted copy under the target CMK
  4. removes the currently managed Aurora resources from Terraform state
  5. temporarily disables Performance Insights and Enhanced Monitoring in the config, then applies Terraform to restore a new Aurora cluster from the copied snapshot (AWS RestoreDBClusterFromSnapshot rejects these parameters for non-Limitless Aurora clusters)
  6. restores the original config from backup and re-applies restore-specific changes (plus any --include-performance-insights overrides), then runs a reconcile apply that re-enables PI and monitoring via ModifyDBCluster (in-place, no downtime)
  7. deletes the old Aurora cluster, secret, parameter groups, subnet group, and security group after the new cluster is managed

Important operational notes for the helper:

  • The restored cluster uses a new rds_config.name. The helper generates one automatically unless you pass --restored-name.
  • The helper leaves rds_config.snapshot_identifier pinned to the copied snapshot after the migration. Removing it later would force Terraform to replace the restored cluster.
  • If you also want the recreated cluster to adopt a Performance Insights / Database Insights CMK, add --include-performance-insights. This updates rds_config.observability in the post-restore config edit so the reconcile apply enables Performance Insights CMK configuration via ModifyDBCluster.
  • If you want the post-restore config edit to write a specific observability CMK alias, also pass --performance-insights-kms-alias <alias>.
  • Run the helper during a maintenance window. It automates the infrastructure steps, but you still need to plan for application cutover timing and validation.
  • Use --dry-run first to inspect the exact names, snapshots, and Terraform state addresses it will touch.
  • --dry-run also writes a manifest.json artifact with the exact state_remove_addresses and AWS-side identifiers that cleanup will use later.
  • If you do not want to delete the old Aurora resources immediately after cutover, use --keep-old-resources during the main migration run. You can perform cleanup later from the saved manifest.
  • If you want an interactive safety rail during AWS cleanup, add --confirm. The helper will print each AWS CLI command and prompt before it runs.

To defer old-resource cleanup until after you have validated the restored cluster, run the migration with --keep-old-resources, then later run:

./byo-vpc/scripts/rds_storage_kms_migration.sh \
  --cleanup-only \
  --manifest ./.rds-storage-kms-migration-<timestamp>/manifest.json \
  --region us-east-2 \
  --confirm

--cleanup-only requires --manifest and skips the snapshot, Terraform, and state-migration steps. It only deletes the old AWS resources recorded in the manifest, such as the retired cluster, instances, secret, enhanced monitoring IAM role, parameter groups, subnet group, and security group.

Aurora database password secret encryption (rds_config.password_secret_kms)

Changing the Secrets Manager CMK for the Fleet database password secret is an in-place metadata update. It does not require an Aurora backup/restore.

Before applying:

  1. Ensure the applying identity can decrypt with the old key and encrypt with the new key.
  2. Keep the old key enabled until you verify the secret can be read everywhere that uses it.

After the key change:

  1. Secrets Manager re-encrypts the AWSCURRENT, AWSPENDING, and AWSPREVIOUS versions if it can decrypt them with the previous key.
  2. Older versions without those staging labels can remain encrypted under the previous key.
  3. If you want the current secret value to depend only on the new CMK, create a fresh secret version or rotate the secret after the CMK change.

Aurora observability encryption (rds_config.observability.kms)

Changing the CMK for Performance Insights / Database Insights is an in-place observability change. AWS documents cluster and instance modifications for Performance Insights and Database Insights as no-downtime changes, but the modification can still take time to complete.

Before applying:

  1. Make sure the new CMK policy allows RDS to use the key and allows the principals that need to read observability data.
  2. Keep the old CMK enabled until you confirm observability data is readable after the update.
  3. If enabling Advanced Database Insights at the same time, also satisfy the module requirements for performance_insights_enabled, monitoring_interval, and retention.

This path does not require an Aurora snapshot/restore migration.

Aurora exported CloudWatch log groups (rds_config.cloudwatch_log_group.kms)

Associating a new CMK with an existing CloudWatch log group only affects newly ingested log events. Historical log events remain encrypted with the previous key, so the old key must remain available until that data ages out or is removed.

  • For CloudWatch log group re-keying, use the repository-root script:
DELETE_OLD_STREAMS=false ./scripts/cloudwatch_logs_kms_migration.sh <log-group-name> <region>

ElastiCache at-rest encryption (redis_config.at_rest_kms)

Changing the ElastiCache at-rest CMK is not an in-place re-key.

AWS documents that ElastiCache at-rest encryption can only be set when a replication group is created. Existing replication groups do not support enabling at-rest encryption later, and encrypted caches do not support manual key rotation to a different CMK. Treat a move to a new Redis/Valkey CMK as a backup-and-restore migration to a new replication group:

  1. Create a fresh manual backup of the existing replication group before making changes.
  2. Keep the current CMK enabled for the entire migration and retention window. Existing encrypted backups and the source replication group still depend on it.
  3. Restore the backup into a new replication group with at-rest encryption enabled and the target CMK selected.
  4. Recreate or verify parameter groups, subnet groups, security groups, maintenance settings, log delivery settings, and any auth/token settings on the restored replication group.
  5. Validate Fleet cache connectivity and application behavior against the restored replication group before cutover.
  6. Cut application traffic over to the new primary endpoint during a maintenance window.
  7. Keep the old replication group and old CMK until rollback is no longer needed and backup retention requirements are satisfied.

Operationally, this should be planned as a replication group replacement, not a normal in-place Terraform apply.

For the default Fleet usage in this module, Redis is used as a cache rather than a durable system of record. Replacing the replication group without backup/restore is therefore not expected to be data-loss breaking for Fleet, though you should expect cache cold-start behavior after cutover. Use backup/restore if you specifically want to preserve warm cache state during the migration.

If you do not need to preserve warm cache state, the simplest Terraform migration is usually:

  1. Enable the new Redis CMK settings.
  2. Set a temporary new redis_config.replication_group_id, for example by appending a suffix such as -1.
  3. Apply Terraform to create a new encrypted replication group alongside the old one.
  4. Validate Fleet against the new replication group and allow the cache to warm naturally.
  5. Terraform will then destroy the old replication group as part of the same replacement once the new one is ready.

This avoids the ReplicationGroupAlreadyExists conflict that happens when Terraform tries to replace an ElastiCache replication group in place while reusing the same replication group ID.

ElastiCache CloudWatch log groups (redis_config.cloudwatch_log_group.kms)

If Redis/Valkey log delivery targets a CloudWatch log group, changing that log group's CMK behaves the same way as any other CloudWatch Logs re-key:

  • only newly ingested log events use the new key
  • historical log events remain encrypted with the previous key
  • the previous key must remain available until old data ages out or is removed

Use the same repository-root helper for CloudWatch Logs re-keying:

DELETE_OLD_STREAMS=false ./scripts/cloudwatch_logs_kms_migration.sh <log-group-name> <region>

How to update this readme

Edit .header.md, run terraform init, then run terraform-docs markdown --header-from .header.md . > README.md.

Requirements

Name Version
terraform >= 1.12.0
aws >= 6.37.0

Providers

Name Version
aws 6.39.0
random 3.8.1

Modules

Name Source Version
byo-db ./byo-db n/a
rds terraform-aws-modules/rds-aurora/aws 9.16.1
redis cloudposse/elasticache-redis/aws >= 1.9.1
secrets-manager-1 lgallard/secrets-manager/aws 0.6.1

Resources

Name Type
aws_cloudwatch_log_group.redis resource
aws_db_parameter_group.main resource
aws_kms_alias.rds_cloudwatch_log_group resource
aws_kms_alias.rds_observability resource
aws_kms_alias.rds_password_secret resource
aws_kms_alias.rds_storage resource
aws_kms_alias.redis_at_rest resource
aws_kms_alias.redis_cloudwatch_log_group resource
aws_kms_key.rds_cloudwatch_log_group resource
aws_kms_key.rds_observability resource
aws_kms_key.rds_password_secret resource
aws_kms_key.rds_storage resource
aws_kms_key.redis_at_rest resource
aws_kms_key.redis_cloudwatch_log_group resource
aws_rds_cluster_parameter_group.main resource
aws_security_group_rule.rds_ecs_ingress resource
random_id.rds_final_snapshot_identifier resource
random_password.rds resource
aws_caller_identity.current data source
aws_iam_policy_document.rds_cloudwatch_log_group_kms data source
aws_iam_policy_document.rds_observability_kms data source
aws_iam_policy_document.rds_password_secret_kms data source
aws_iam_policy_document.rds_storage_kms data source
aws_iam_policy_document.redis_at_rest_kms data source
aws_iam_policy_document.redis_cloudwatch_log_group_kms data source
aws_partition.current data source
aws_region.current data source

Inputs

Name Description Type Default Required
active_rds_config_name Name of the rds_configs entry used by Fleet. Defaults to the synthetic current entry when using legacy rds_config. string "current" no
alb_config n/a
object({
name = optional(string, "fleet")
subnets = list(string)
security_groups = optional(list(string), [])
access_logs = optional(map(string), {})
certificate_arn = string
allowed_cidrs = optional(list(string), ["0.0.0.0/0"])
allowed_ipv6_cidrs = optional(list(string), ["::/0"])
egress_cidrs = optional(list(string), ["0.0.0.0/0"])
egress_ipv6_cidrs = optional(list(string), ["::/0"])
fleet_target_group = optional(object({
protocol = optional(string, "HTTP")
port = optional(number, 80)
target_type = optional(string, "ip")
create_attachment = optional(bool, false)
health_check = optional(object({
path = optional(string, "/healthz")
matcher = optional(string, "200")
port = optional(string)
timeout = optional(number, 10)
interval = optional(number, 15)
healthy_threshold = optional(number, 5)
unhealthy_threshold = optional(number, 5)
}), {})
}), {})
extra_target_groups = optional(any, [])
https_listener_rules = optional(any, [])
https_overrides = optional(any, {})
xff_header_processing_mode = optional(string, null)
tls_policy = optional(string, "ELBSecurityPolicy-TLS13-1-2-2021-06")
idle_timeout = optional(number, 905)
internal = optional(bool, false)
enable_deletion_protection = optional(bool, false)
})
n/a yes
ecs_cluster The config for the terraform-aws-modules/ecs/aws module. For published KMS blocks, legacy enabled is deprecated and still accepted; prefer cmk_enabled.
object({
autoscaling_capacity_providers = optional(any, {})
cluster_configuration = optional(any, {
execute_command_configuration = {
logging = "OVERRIDE"
log_configuration = {
cloud_watch_log_group_name = "/aws/ecs/aws-ec2"
}
}
})
cluster_name = optional(string, "fleet")
cloudwatch_log_group = optional(object({
create = optional(bool, true)
retention_in_days = optional(number, 90)
kms = optional(object({
cmk_enabled = optional(bool, null)
enabled = optional(bool, null)
kms_key_arn = optional(string, null)
kms_alias = optional(string, "fleet-ecs-cluster-logs")
extra_kms_policies = optional(list(any), [])
}), {
cmk_enabled = null
enabled = null
kms_key_arn = null
kms_alias = "fleet-ecs-cluster-logs"
extra_kms_policies = []
})
}), {
create = true
retention_in_days = 90
kms = {
cmk_enabled = null
enabled = null
kms_key_arn = null
kms_alias = "fleet-ecs-cluster-logs"
extra_kms_policies = []
}
})
cluster_settings = optional(any, {
"name" : "containerInsights",
"value" : "enabled",
})
create = optional(bool, true)
default_capacity_provider_use_fargate = optional(bool, true)
fargate_capacity_providers = optional(any, {
FARGATE = {
default_capacity_provider_strategy = {
weight = 100
}
}
FARGATE_SPOT = {
default_capacity_provider_strategy = {
weight = 0
}
}
})
tags = optional(map(string))
})
{
"autoscaling_capacity_providers": {},
"cloudwatch_log_group": {
"create": true,
"kms": {
"cmk_enabled": false,
"kms_alias": "fleet-ecs-cluster-logs",
"kms_key_arn": null
},
"retention_in_days": 90
},
"cluster_configuration": {
"execute_command_configuration": {
"log_configuration": {
"cloud_watch_log_group_name": "/aws/ecs/aws-ec2"
},
"logging": "OVERRIDE"
}
},
"cluster_name": "fleet",
"cluster_settings": {
"name": "containerInsights",
"value": "enabled"
},
"create": true,
"default_capacity_provider_use_fargate": true,
"fargate_capacity_providers": {
"FARGATE": {
"default_capacity_provider_strategy": {
"weight": 100
}
},
"FARGATE_SPOT": {
"default_capacity_provider_strategy": {
"weight": 0
}
}
},
"tags": {}
}
no
fleet_config The configuration object for Fleet itself. Fields that default to null will have their respective resources created if not specified. For published KMS blocks, legacy enabled is deprecated and still accepted; prefer cmk_enabled.
object({
task_mem = optional(number, null)
task_cpu = optional(number, null)
ephemeral_storage = optional(object({
size_in_gib = number
}), null)
mem = optional(number, 4096)
cpu = optional(number, 512)
pid_mode = optional(string, null)
command = optional(list(string), null)
private_key_delivery_method = optional(string, "ecs")
image = optional(string, "fleetdm/fleet:v4.90.0")
family = optional(string, "fleet")
sidecars = optional(list(any), [])
depends_on = optional(list(any), [])
mount_points = optional(list(any), [])
volumes = optional(list(any), [])
extra_environment_variables = optional(map(string), {})
extra_iam_policies = optional(list(string), [])
extra_execution_iam_policies = optional(list(string), [])
extra_secrets = optional(map(string), {})
security_group_name = optional(string, "fleet")
iam_role_arn = optional(string, null)
repository_credentials = optional(string, "")
private_key_secret_arn = optional(string, null)
private_key_secret_name = optional(string, "fleet-server-private-key")
private_key_secret_kms = optional(object({
cmk_enabled = optional(bool, null)
enabled = optional(bool, null)
kms_key_arn = optional(string, null)
kms_alias = optional(string, "fleet-server-private-key")
extra_kms_policies = optional(list(any), [])
}), {
cmk_enabled = null
enabled = null
kms_key_arn = null
kms_alias = "fleet-server-private-key"
extra_kms_policies = []
})
fargate_ephemeral_storage_kms = optional(object({
cmk_enabled = optional(bool, null)
enabled = optional(bool, null)
kms_key_arn = optional(string, null)
kms_alias = optional(string, "fleet-fargate-ephemeral-storage")
extra_kms_policies = optional(list(any), [])
}), {
cmk_enabled = null
enabled = null
kms_key_arn = null
kms_alias = "fleet-fargate-ephemeral-storage"
extra_kms_policies = []
})
server_tls_enabled = optional(bool, false)
service = optional(object({
name = optional(string, "fleet")
}), {
name = "fleet"
})
database = optional(object({
password_secret_arn = optional(string, null)
password_secret_kms_key_arn = optional(string, null)
user = optional(string, null)
database = optional(string, null)
address = optional(string, null)
rr_address = optional(string, null)
}), {
password_secret_arn = null
password_secret_kms_key_arn = null
user = null
database = null
address = null
rr_address = null
})
redis = optional(object({
address = string
use_tls = optional(bool, true)
}), {
address = null
use_tls = true
})
awslogs = optional(object({
name = optional(string, null)
region = optional(string, null)
create = optional(bool, true)
prefix = optional(string, "fleet")
retention = optional(number, 5)
kms = optional(object({
cmk_enabled = optional(bool, null)
enabled = optional(bool, null)
kms_key_arn = optional(string, null)
kms_alias = optional(string, "fleet-application-logs")
extra_kms_policies = optional(list(any), [])
}), {
cmk_enabled = null
enabled = null
kms_key_arn = null
kms_alias = "fleet-application-logs"
extra_kms_policies = []
})
}), {
name = null
region = null
create = true
prefix = "fleet"
retention = 5
kms = {
cmk_enabled = null
enabled = null
kms_key_arn = null
kms_alias = "fleet-application-logs"
extra_kms_policies = []
}
})
loadbalancer = optional(object({
arn = string
}), {
arn = null
})
extra_load_balancers = optional(list(any), [])
networking = optional(object({
subnets = optional(list(string), null)
security_groups = optional(list(string), null)
ingress_sources = optional(object({
cidr_blocks = optional(list(string), [])
ipv6_cidr_blocks = optional(list(string), [])
security_groups = optional(list(string), [])
prefix_list_ids = optional(list(string), [])
}), {
cidr_blocks = []
ipv6_cidr_blocks = []
security_groups = []
prefix_list_ids = []
})
assign_public_ip = optional(bool, false)
}), {
subnets = null
security_groups = null
ingress_sources = {
cidr_blocks = []
ipv6_cidr_blocks = []
security_groups = []
prefix_list_ids = []
}
assign_public_ip = false
})
autoscaling = optional(object({
max_capacity = optional(number, 5)
min_capacity = optional(number, 1)
memory_tracking_target_value = optional(number, 80)
cpu_tracking_target_value = optional(number, 80)
}), {
max_capacity = 5
min_capacity = 1
memory_tracking_target_value = 80
cpu_tracking_target_value = 80
})
iam = optional(object({
role = optional(object({
name = optional(string, "fleet-role")
policy_name = optional(string, "fleet-iam-policy")
}), {
name = "fleet-role"
policy_name = "fleet-iam-policy"
})
execution = optional(object({
name = optional(string, "fleet-execution-role")
policy_name = optional(string, "fleet-execution-role")
}), {
name = "fleet-execution-role"
policy_name = "fleet-iam-policy-execution"
})
}), {
name = "fleetdm-execution-role"
})
software_installers = optional(object({
create_bucket = optional(bool, true)
bucket_name = optional(string, null)
bucket_prefix = optional(string, "fleet-software-installers-")
s3_object_prefix = optional(string, "")
cloudfront_distribution_arn = optional(string, null)
enable_bucket_versioning = optional(bool, false)
expire_noncurrent_versions = optional(bool, true)
noncurrent_version_expiration_days = optional(number, 30)
create_kms_key = optional(bool, false)
kms_key_arn = optional(string, null)
kms_alias = optional(string, "fleet-software-installers")
extra_kms_policies = optional(list(any), [])
tags = optional(map(string), {})
}), {
create_bucket = true
bucket_name = null
bucket_prefix = "fleet-software-installers-"
s3_object_prefix = ""
cloudfront_distribution_arn = null
enable_bucket_versioning = false
expire_noncurrent_versions = true
noncurrent_version_expiration_days = 30
create_kms_key = false
kms_key_arn = null
kms_alias = "fleet-software-installers"
extra_kms_policies = []
tags = {}
})
})
{
"autoscaling": {
"cpu_tracking_target_value": 80,
"max_capacity": 5,
"memory_tracking_target_value": 80,
"min_capacity": 1
},
"awslogs": {
"create": true,
"kms": {
"cmk_enabled": null,
"enabled": null,
"extra_kms_policies": [],
"kms_alias": "fleet-application-logs",
"kms_key_arn": null
},
"name": null,
"prefix": "fleet",
"region": null,
"retention": 5
},
"command": null,
"cpu": 512,
"database": {
"address": null,
"database": null,
"password_secret_arn": null,
"rr_address": null,
"user": null
},
"depends_on": [],
"ephemeral_storage": null,
"extra_environment_variables": {},
"extra_execution_iam_policies": [],
"extra_iam_policies": [],
"extra_load_balancers": [],
"extra_secrets": {},
"family": "fleet",
"fargate_ephemeral_storage_kms": {
"cmk_enabled": null,
"enabled": null,
"extra_kms_policies": [],
"kms_alias": "fleet-fargate-ephemeral-storage",
"kms_key_arn": null
},
"iam": {
"execution": {
"name": "fleet-execution-role",
"policy_name": "fleet-iam-policy-execution"
},
"role": {
"name": "fleet-role",
"policy_name": "fleet-iam-policy"
}
},
"iam_role_arn": null,
"image": "fleetdm/fleet:v4.90.0",
"loadbalancer": {
"arn": null
},
"mem": 4096,
"mount_points": [],
"networking": {
"assign_public_ip": false,
"ingress_sources": {
"cidr_blocks": [],
"ipv6_cidr_blocks": [],
"prefix_list_ids": [],
"security_groups": []
},
"security_groups": null,
"subnets": null
},
"pid_mode": null,
"private_key_delivery_method": "ecs",
"private_key_secret_arn": null,
"private_key_secret_kms": {
"cmk_enabled": null,
"enabled": null,
"extra_kms_policies": [],
"kms_alias": "fleet-server-private-key",
"kms_key_arn": null
},
"private_key_secret_name": "fleet-server-private-key",
"redis": {
"address": null,
"use_tls": true
},
"repository_credentials": "",
"security_group_name": "fleet",
"security_groups": null,
"server_tls_enabled": false,
"service": {
"name": "fleet"
},
"sidecars": [],
"software_installers": {
"bucket_name": null,
"bucket_prefix": "fleet-software-installers-",
"cloudfront_distribution_arn": null,
"create_bucket": true,
"create_kms_key": false,
"enable_bucket_versioning": false,
"expire_noncurrent_versions": true,
"extra_kms_policies": [],
"kms_alias": "fleet-software-installers",
"kms_key_arn": null,
"noncurrent_version_expiration_days": 30,
"s3_object_prefix": "",
"tags": {}
},
"task_cpu": null,
"task_mem": null,
"volumes": []
}
no
kms_base_policy Optional base KMS key-policy statements to apply to module-created CMKs before module-required service access statements are merged in. If null, the module defaults to the historical root kms:* statement.
list(object({
sid = string
effect = string
principals = object({
type = string
identifiers = list(string)
})
actions = list(string)
resources = list(string)
conditions = optional(list(object({
test = string
variable = string
values = list(string)
})), [])
}))
null no
migration_config The configuration object for Fleet's migration task.
object({
mem = number
cpu = number
})
{
"cpu": 1024,
"mem": 2048
}
no
rds_config The config for the terraform-aws-modules/rds-aurora/aws module. Deprecated: use rds_configs instead.
object({
name = optional(string, "fleet")
engine_version = optional(string, "8.0.mysql_aurora.3.07.1")
instance_class = optional(string, "db.t4g.large")
subnets = optional(list(string), [])
allowed_security_groups = optional(list(string), [])
allowed_cidr_blocks = optional(list(string), [])
apply_immediately = optional(bool, true)
monitoring_interval = optional(number, 10)
backtrack_window = optional(number, null)
db_parameter_group_name = optional(string)
db_parameters = optional(map(string), {})
db_cluster_parameter_group_name = optional(string)
db_cluster_parameters = optional(map(string), {})
enabled_cloudwatch_logs_exports = optional(list(string), [])
final_snapshot_identifier = optional(string, null)
password_secret_kms = optional(object({
cmk_enabled = optional(bool, false)
kms_key_arn = optional(string, null)
kms_alias = optional(string, "fleet-rds-password-secret")
extra_kms_policies = optional(list(any), [])
}), {
cmk_enabled = false
kms_key_arn = null
kms_alias = "fleet-rds-password-secret"
extra_kms_policies = []
})
storage_kms = optional(object({
cmk_enabled = optional(bool, false)
kms_key_arn = optional(string, null)
kms_alias = optional(string, "fleet-rds-storage")
extra_kms_policies = optional(list(any), [])
}), {
cmk_enabled = false
kms_key_arn = null
kms_alias = "fleet-rds-storage"
extra_kms_policies = []
})
observability = optional(object({
performance_insights_enabled = optional(bool, true)
retention_period = optional(number, null)
database_insights_mode = optional(string, null)
kms = optional(object({
cmk_enabled = optional(bool, false)
kms_key_arn = optional(string, null)
kms_alias = optional(string, "fleet-rds-performance-insights")
extra_kms_policies = optional(list(any), [])
}), {
cmk_enabled = false
kms_key_arn = null
kms_alias = "fleet-rds-performance-insights"
extra_kms_policies = []
})
}), {
performance_insights_enabled = true
retention_period = null
database_insights_mode = null
kms = {
cmk_enabled = false
kms_key_arn = null
kms_alias = "fleet-rds-performance-insights"
extra_kms_policies = []
}
})
cloudwatch_log_group = optional(object({
retention_in_days = optional(number, null)
skip_destroy = optional(bool, false)
kms = optional(object({
cmk_enabled = optional(bool, false)
kms_key_arn = optional(string, null)
kms_alias = optional(string, "fleet-rds-logs")
extra_kms_policies = optional(list(any), [])
}), {
cmk_enabled = false
kms_key_arn = null
kms_alias = "fleet-rds-logs"
extra_kms_policies = []
})
}), {
retention_in_days = null
skip_destroy = false
kms = {
cmk_enabled = false
kms_key_arn = null
kms_alias = "fleet-rds-logs"
extra_kms_policies = []
}
})
master_username = optional(string, "fleet")
database_name = optional(string, "fleet")
snapshot_identifier = optional(string)
cluster_tags = optional(map(string), {})
preferred_maintenance_window = optional(string, "thu:23:00-fri:00:00")
skip_final_snapshot = optional(bool, true)
backup_retention_period = optional(number, 7)
replicas = optional(number, 2)
serverless = optional(bool, false)
serverless_min_capacity = optional(number, 2)
serverless_max_capacity = optional(number, 10)
restore_to_point_in_time = optional(map(string), {})
})
{
"allowed_cidr_blocks": [],
"allowed_security_groups": [],
"apply_immediately": true,
"backtrack_window": null,
"backup_retention_period": 7,
"cloudwatch_log_group": {
"kms": {
"cmk_enabled": false,
"extra_kms_policies": [],
"kms_alias": "fleet-rds-logs",
"kms_key_arn": null
},
"retention_in_days": null,
"skip_destroy": false
},
"cluster_tags": {},
"database_name": "fleet",
"db_cluster_parameter_group_name": null,
"db_cluster_parameters": {},
"db_parameter_group_name": null,
"db_parameters": {},
"enabled_cloudwatch_logs_exports": [],
"engine_version": "8.0.mysql_aurora.3.07.1",
"final_snapshot_identifier": null,
"instance_class": "db.t4g.large",
"master_username": "fleet",
"monitoring_interval": 10,
"name": "fleet",
"observability": {
"database_insights_mode": null,
"kms": {
"cmk_enabled": false,
"extra_kms_policies": [],
"kms_alias": "fleet-rds-performance-insights",
"kms_key_arn": null
},
"performance_insights_enabled": true,
"retention_period": null
},
"password_secret_kms": {
"cmk_enabled": false,
"extra_kms_policies": [],
"kms_alias": "fleet-rds-password-secret",
"kms_key_arn": null
},
"preferred_maintenance_window": "thu:23:00-fri:00:00",
"replicas": 2,
"restore_to_point_in_time": {},
"serverless": false,
"serverless_max_capacity": 10,
"serverless_min_capacity": 2,
"skip_final_snapshot": true,
"snapshot_identifier": null,
"storage_kms": {
"cmk_enabled": false,
"extra_kms_policies": [],
"kms_alias": "fleet-rds-storage",
"kms_key_arn": null
},
"subnets": []
}
no
rds_configs Map of named Aurora cluster configurations for blue-green cutovers. When set, rds_config is ignored.
map(object({
name = optional(string, "fleet")
engine_version = optional(string, "8.0.mysql_aurora.3.07.1")
instance_class = optional(string, "db.t4g.large")
subnets = optional(list(string), [])
allowed_security_groups = optional(list(string), [])
allowed_cidr_blocks = optional(list(string), [])
apply_immediately = optional(bool, true)
monitoring_interval = optional(number, 10)
backtrack_window = optional(number, null)
db_parameter_group_name = optional(string)
db_parameters = optional(map(string), {})
db_cluster_parameter_group_name = optional(string)
db_cluster_parameters = optional(map(string), {})
enabled_cloudwatch_logs_exports = optional(list(string), [])
final_snapshot_identifier = optional(string, null)
password_secret_kms = optional(object({
cmk_enabled = optional(bool, false)
kms_key_arn = optional(string, null)
kms_alias = optional(string, "fleet-rds-password-secret")
extra_kms_policies = optional(list(any), [])
}), {
cmk_enabled = false
kms_key_arn = null
kms_alias = "fleet-rds-password-secret"
extra_kms_policies = []
})
storage_kms = optional(object({
cmk_enabled = optional(bool, false)
kms_key_arn = optional(string, null)
kms_alias = optional(string, "fleet-rds-storage")
extra_kms_policies = optional(list(any), [])
}), {
cmk_enabled = false
kms_key_arn = null
kms_alias = "fleet-rds-storage"
extra_kms_policies = []
})
observability = optional(object({
performance_insights_enabled = optional(bool, true)
retention_period = optional(number, null)
database_insights_mode = optional(string, null)
kms = optional(object({
cmk_enabled = optional(bool, false)
kms_key_arn = optional(string, null)
kms_alias = optional(string, "fleet-rds-performance-insights")
extra_kms_policies = optional(list(any), [])
}), {
cmk_enabled = false
kms_key_arn = null
kms_alias = "fleet-rds-performance-insights"
extra_kms_policies = []
})
}), {
performance_insights_enabled = true
retention_period = null
database_insights_mode = null
kms = {
cmk_enabled = false
kms_key_arn = null
kms_alias = "fleet-rds-performance-insights"
extra_kms_policies = []
}
})
cloudwatch_log_group = optional(object({
retention_in_days = optional(number, null)
skip_destroy = optional(bool, false)
kms = optional(object({
cmk_enabled = optional(bool, false)
kms_key_arn = optional(string, null)
kms_alias = optional(string, "fleet-rds-logs")
extra_kms_policies = optional(list(any), [])
}), {
cmk_enabled = false
kms_key_arn = null
kms_alias = "fleet-rds-logs"
extra_kms_policies = []
})
}), {
retention_in_days = null
skip_destroy = false
kms = {
cmk_enabled = false
kms_key_arn = null
kms_alias = "fleet-rds-logs"
extra_kms_policies = []
}
})
master_username = optional(string, "fleet")
database_name = optional(string, "fleet")
snapshot_identifier = optional(string)
cluster_tags = optional(map(string), {})
preferred_maintenance_window = optional(string, "thu:23:00-fri:00:00")
skip_final_snapshot = optional(bool, true)
backup_retention_period = optional(number, 7)
replicas = optional(number, 2)
serverless = optional(bool, false)
serverless_min_capacity = optional(number, 2)
serverless_max_capacity = optional(number, 10)
restore_to_point_in_time = optional(map(string), {})
}))
null no
redis_config n/a
object({
name = optional(string, "fleet")
replication_group_id = optional(string)
elasticache_subnet_group_name = optional(string, "")
allowed_security_group_ids = optional(list(string), [])
subnets = list(string)
allowed_cidrs = list(string)
availability_zones = optional(list(string), [])
cluster_size = optional(number, 3)
instance_type = optional(string, "cache.m5.large")
apply_immediately = optional(bool, true)
automatic_failover_enabled = optional(bool, false)
engine = optional(string, "redis")
engine_version = optional(string, "7.1")
family = optional(string, "redis7")
at_rest_encryption_enabled = optional(bool, true)
at_rest_kms = optional(object({
cmk_enabled = optional(bool, false)
kms_key_arn = optional(string, null)
kms_alias = optional(string, "fleet-redis-at-rest")
extra_kms_policies = optional(list(any), [])
}), {
cmk_enabled = false
kms_key_arn = null
kms_alias = "fleet-redis-at-rest"
extra_kms_policies = []
})
transit_encryption_enabled = optional(bool, true)
parameter = optional(list(object({
name = string
value = string
})), [])
cloudwatch_log_group = optional(object({
retention_in_days = optional(number, null)
skip_destroy = optional(bool, false)
kms = optional(object({
cmk_enabled = optional(bool, false)
kms_key_arn = optional(string, null)
kms_alias = optional(string, "fleet-redis-logs")
extra_kms_policies = optional(list(any), [])
}), {
cmk_enabled = false
kms_key_arn = null
kms_alias = "fleet-redis-logs"
extra_kms_policies = []
})
}), {
retention_in_days = null
skip_destroy = false
kms = {
cmk_enabled = false
kms_key_arn = null
kms_alias = "fleet-redis-logs"
extra_kms_policies = []
}
})
log_delivery_configuration = optional(list(map(any)), [])
tags = optional(map(string), {})
})
{
"allowed_cidrs": null,
"allowed_security_group_ids": [],
"apply_immediately": true,
"at_rest_encryption_enabled": true,
"at_rest_kms": {
"cmk_enabled": false,
"extra_kms_policies": [],
"kms_alias": "fleet-redis-at-rest",
"kms_key_arn": null
},
"automatic_failover_enabled": false,
"availability_zones": [],
"cloudwatch_log_group": {
"kms": {
"cmk_enabled": false,
"extra_kms_policies": [],
"kms_alias": "fleet-redis-logs",
"kms_key_arn": null
},
"retention_in_days": null,
"skip_destroy": false
},
"cluster_size": 3,
"elasticache_subnet_group_name": "",
"engine": "redis",
"engine_version": "7.1",
"family": "redis7",
"instance_type": "cache.m5.large",
"log_delivery_configuration": [],
"name": "fleet",
"parameter": [],
"replication_group_id": null,
"subnets": null,
"tags": {},
"transit_encryption_enabled": true
}
no
vpc_config n/a
object({
vpc_id = string
networking = object({
subnets = list(string)
})
})
n/a yes

Outputs

Name Description
byo-db n/a
rds n/a
rds_clusters All named Aurora cluster module outputs.
rds_password_secret_kms_key_arn n/a
rds_password_secret_kms_key_arns Aurora database password secret KMS key ARNs by cluster configuration name.
redis n/a
secrets n/a