Skip to content

variable system

Aleksej Komnenovic edited this page Jun 30, 2026 · 3 revisions

Variable System

How config flows from Root Module to child modules.

Design Principles

  1. Structured objects: Top-level variables are typed object({}) with optional() attributes and defaults
  2. Null-disabling: Setting a component to null disables it entirely
  3. Extensive validation: Regex patterns, numeric ranges, cross-field checks, Fargate CPU/memory matrix
  4. Sensible defaults: Most attributes have defaults; only a few are truly required

Variable Hierarchy

Required (no defaults)

Variable Type Validation
project_name string 2-32 chars, lowercase alphanumeric + hyphens
environment string 2-16 chars, same pattern
region string AWS region format (e.g. us-east-1)

Component Variables (nullable objects)

Variable Default Controls
vpc { create = true } VPC Module
storage null (disabled; supply object to enable) Storage Module
database Must provide min/max capacity Database Module
brms Must provide cpu, memory, domain, etc. BRMS in ECS Module
agent Must provide cpu, memory, etc. Agent in ECS Module

Leaving storage unset (its null default) disables storage creation, matching database, brms, and agent. When a non-null storage object is supplied, its inner attributes default to create_bucket = true and auth = "iam".

Data Flow: Root → Child Modules

flowchart TD
    subgraph VPC Flow
        varVPC[var.vpc] --> modVPC["module.vpc[0]"]
        modVPC -->|"outputs: vpc_id, subnet_ids"| localsVPC["locals.tf\nvpc_id, private_subnet_ids,\npublic_subnet_ids"]
        localsVPC --> modDB["module.database[0]\nvpc_id, private_subnet_ids"]
        localsVPC --> modECS1["module.ecs[0]\nvpc_id, all subnet_ids"]
    end

    subgraph Storage Flow
        varStorage[var.storage] --> modStorage["module.storage[0]"]
        modStorage -->|"outputs: bucket_name,\niam_policy_arns"| localsStorage["locals.tf\nbucket_name, bucket_arn"]
        localsStorage --> modECS2["module.ecs[0]\nstorage config + IAM policies"]
    end

    subgraph Database Flow
        varDB[var.database] --> modDB2["module.database[0]"]
        modDB2 -->|"outputs: endpoint,\ncredentials_secret_arn"| rootMain["root main.tf"]
        rootMain --> modECS3["module.ecs[0]\ndatabase config, BRMS only"]
    end

    subgraph Services
        varBRMS[var.brms / var.agent] --> modECS4["module.ecs[0]\nfull config objects"]
    end
Loading

Locals as Routing Layer (locals.tf)

The locals.tf file acts as a routing layer, resolving whether to use created or existing resources:

# VPC routing
local.vpc_id = local.create_vpc ? module.vpc[0].vpc_id : var.vpc.id
local.private_subnet_ids = local.create_vpc ? module.vpc[0].private_subnet_ids : var.vpc.private_subnet_ids

# Storage routing
local.bucket_name = local.create_bucket ? module.storage[0].bucket_name : var.storage.existing_bucket_name

# AZ selection
local.availability_zones = length(var.vpc.availability_zones) > 0 ? var.vpc.availability_zones : slice(data.aws_availability_zones.available.names, 0, 2)

Validation Patterns

Regex Validation

validation {
  condition     = can(regex("^[a-z][a-z0-9-]*[a-z0-9]$", var.project_name))
  error_message = "Must be lowercase alphanumeric with hyphens."
}

Fargate CPU/Memory Matrix

Complex cross-field validation ensuring valid Fargate combinations. Memory must be one of the discrete values below (1024 MiB increments for the lower tiers, larger increments at the top), not any value in the range:

CPU (units) Valid Memory (MiB) Increment
256 512, 1024, 2048 discrete
512 1024, 2048, 3072, 4096 1024
1024 2048, 3072, 4096, 5120, 6144, 7168, 8192 1024
2048 4096 - 16384 1024
4096 8192 - 30720 1024
8192 16384 - 61440 4096
16384 32768 - 122880 8192

Cross-Field Validation

  • min_count <= max_count
  • Auto-pause requires min_capacity = 0
  • HTTPS: must have route53_zone_id OR certificate_arn
  • Azure OpenAI requires azure_resource_name
  • AI API key required unless provider is amazon-bedrock

Naming Convention

name_prefix = "{project_name}-{environment}"

All resources follow: {project_name}-{environment}-{component} Examples: gorules-prod-brms-alb, gorules-staging-aurora-sg

Tagging Strategy

All resources get merged tags:

default_tags = {
  Project     = var.project_name
  Environment = var.environment
  ManagedBy   = "terraform"
}
# The vpc, storage, and ecs modules add: Module = "<module_name>"
# (the database module does not add a Module tag)
# All modules merge with user-provided var.tags

Clone this wiki locally