Bootstrapping Your Account

Real AWS accounts come pre-provisioned with default VPCs, KMS keys, and service-linked roles. Terraform modules often assume these resources exist. Simfra provides several ways to replicate this starting state.

Prerequisites

  • Simfra running on localhost:4599 (see Installation)
  • For custom Terraform bootstrap: Terraform 1.6+ installed

The Problem

Your Terraform code might reference:

  • A default VPC and its subnets (data sources like data "aws_vpc" "default")
  • AWS-managed KMS keys (alias/aws/s3, alias/aws/rds)
  • IAM service-linked roles
  • Specific resource IDs that are hardcoded in variables or remote state

Without these resources, terraform plan fails with "not found" errors.

Solution 1: Standard Bootstrap

Set SIMFRA_BOOTSTRAP=standard to create the same default resources that a real AWS account has:

export SIMFRA_BOOTSTRAP=standard

This creates in 16 AWS regions (us-east-1, us-east-2, us-west-1, us-west-2, eu-west-1, eu-west-2, eu-west-3, eu-central-1, eu-north-1, ap-southeast-1, ap-southeast-2, ap-northeast-1, ap-northeast-2, ap-south-1, sa-east-1, ca-central-1):

Per region:

  • Default VPC (172.31.0.0/16) with 6 subnets, internet gateway, main route table, default security group, default network ACL, and DHCP options set
  • AWS-managed KMS keys with aliases: alias/aws/dynamodb, alias/aws/ebs, alias/aws/s3, alias/aws/sns, alias/aws/sqs, alias/aws/lambda, alias/aws/rds, alias/aws/logs, alias/aws/ssm, alias/aws/cloudwatch

Global (once):

  • IAM service-linked roles: AWSServiceRoleForSupport, AWSServiceRoleForTrustedAdvisor

Standard bootstrap is idempotent. When persistence is enabled (SIMFRA_DATA_DIR), it is skipped on restart if persisted state already exists.

Solution 2: Custom Terraform Bootstrap

Point SIMFRA_BOOTSTRAP at a directory containing .tf files that mirror your account's starting state:

export SIMFRA_BOOTSTRAP=/path/to/my/bootstrap

Simfra runs terraform init and terraform apply -auto-approve against itself at startup.

Example: Bootstrap Specific Resources

# /path/to/my/bootstrap/main.tf

terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
    }
  }
}

provider "aws" {
  region = "us-east-1"
}

# Create a VPC with a specific ID that your code references
resource "aws_vpc" "shared" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name           = "shared-services"
    "simfra:VpcId" = "vpc-0abc123def456789a"
  }
}

# Subnets your modules expect
resource "aws_subnet" "private_a" {
  vpc_id            = aws_vpc.shared.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "us-east-1a"

  tags = {
    Name              = "private-a"
    "simfra:SubnetId" = "subnet-0aaaa00000000000a"
  }
}

resource "aws_subnet" "private_b" {
  vpc_id            = aws_vpc.shared.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = "us-east-1b"

  tags = {
    Name              = "private-b"
    "simfra:SubnetId" = "subnet-0bbbb00000000000b"
  }
}

# KMS key your encryption config references
resource "aws_kms_key" "app" {
  description = "Application encryption key"

  tags = {
    "simfra:KeyId" = "12345678-1234-1234-1234-123456789012"
  }
}

resource "aws_kms_alias" "app" {
  name          = "alias/app-key"
  target_key_id = aws_kms_key.app.id
}

# IAM role your Lambda functions assume
resource "aws_iam_role" "lambda_exec" {
  name = "lambda-execution-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { Service = "lambda.amazonaws.com" }
      Action    = "sts:AssumeRole"
    }]
  })
}

resource "aws_iam_role_policy_attachment" "lambda_basic" {
  role       = aws_iam_role.lambda_exec.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

Terraform State Persistence

When SIMFRA_DATA_DIR is set, the bootstrap working directory is $SIMFRA_DATA_DIR/bootstrap/. The Terraform state file survives restarts, so terraform apply on subsequent starts only creates or updates resources that changed.

When SIMFRA_DATA_DIR is not set, a temporary directory is used and state is discarded on exit.

Timeout

Terraform bootstrap has a 5-minute timeout. If terraform apply does not complete within this window, Simfra exits with an error.

Solution 3: Replay Existing State

If you already manage your account's baseline resources with Terraform, you can replay the same configuration against Simfra:

  1. Copy your baseline .tf files to a bootstrap directory
  2. Remove any remote backend configuration (Simfra uses local state)
  3. Add simfra: override tags where you need specific resource IDs
  4. Point SIMFRA_BOOTSTRAP at the directory
cp -r infra/baseline/ simfra-bootstrap/

# Remove backend config - Simfra uses local state
rm simfra-bootstrap/backend.tf

export SIMFRA_BOOTSTRAP=./simfra-bootstrap

Pinning Resource IDs

Your code may reference specific resource IDs - a VPC ID in a variables file, a KMS key ARN in a config map. Use simfra: override tags to create resources with exact IDs.

See Resource ID Overrides for the complete tag reference and examples.

Example: Match a Specific VPC and All Associated Resources

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"

  tags = {
    "simfra:VpcId"                  = "vpc-0abc123def456789a"
    "simfra:DefaultSecurityGroupId" = "sg-0abc123def456789a"
    "simfra:MainRouteTableId"       = "rtb-0abc123def456789a"
    "simfra:DefaultNetworkAclId"    = "acl-0abc123def456789a"
  }
}

Combining Bootstrap Modes

You can use SIMFRA_BOOTSTRAP=standard for the default VPC and KMS keys, then apply additional Terraform after Simfra starts to add project-specific resources. The admin API also supports per-account bootstrap:

# Start with standard defaults
SIMFRA_BOOTSTRAP=standard ./bin/simfra &

# Wait for healthy
curl --retry 10 --retry-connrefused http://localhost:4599/_simfra/health

# Apply project-specific resources
cd my-bootstrap && terraform apply -auto-approve

Next Steps