Skip to main content

Backend Provisioning

provision.backend automatically creates the Terraform state backend (S3 bucket, lockfile resource) before the first run of a component. The backend: block describes where state lives; provision.backend.enabled tells Atmos to create that location if it doesn't exist. Use this to eliminate the chicken-and-egg bootstrap problem of needing a state backend before you can deploy the component that creates it.

Experimental

Schema

provision.backend.enabled

Automatically provision the Terraform state backend before the first run. Currently supports S3 backends with optional native S3 locking (Terraform 1.10+).

  • Type: boolean
  • Default: false
  • Applies to: Terraform components only

Configuration

Enable automatic backend creation alongside the existing backend: configuration.

stacks/catalog/vpc.yaml

components:
terraform:
vpc:
backend_type: s3
backend:
bucket: acme-ue1-dev-tfstate
key: vpc/terraform.tfstate
region: us-east-1
use_lockfile: true # Native S3 locking (Terraform 1.10+)

provision:
backend:
enabled: true # Auto-create the bucket if missing

When enabled, before running any Terraform command Atmos will:

  1. Check whether the configured backend already exists.
  2. If it doesn't, provision it using secure defaults (versioning, encryption, access blocking).
  3. Continue with terraform init and execution.

Configuration Hierarchy

provision.backend participates in Atmos's deep-merge system, so you can set defaults at high levels and override per component.

Toolchain-Level Defaults

Apply backend provisioning to every Terraform component in a stack by setting it under the toolchain key:

stacks/orgs/acme/plat/dev/_defaults.yaml

terraform:
provision:
backend:
enabled: true # Every Terraform component in this stack gets backend provisioning

Environment-Specific Overrides

Configure different provisioning policies per environment:

stacks/orgs/acme/plat/staging/_defaults.yaml

terraform:
provision:
backend:
enabled: false # Override for specific environment

Catalog Inheritance

Share provision configuration through reusable catalog components:

stacks/catalog/networking/vpc.yaml

components:
terraform:
vpc/defaults:
provision:
backend:
enabled: true # Catalog default

# stacks/dev.yaml
components:
terraform:
vpc:
metadata:
inherits: [vpc/defaults]
# Inherits provision.backend.enabled: true

Component-Level Overrides

Opt a single component out of a toolchain or catalog default by setting enabled: false:

stacks/orgs/acme/plat/dev/us-east-1.yaml

components:
terraform:
legacy-vpc:
provision:
backend:
enabled: false # Use a manually-bootstrapped backend

Atmos combines configurations from all levels, with component-level configuration having the highest precedence. Use catalog inheritance for reusable patterns and override per component when needed.

Supported Backend Types

S3 (AWS)

The S3 backend provisioner creates buckets with hardcoded security best practices:

  • Versioning: Enabled (protects against accidental deletions)
  • Encryption: AES-256 with AWS-managed keys (always enabled)
  • Public Access: Blocked (all 4 block settings enabled)
  • Locking: Native S3 locking (Terraform 1.10+, no DynamoDB required)
  • Tags: Automatic resource tags (Name, ManagedBy=Atmos)

Required Configuration:

stacks/catalog/vpc.yaml

backend_type: s3
backend:
bucket: my-terraform-state # Required
key: vpc/terraform.tfstate
region: us-east-1 # Required
use_lockfile: true # Enable native S3 locking (Terraform 1.10+)

provision:
backend:
enabled: true

Cross-Account Provisioning

stacks/catalog/vpc.yaml

backend:
bucket: my-terraform-state
region: us-east-1
use_lockfile: true # Enable native S3 locking (Terraform 1.10+)
assume_role:
role_arn: arn:aws:iam::999999999999:role/TerraformStateAdmin

provision:
backend:
enabled: true

The provisioner will assume the specified role to create the bucket in the target account.

Manual Provisioning

You can also provision backends explicitly using the CLI:

