interview-prep

Crisp answer: The terraform block sets global configuration: required provider sources and version constraints, the backend for state storage, and the minimum Terraform CLI version. It must not use variables or references.

Full example:

terraform {
  # Minimum Terraform version required to run this config
  required_version = ">= 1.9"

  # Provider sources and version constraints
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = "~> 2.30"
    }
    helm = {
      source  = "hashicorp/helm"
      version = "~> 2.14"
    }
  }

  # Remote state backend
  backend "s3" {
    bucket       = "my-terraform-state"
    key          = "prod/eks/terraform.tfstate"
    region       = "eu-west-2"
    use_lockfile = true   # S3-native locking, Terraform >= 1.9
    encrypt      = true
  }
}

Why required_version matters:

Different Terraform versions have different syntax, behaviours, and provider compatibility. Pinning required_version prevents a team member with an older CLI from silently producing a different plan.

# If your CLI is older than required:
terraform plan
# Error: Unsupported Terraform Core version
# This configuration does not support Terraform version 1.7.0.

Backend configuration rules:

The backend block cannot use variables, locals, or references. Values must be hardcoded strings. This is because the backend must be initialised before Terraform evaluates any expressions.

# WRONG — not allowed:
backend "s3" {
  bucket = var.state_bucket   # ← variables not allowed in backend
}

# RIGHT — partial configuration with -backend-config:
backend "s3" {}
# Then:
terraform init -backend-config="bucket=my-state-bucket" \
               -backend-config="key=prod/terraform.tfstate" \
               -backend-config="region=eu-west-2"

The partial configuration pattern (empty backend block with values passed via -backend-config) is useful for CI pipelines where the state bucket name differs per environment.

What to say in the interview:

"The terraform block is the global config: required_version pins the CLI version, required_providers declares where to download providers and what version constraints to apply, and backend configures remote state. The backend block has a constraint that prevents variables — values must be literals. This leads to the partial configuration pattern in CI where you pass backend values via -backend-config flags rather than hardcoding environment-specific bucket names."


My notes