# 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.

**File:** `stacks/catalog/vpc.yaml`

```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:

**File:** `stacks/orgs/acme/plat/dev/_defaults.yaml`

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

### Environment-Specific Overrides

Configure different provisioning policies per environment:

**File:** `stacks/orgs/acme/plat/staging/_defaults.yaml`

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

### Catalog Inheritance

Share provision configuration through reusable catalog components:

**File:** `stacks/catalog/networking/vpc.yaml`

```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`:

**File:** `stacks/orgs/acme/plat/dev/us-east-1.yaml`

```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:**

**File:** `stacks/catalog/vpc.yaml`

```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

**File:** `stacks/catalog/vpc.yaml`

```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:

```shell
# 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`](/cli/commands/terraform/terraform-backend) for complete CLI documentation.

## Required IAM Permissions

For S3 backend provisioning, the identity needs these permissions:

```shell
{
  "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:

```shell
{
  "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:

```shell
atmos terraform backend create vpc --stack prod
```

**Step 2: Import into Terraform**

Add the backend to your Terraform configuration and import it:

```shell
# 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:

**File:** `stacks/prod.yaml`

```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`](https://github.com/cloudposse/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:

```shell
$ 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](/cli/configuration/settings/provision).

## Related

- [Terraform Backend Configuration](/stacks/components/terraform/backend) — The separate `backend:` block describing where state lives
- [Terraform Backends](/components/terraform/backends) — Conceptual overview of supported backend types
- [Remote State](/components/terraform/remote-state) — Reading other components' state
- [Workdir Provisioning](/stacks/components/provision/workdir) — The other half of the `provision:` block
- [`atmos terraform backend`](/cli/commands/terraform/terraform-backend) — CLI commands for backend management
- [`terraform-aws-tfstate-backend`](https://github.com/cloudposse/terraform-aws-tfstate-backend) — Advanced backend module