# Provision backend before Terraform execution
atmos terraform backend create vpc --stack dev

# Then run Terraform
atmos terraform apply vpc --stack dev

This is useful for:

  • CI/CD pipelines with separate provisioning stages
  • Troubleshooting provisioning issues
  • Batch provisioning for multiple components
  • Pre-provisioning before large-scale deployments

See atmos terraform backend for complete CLI documentation.

Required IAM Permissions

For S3 backend provisioning, the identity needs these permissions:

IAM Policy

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:CreateBucket",
"s3:HeadBucket",
"s3:PutBucketVersioning",
"s3:PutBucketEncryption",
"s3:PutBucketPublicAccessBlock",
"s3:PutBucketTagging"
],
"Resource": "arn:aws:s3:::my-terraform-state*"
}
]
}

For cross-account provisioning, also add:

IAM Policy

{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::999999999999:role/TerraformStateAdmin"
}

Solving the Terraform Bootstrap Problem

Automatic provisioning is fully compatible with Terraform-managed backends. It solves a classic chicken-and-egg problem: "How do I manage my state backend with Terraform when I need that backend to exist before Terraform can run?"

Traditional Workaround:

  1. Use local state temporarily.
  2. Create the S3 bucket with Terraform using local state.
  3. Switch backend configuration to S3.
  4. Import the bucket into the S3-backed state.
  5. Delete local state files.

With Atmos Automatic Provisioning:

  1. Enable provision.backend.enabled: true.
  2. Run atmos terraform plan — backend auto-created with secure defaults.
  3. Import the bucket into Terraform (no local state dance needed).
  4. Done — everything managed by Terraform.

Migrating to Terraform-Managed Backends

Once your backend is provisioned, you can import it into Terraform for advanced management.

Step 1: Provision the Backend

Use Atmos to create the backend with secure defaults:

atmos terraform backend create vpc --stack prod

Step 2: Import into Terraform

Add the backend to your Terraform configuration and import it:

components/terraform/backend-state/main.tf

# Import the provisioned backend
import {
to = aws_s3_bucket.terraform_state
id = "acme-ue1-prod-tfstate"
}

resource "aws_s3_bucket" "terraform_state" {
bucket = "acme-ue1-prod-tfstate"
}

# Add lifecycle rules
resource "aws_s3_bucket_lifecycle_configuration" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id

rule {
id = "delete-old-versions"
status = "Enabled"

noncurrent_version_expiration {
noncurrent_days = 90
}
}
}

# Add replication for disaster recovery
resource "aws_s3_bucket_replication_configuration" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
role = aws_iam_role.replication.arn

rule {
id = "replicate-state"
status = "Enabled"

destination {
bucket = aws_s3_bucket.terraform_state_replica.arn
storage_class = "STANDARD_IA"
}
}
}

Step 3: Optionally Disable Automatic Provisioning

Once Terraform manages the backend, you can optionally disable automatic provisioning:

stacks/prod.yaml

provision:
backend:
enabled: false # Backend now managed by Terraform
NOTE:

You can leave provision.backend.enabled: true even after importing to Terraform. The provisioner is idempotent — it will detect the bucket exists and skip creation, causing no conflicts with Terraform management.

Alternatively, use the terraform-aws-tfstate-backend module for backends with advanced features like cross-region replication, lifecycle policies, and custom KMS keys.

Idempotent Operations

Backend provisioning is idempotent — running it multiple times is safe:

$ atmos terraform backend create vpc --stack dev
✓ Created S3 bucket 'acme-ue1-dev-tfstate'

$ atmos terraform backend create vpc --stack dev
S3 bucket 'acme-ue1-dev-tfstate' already exists (idempotent)
✓ Backend provisioning completed

Global Defaults

There is no settings.provision.backend in atmos.yaml today. Backend provisioning is opted in per component or per toolchain because it has stronger side effects (creating cloud resources). For workdir defaults, see Settings: Provision Defaults.