🏗️

Top 45 Terraform / IaC Interview Questions & Answers (2026)

45 Questions 20 Beginner 15 Intermediate 10 Advanced

About Terraform / IaC

Top 50 Terraform and Infrastructure as Code interview questions covering HCL, state management, modules, providers, workspaces, and cloud provisioning. Companies hiring for Terraform / IaC roles test this knowledge at every stage — from first-round screens that check the basics to final-round conversations about real-world trade-offs.

What to Expect in a Terraform / IaC Interview

Expect a mix of conceptual and practical Terraform / IaC questions: clear definitions and core-concept checks for junior roles, hands-on scenario questions for mid-level roles, and architecture or trade-off discussions for senior roles. Interviewers usually move from foundational topics toward the kind of problems you'd actually face on the job.

How to Use This Guide

Work through the Terraform / IaC questions in order — Beginner, then Intermediate, then Advanced — so each concept builds on the last. Every question has its own page; bookmark the ones that trip you up and revisit them the day before your interview.

Curated by Tech Baithak Editorial Team  ·  Last updated: June 2026

Beginner 20 questions

Core concepts every Terraform / IaC developer must know.

01

What is Infrastructure as Code (IaC)?

Infrastructure as Code (IaC) is the practice of defining and managing cloud and on-premises infrastructure through machine-readable configuration files rather than manual processes. Instead of clicking through a cloud console, you write code that describes the desired state of your infrastructure. Benefits: Consistency: the same code produces identical environments every time. Version control: infrastructure changes are tracked in Git with history, blame, and rollback. Automation: integrate with CI/CD pipelines for automated provisioning. Documentation: code is self-documenting infrastructure. Disaster recovery: recreate entire environments from code. Popular IaC tools: Terraform (multi-cloud), AWS CloudFormation, Azure Bicep/ARM, Pulumi (general-purpose languages), Ansible (configuration management). IaC is a foundational DevOps and SRE practice.

Open this question on its own page
02

What is Terraform?

Terraform is an open-source Infrastructure as Code tool created by HashiCorp. It uses a declarative language called HCL (HashiCorp Configuration Language) to define the desired state of infrastructure across multiple cloud providers and services. Terraform determines what changes need to be made to reach the desired state and executes them in the correct order. Key characteristics: Multi-cloud: works with AWS, Azure, GCP, Kubernetes, GitHub, Datadog, and thousands of other providers via provider plugins. Declarative: you describe what you want, not how to create it. Idempotent: running the same configuration multiple times produces the same result. State management: tracks the actual deployed infrastructure in a state file. Terraform is the most widely used IaC tool for cloud infrastructure provisioning.

Open this question on its own page
03

What is HCL (HashiCorp Configuration Language)?

HCL (HashiCorp Configuration Language) is the configuration language used by Terraform (and other HashiCorp tools). It is designed to be both human-readable and machine-parseable. Key syntax elements: Blocks: define resources, providers, variables, outputs. resource "aws_instance" "web" { ami = "ami-123" instance_type = "t3.micro" }. Arguments: key-value pairs within blocks. Expressions: reference values: var.region, aws_vpc.main.id. Comments: # or // for single-line, /* */ for multi-line. String interpolation: "${var.prefix}-server". HCL supports conditionals (condition ? true_val : false_val), for expressions, count and for_each meta-arguments for resource iteration. Files use the .tf extension.

Open this question on its own page
04

What are the main Terraform commands?

The core Terraform workflow uses these commands: terraform init: initializes the working directory — downloads provider plugins and modules, creates the .terraform directory. Run this first and after any provider/module changes. terraform plan: shows what changes will be made (add, change, destroy) without actually applying them. The plan is the most important safety check. terraform apply: applies the planned changes. Prompts for confirmation unless --auto-approve is used. terraform destroy: destroys all resources managed by the configuration. terraform validate: checks HCL syntax and configuration correctness without accessing APIs. terraform fmt: formats code to canonical style. terraform output: displays output values. terraform state: manage state (list, show, move, remove resources). terraform import: bring existing resources into Terraform management.

Open this question on its own page
05

What is Terraform state?

Terraform state is a JSON file (terraform.tfstate) that records the mapping between your Terraform configuration and the actual deployed infrastructure. Terraform uses state to: determine what changes are needed (compare desired config vs actual state), track resource metadata (IDs, ARNs), and manage dependencies. By default, state is stored locally in terraform.tfstate. For team environments, store state remotely (S3, Azure Blob, GCS, Terraform Cloud) with state locking (DynamoDB, Blob lease) to prevent concurrent modifications. Never edit state manually — use terraform state commands. Protect state files — they contain sensitive values like passwords and private keys. Enable versioning on the remote backend bucket for rollback capability.

Open this question on its own page
06

What is a Terraform Provider?

A Terraform Provider is a plugin that enables Terraform to interact with a specific infrastructure platform or service. Each provider defines resource types and data sources for that platform. Configure providers in a required_providers block: terraform { required_providers { aws = { source = "hashicorp/aws"; version = "~> 5.0" } } }. Then configure credentials: provider "aws" { region = "us-east-1" }. Popular providers: AWS, Azure (azurerm), Google Cloud (google), Kubernetes, Helm, GitHub, Datadog. Providers are distributed via the Terraform Registry (registry.terraform.io). The provider is downloaded during terraform init. Pin provider versions to avoid unexpected upgrades breaking your infrastructure.

Open this question on its own page
07

What is a Terraform Resource?

A Terraform Resource is the most important element in HCL — it represents a real infrastructure object to create and manage. Syntax: resource "<provider_type>" "<local_name>" { ... }. Example: resource "aws_instance" "web_server" { ami = "ami-0c55b159cbfafe1f0"; instance_type = "t3.micro"; tags = { Name = "WebServer" } }. The combination of type (aws_instance) and name (web_server) forms a unique address: aws_instance.web_server. Reference its attributes: aws_instance.web_server.id, aws_instance.web_server.public_ip. Terraform automatically orders resource creation based on references — if resource B references resource A's output, A is created first. Meta-arguments like count, for_each, depends_on, and lifecycle apply to all resource types.

Open this question on its own page
08

What are Terraform Variables?

Terraform variables make configurations reusable and parameterizable. Declare input variables: variable "region" { type = string; default = "us-east-1"; description = "AWS region to deploy in" }. Use: provider "aws" { region = var.region }. Set variable values: tfvars files: create terraform.tfvars or prod.tfvars. Environment variables: TF_VAR_region=us-east-2. Command line: terraform apply -var="region=us-west-2". Types: string, number, bool, list(string), map(string), object({ ... }), any. Mark sensitive variables with sensitive = true to prevent them from appearing in plan output and logs. Use validation blocks to enforce allowed values.

Open this question on its own page
09

What are Terraform Outputs?

Terraform Outputs expose values from your configuration — they are the return values of a Terraform module. Declare: output "instance_ip" { value = aws_instance.web.public_ip; description = "Public IP of the web server" }. View: terraform output instance_ip after apply. Outputs are used to: share values between Terraform configurations (root module to calling module), surface resource IDs and endpoints for use in scripts/CI, expose child module values to the parent. Mark outputs as sensitive = true to suppress them in logs. In root modules, outputs are saved to state and displayed after apply. In child modules, outputs are the only way to pass values to the calling module — all other resource attributes are private to the module.

Open this question on its own page
10

What is a Terraform Module?

A Terraform Module is a container for multiple resources that are used together. Every directory containing Terraform files is a module. The directory you run Terraform from is the root module. Reusable modules are called child modules. Call a module: module "vpc" { source = "./modules/vpc"; region = var.region; cidr_block = "10.0.0.0/16" }. Source can be a local path, Terraform Registry path ("terraform-aws-modules/vpc/aws"), Git URL, or S3 bucket. Modules encapsulate complexity — a VPC module might create the VPC, subnets, internet gateway, route tables, and NAT gateways internally, exposing only vpc_id and subnet_ids as outputs. The Terraform Registry has hundreds of official and community modules for common infrastructure patterns.

Open this question on its own page
11

What is the difference between terraform plan and terraform apply?

terraform plan is a dry run — it reads the current state, compares it with the desired configuration, and shows exactly what would be created, modified, or destroyed. It makes no changes to real infrastructure. Output shows: + (resource to create), ~ (resource to modify in-place), -/+ (resource to destroy and recreate), - (resource to destroy). Always review the plan carefully before applying. In CI/CD, run plan in PRs for code review. terraform apply executes the plan — first shows the plan again and prompts for confirmation, then applies changes. Use terraform plan -out=tfplan to save the plan, then terraform apply tfplan to apply exactly that plan (safe for automation). The golden rule: never run apply on infrastructure you haven't reviewed the plan for.

Open this question on its own page
12

What is the Terraform Registry?

The Terraform Registry (registry.terraform.io) is the official repository for Terraform providers and modules. Providers: search and find provider documentation. HashiCorp maintains official providers (AWS, Azure, GCP, Kubernetes). Partners and community maintain their own. Modules: pre-built, peer-reviewed modules for common infrastructure patterns. Official modules like terraform-aws-modules/vpc/aws are extensively tested and widely used. Usage in configuration: source = "terraform-aws-modules/vpc/aws"; version = "5.1.0". Benefits of using Registry modules: reduce boilerplate, follow best practices, get community bug fixes, and use well-documented interfaces. Always pin module versions — version = "~> 5.1" — to avoid unexpected breaking changes from module updates.

Open this question on its own page
13

What is Terraform remote state?

Remote state stores the Terraform state file in a shared location accessible to all team members and CI/CD systems, rather than locally. Configure with a backend block: terraform { backend "s3" { bucket = "my-tf-state"; key = "prod/vpc/terraform.tfstate"; region = "us-east-1"; dynamodb_table = "tf-locks" } }. Benefits: Collaboration: all team members use the same state. State locking: prevents concurrent applies (DynamoDB lock for S3 backend). Security: state is not on developer laptops. Versioning: S3 bucket versioning allows rollback. Common backends: S3 + DynamoDB (AWS), Azure Blob Storage, GCS (GCP), Terraform Cloud (managed, includes locking and remote execution). Run terraform init after changing backends — Terraform will offer to migrate local state to the remote backend.

Open this question on its own page
14

What is count and for_each in Terraform?

count and for_each are meta-arguments for creating multiple instances of a resource. count: create N identical resources. resource "aws_instance" "web" { count = 3; ... }. Reference by index: aws_instance.web[0].id. Problem: if you remove an item from the middle, all subsequent resources are renamed and recreated. for_each: create resources from a map or set. for_each = { "web" = "t3.micro", "db" = "t3.large" }. Reference by key: aws_instance.servers["web"].id. each.key and each.value are available inside the block. Advantage over count: removing one item from the map only affects that specific resource. Prefer for_each over count when resources have meaningful identities. Use count only for truly homogeneous resources (like N identical replicas).

Open this question on its own page
15

What is terraform.tfvars file?

The terraform.tfvars file provides values for input variables. Terraform automatically loads it if present in the working directory. Format: plain variable assignments: region = "us-east-1"\ninstance_type = "t3.micro"\nallowed_cidrs = ["10.0.0.0/8", "192.168.0.0/16"]. For different environments, create named files: dev.tfvars, prod.tfvars. Load explicitly: terraform apply -var-file="prod.tfvars". Files ending in .auto.tfvars are loaded automatically without explicit flags. Do not commit sensitive tfvars files to Git — add *.tfvars to .gitignore (except non-sensitive example files). For CI/CD, pass sensitive values via environment variables (TF_VAR_*) or secret management systems. Provide a terraform.tfvars.example with placeholder values for documentation.

Open this question on its own page
16

What are Terraform data sources?

Data sources allow Terraform to read information from existing infrastructure or external sources without managing it. Syntax: data "<provider_type>" "<local_name>" { ... }. Example: data "aws_ami" "ubuntu" { most_recent = true; filter { name = "name"; values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"] } }. Use its output: resource "aws_instance" "web" { ami = data.aws_ami.ubuntu.id }. Common use cases: look up the latest AMI, read an existing VPC ID to deploy into, get secrets from AWS Secrets Manager, query existing Route53 zones. Data sources query the provider's API during plan — they do not create resources but provide reference data. They are essential for referencing infrastructure managed outside Terraform (manually created or by another team).

Open this question on its own page
17

What is the lifecycle block in Terraform?

The lifecycle meta-argument block controls how Terraform handles resource creation, updates, and deletion. Key settings: create_before_destroy: when a resource must be replaced, create the new one before destroying the old — prevents downtime for immutable resources like SSL certificates. lifecycle { create_before_destroy = true }. prevent_destroy: raises an error if anything attempts to destroy this resource. Use for databases and S3 buckets that should never be accidentally deleted. lifecycle { prevent_destroy = true }. ignore_changes: ignore specific attribute changes (e.g., tags managed externally). lifecycle { ignore_changes = [tags] }. replace_triggered_by: force replacement when referenced resources change. Understanding lifecycle is critical for managing stateful resources like databases safely.

Open this question on its own page
18

What is Terraform Cloud?

Terraform Cloud is HashiCorp's managed service for Terraform workflows, providing remote state storage, remote execution, VCS integration, and team collaboration features. Key features: Remote state: stores and versions state files with locking. Remote runs: executes Terraform plans and applies on Terraform Cloud's infrastructure (instead of developer laptops or CI servers). VCS integration: automatically triggers runs when code is pushed to GitHub/GitLab. Sentinel policies: policy-as-code to enforce governance rules (prevent resources in unapproved regions, require tags). Workspaces: manage multiple environments. Cost estimation: shows cost impact of planned changes. The Free tier covers remote state for teams. Paid tiers add Sentinel, SSO, audit logs, and private module registry. Terraform Enterprise is the self-hosted version for enterprises with strict data residency requirements.

Open this question on its own page
19

What is the difference between Terraform and Ansible?

Terraform and Ansible serve complementary but different purposes. Terraform: declarative, infrastructure provisioning tool. Best for creating and managing cloud resources (VMs, networks, databases, Kubernetes clusters). Manages state and detects drift. Stateful — knows what it has created. Ansible: procedural, configuration management and application deployment tool. Best for installing software on existing servers, configuring OS settings, deploying applications. Stateless — does not track what it has changed. Uses SSH/WinRM to connect to targets. Common pattern: use Terraform to provision the infrastructure (create EC2 instances, VPC, RDS), then use Ansible to configure the servers (install Nginx, deploy application code, set up monitoring). They are complementary tools — Terraform handles infrastructure provisioning, Ansible handles what runs on that infrastructure.

Open this question on its own page
20

What are Terraform workspaces?

Terraform workspaces allow multiple state files from the same configuration, enabling different deployments (environments) from the same code. Commands: terraform workspace new staging, terraform workspace select prod, terraform workspace list. Each workspace has its own state file stored separately. Reference the workspace name in configuration: resource "aws_instance" "web" { tags = { Environment = terraform.workspace } }. Use different variable files per workspace: terraform apply -var-file="${terraform.workspace}.tfvars". Limitations: workspaces share the same backend; they are not isolated by default (same AWS account/region unless configured otherwise). For strong environment isolation (separate AWS accounts), use separate Terraform configurations or directories with separate backends rather than workspaces. Workspaces are best for short-lived feature branch environments, not permanent prod/staging separation.

Open this question on its own page
Intermediate 15 questions

Practical knowledge for developers with hands-on experience.

01

What is the Terraform state locking mechanism?

State locking prevents multiple Terraform runs from modifying state simultaneously, which could corrupt the state file. When Terraform starts a write operation (plan, apply, destroy), it acquires a lock. If another process already holds the lock, the second process waits. Backend-specific implementations: S3 + DynamoDB: Terraform writes a lock item to a DynamoDB table with the lock ID, caller, and timestamp. The item is deleted when the lock is released. Azure Blob Storage: uses Azure Blob lease (built-in). GCS: uses GCS object locking. Terraform Cloud: has built-in locking. If a process crashes while holding the lock, manually release it: terraform force-unlock <LOCK_ID>. Always configure state locking for any team environment. Without locking, two simultaneous terraform apply operations will race and can produce corrupted state.

Open this question on its own page
02

How do you handle sensitive values in Terraform?

Sensitive values in Terraform require careful handling. Variable sensitivity: mark variables with sensitive = true — their values are redacted in plan output and logs but still stored in state. Output sensitivity: similarly mark outputs as sensitive = true. State file security: state files contain all sensitive values in plain text — encrypt your remote backend (S3 server-side encryption, Azure storage encryption), restrict access with IAM/RBAC, and never commit state to Git. Secrets injection: do not hardcode secrets in tfvars files. Instead, inject via environment variables (TF_VAR_db_password=$SECRET) sourced from a vault. Use the Vault provider or AWS Secrets Manager data source to read secrets at plan time. SOPS: encrypt tfvars files at rest. The Terraform provider documentation often has specific guidance for managing service credentials securely.

Open this question on its own page
03

What are Terraform Provisioners and when should you avoid them?

Terraform Provisioners execute scripts on local or remote machines during resource creation or destruction. Types: local-exec: runs a command on the machine running Terraform. remote-exec: SSH into a resource and run commands. file: copy files to a remote resource. Example: install software after creating a VM. Why to avoid them: HashiCorp officially recommends using provisioners as a last resort. Problems: provisioners run only at creation/destroy, not on updates; they break Terraform's idempotency; they can fail silently or leave resources in partial states; they make plans unreliable (Terraform cannot know what the script does). Better alternatives: use cloud-init/user_data for initial VM configuration, use purpose-built configuration management tools (Ansible, Chef, Puppet) post-provisioning, use pre-baked images with Packer, or use container images. Reserve provisioners only for bootstrapping that cannot be handled any other way.

Open this question on its own page
04

What is Terraform import?

Terraform import brings existing infrastructure (created manually or by other tools) under Terraform management. Without importing, Terraform would try to create duplicate resources. Classic syntax: terraform import aws_instance.web i-0abc123def — adds the existing EC2 instance to state. You must write the corresponding resource block in your configuration before importing. After import, run terraform plan — if the configuration matches reality, it shows no changes; if not, the plan shows what Terraform would change to match your config. New import block (Terraform 1.5+): declarative import in HCL: import { to = aws_instance.web; id = "i-0abc123def" }. Run terraform plan -generate-config-out=generated.tf to auto-generate the resource block. Import does not modify the actual infrastructure — it only updates state. Avoid importing large numbers of resources manually; consider tools like Terraformer or cf2tf for bulk import.

Open this question on its own page
05

How do you structure Terraform code for large teams?

Scaling Terraform for large teams involves several patterns. Environment separation: use separate directories (or workspaces with separate state) per environment: infra/envs/dev/, infra/envs/prod/. Each environment has its own main.tf calling shared modules. Module library: extract reusable patterns into modules (infra/modules/vpc/, infra/modules/eks/). Publish to a private module registry or maintain in the same repo. Layer separation: split infrastructure into layers (network, databases, applications) with separate state files — changes to the app layer don't risk the network layer. Remote state data sources: reference other layers' outputs via terraform_remote_state. Atlantis or Terraform Cloud: automate plan/apply in CI/CD with PR-based workflows. Naming conventions: consistent resource tagging with environment, team, and project. Linting: tflint, checkov, and tfsec in CI pipelines.

Open this question on its own page
06

What is Terragrunt?

Terragrunt is a thin wrapper around Terraform that provides extra tooling for working with multiple Terraform modules and environments. Key features: DRY (Don't Repeat Yourself): define backend configuration and provider settings once in a parent terragrunt.hcl and inherit in all child configs. Dependency management: explicitly declare dependencies between Terraform modules and automatically pass outputs: dependency "vpc" { config_path = "../vpc"; inputs = { vpc_id = dependency.vpc.outputs.vpc_id } }. run-all: apply all modules in a directory respecting dependency order: terragrunt run-all apply. Hooks: run scripts before/after Terraform commands. Generate blocks: dynamically generate HCL files (backend configs, provider configs). Terragrunt is popular in large organizations running Terraform at scale across dozens of environments and regions, where Terraform's native module and workspace support becomes unwieldy.

Open this question on its own page
07

What are Terraform modules best practices?

Terraform module best practices: Single purpose: each module should do one thing well (a VPC module, a GKE cluster module). Avoid "do everything" mega-modules. Interface design: expose the minimum necessary inputs and outputs. Hide internal complexity. Version pinning: always use version constraints on module sources. Documentation: document all inputs and outputs with descriptions. Use terraform-docs to auto-generate README. Examples: include a working example in an examples/ directory. Testing: use Terratest (Go) or Terraform's built-in testing framework (.tftest.hcl) to validate modules. Semantic versioning: version modules with semver; breaking changes bump major version. No provider configuration in modules: modules should not configure providers — pass them from the root. Avoid hardcoding: make regions, tags, and names configurable. Use the official AWS/Azure/GCP Registry modules as reference implementations.

Open this question on its own page
08

What is the terraform_remote_state data source?

The terraform_remote_state data source reads the outputs of another Terraform state file, enabling cross-stack references without hardcoding values. Example: read VPC ID from a network stack into an application stack: data "terraform_remote_state" "network" { backend = "s3"; config = { bucket = "my-tf-state"; key = "network/terraform.tfstate"; region = "us-east-1" } }. Reference: module "app" { vpc_id = data.terraform_remote_state.network.outputs.vpc_id }. Requirements: the referenced state must be accessible (correct IAM permissions) and the output must be declared in the source configuration. Limitation: this creates a tight coupling between stacks — the referencing stack fails if the referenced state doesn't exist or its outputs change. Alternative: use SSM Parameter Store, Consul, or other external stores for loose coupling between independent stacks.

Open this question on its own page
09

How do you test Terraform code?

Terraform testing approaches: terraform validate: syntax and basic configuration checks (fast, no API calls). tflint: linter that checks for provider-specific errors (invalid instance types, deprecated attributes), enforces naming conventions. terraform plan: integration test against the actual provider API — shows what would change. Run in CI on PRs. Terratest (Go library by Gruntwork): deploy real infrastructure, run assertions against it, then destroy. The gold standard but expensive to run. Built-in testing framework (Terraform 1.6+): write .tftest.hcl files with run blocks that call modules and assert against plan or apply output. checkov: static analysis for security misconfigurations (open security groups, unencrypted S3 buckets). OPA/Conftest: policy-as-code tests for governance checks. A complete testing pipeline: validate → tflint → checkov → plan review → Terratest (on merge).

Open this question on its own page
10

What is Terraform drift and how do you handle it?

Terraform drift occurs when the actual state of infrastructure diverges from the Terraform state — usually because someone changed infrastructure manually (console clicks, CLI commands) rather than through Terraform. Detecting drift: terraform plan compares real infrastructure (via API calls) with state and shows differences. terraform refresh updates the state file to match reality without making changes (deprecated in favor of terraform apply -refresh-only). Handling drift options: Accept and reconcile: run terraform apply to revert to the desired Terraform configuration, overwriting the manual change. Accept and adopt: update the Terraform configuration to match the manual change, then run apply (no changes). Prevent drift: use IAM policies to deny direct console access to Terraform-managed resources; enforce change management through Terraform only. Tools like driftctl scan for all untracked resources in your cloud account, revealing what Terraform doesn't know about.

Open this question on its own page
11

What is the Terraform provider version constraint syntax?

Terraform uses version constraint strings to specify acceptable provider and module versions. Operators: =: exact version only. !=: exclude a version. >, >=, <, <=: comparison operators. ~> (pessimistic constraint operator): allows only the rightmost version component to increment. ~> 5.0 allows 5.0, 5.1, 5.99 but NOT 6.0. ~> 5.0.2 allows 5.0.2, 5.0.3 but NOT 5.1.0. Best practices: use ~> major.minor to allow patch updates while pinning the minor version. The .terraform.lock.hcl file (committed to Git) locks exact provider versions — ensuring all team members and CI use the same provider version even if the constraint allows a range. Run terraform init -upgrade to update locked versions within constraints.

Open this question on its own page
12

What is the Terraform lifecycle of a resource?

A Terraform resource goes through these lifecycle phases. Plan: Terraform reads current state, calls provider APIs to get actual resource state, and computes the diff with desired configuration. Generates a plan showing required actions. Apply - Create: provider plugin calls cloud API to create the resource. Terraform writes the new resource to state with its ID and attributes. Apply - Update in-place: provider API calls are made to modify specific attributes. State is updated. Apply - Destroy and recreate: some attributes require destroying and recreating (immutable parameters). Old resource is destroyed, new one created. create_before_destroy = true inverts the order. Apply - Destroy: cloud API called to delete the resource. State entry is removed. Read (Refresh): Terraform reads current resource state from the cloud API to detect drift. Understanding when update-in-place vs recreate happens is critical for managing production resources safely.

Open this question on its own page
13

What is Packer and how does it relate to Terraform?

Packer is a HashiCorp tool for creating identical machine images (AMIs, VHDs, Docker images) from a single template across multiple platforms. It automates creating pre-baked images with all software pre-installed. Relationship with Terraform: Build time vs runtime: Packer builds the image with software; Terraform deploys instances using that image. Workflow: 1. Packer: starts a temporary VM, installs Nginx/Java/your app via a shell provisioner or Ansible, creates a snapshot (AMI), terminates the VM. 2. Terraform: use the AMI ID from Packer as the ami attribute. VMs launch instantly with everything pre-installed. Benefits: faster instance boot (no user_data scripts), immutable infrastructure (never modify running instances — build a new image and redeploy), consistent environments. The Packer AMI ID can be passed to Terraform via a data source: data "aws_ami" "my_app" { filter { name = "tag:Version"; values = ["1.2.3"] } }.

Open this question on its own page
14

What is Atlantis and how does it automate Terraform?

Atlantis is an open-source tool that automates Terraform pull request workflows. When a developer opens a PR with Terraform changes, Atlantis automatically runs terraform plan and posts the output as a PR comment. Team members review the plan and approve. After approval, a atlantis apply comment triggers the apply. Benefits: Plan visibility: everyone sees exactly what will change before merging. Apply gating: requires human approval (and optionally successful CI) before applying. No local apply: developers never run apply locally — all applies go through the PR workflow with a full audit trail. Webhook-driven: Atlantis runs on a server (or as a Kubernetes pod) and listens to GitHub/GitLab webhooks. Configuration: atlantis.yaml defines which Terraform paths to watch and workspace configurations. Atlantis is the most popular open-source alternative to Terraform Cloud for teams wanting GitOps-based Terraform automation on their own infrastructure.

Open this question on its own page
15

How do you manage multiple environments in Terraform?

Multiple environment strategies in Terraform: Directory-per-environment (recommended): separate directories envs/dev/main.tf, envs/prod/main.tf. Each calls shared modules with different variables. Each environment has its own state file. Strong isolation — a mistake in dev never touches prod state. Workspaces: single config, multiple state files. Simpler but risk of one codebase affecting all environments. Best for short-lived environments. Terragrunt environment hierarchy: parent terragrunt.hcl with DRY backend config; each env folder overrides variables. Scales well for many environments and regions. Variable overrides: use *.auto.tfvars files per environment loaded based on workspace or CLI flags. The directory-per-environment approach is the most robust for production systems because it provides full isolation of state and can use different IAM credentials per environment, preventing accidents.

Open this question on its own page
Advanced 10 questions

Deep expertise questions for senior and lead roles.

01

What is Terraform's provider development and custom providers?

Custom Terraform providers let you manage any API as Terraform resources. Providers are written in Go using the Terraform Plugin Framework (current) or the legacy Plugin SDK. A provider implements: Provider schema: configuration (credentials, endpoints). Resources: CRUD operations (Create, Read, Update, Delete) as Go functions that call the target API. Data sources: Read-only operations. The framework uses resource.Schema to define attribute types and validation. Publish to the Terraform Registry with a GitHub release and GPG-signed binary. Use cases: internal company APIs, third-party SaaS tools without community providers, on-premises systems. The CDKTF (CDK for Terraform) is an alternative — write providers and configurations in TypeScript, Python, Java, or C#, compiled to HCL JSON. The terraform-provider-scaffolding-framework template is the starting point for new providers.

Open this question on its own page
02

What is Policy as Code with Sentinel in Terraform?

Sentinel is HashiCorp's policy-as-code framework embedded in Terraform Cloud/Enterprise. Policies are Go-like rules evaluated between plan and apply — if a policy fails, the apply is blocked. Example policy: import "tfplan/v2" as tfplan; all_ec2 = filter tfplan.resource_changes as _, rc { rc.type == "aws_instance" } rule "require_tags" { all all_ec2 as _, instance { instance.change.after.tags contains "Environment" and instance.change.after.tags contains "Owner" } }. Enforcement levels: advisory (warn only), soft-mandatory (overridable by approved users), hard-mandatory (never overridable). Common policies: require specific tags, deny resources in unapproved regions, enforce encryption on storage, require minimum security group rules. OPA (Open Policy Agent) with Conftest is the open-source alternative for Sentinel-like checks in any CI system without Terraform Cloud.

Open this question on its own page
03

How does Terraform handle dependencies between resources?

Terraform automatically handles resource dependencies through two mechanisms. Implicit dependencies (preferred): when one resource references another's attribute, Terraform infers a dependency and creates/updates them in the correct order. resource "aws_eip" "ip" { instance = aws_instance.web.id } — Terraform knows to create the instance before the EIP. Explicit dependencies: use depends_on when the dependency cannot be inferred from attribute references — typically for IAM policies that need to exist before a resource that uses them but aren't referenced directly. resource "aws_instance" "web" { depends_on = [aws_iam_role_policy.web_policy] }. Terraform builds a dependency graph (DAG) and applies resources in topological order, running independent resources in parallel. The terraform graph command outputs a DOT format visualization of the dependency graph. Circular dependencies cause a validation error.

Open this question on its own page
04

What is the Terraform CDK (CDKTF)?

The Cloud Development Kit for Terraform (CDKTF) allows defining Terraform infrastructure using general-purpose programming languages instead of HCL. Supported languages: TypeScript, Python, Java, C#, Go. CDKTF generates HCL JSON that Terraform can apply. Example in TypeScript: import { App, TerraformStack } from "cdktf"; import { AwsProvider, instance } from "@cdktf/provider-aws"; class MyStack extends TerraformStack { constructor(scope, id) { super(scope, id); new AwsProvider(this, "AWS", { region: "us-east-1" }); new instance.Instance(this, "Compute", { ami: "ami-0c55b159cbfafe1f0", instanceType: "t3.micro" }) } }. Benefits: use programming language constructs (loops, conditions, classes) instead of HCL's limited expressions; IDE type-checking; leverage existing package ecosystems. Downsides: adds complexity and requires familiarity with the language. CDKTF is gaining adoption in teams already using TypeScript or Python extensively who find HCL limiting for complex dynamic infrastructure.

Open this question on its own page
05

What are advanced Terraform state management operations?

Advanced state management operations for production scenarios: terraform state mv: rename a resource in state without destroying it — used when refactoring module structure or renaming resources. terraform state mv module.old.aws_instance.web module.new.aws_instance.web. terraform state rm: remove a resource from state without destroying the actual infrastructure — used when you want to stop managing a resource with Terraform. terraform state pull/push: download or upload state JSON directly — for manual state surgery (last resort). terraform state replace-provider: replace the provider source in state after provider namespace changes. State migration: move state between backends by changing the backend config and running terraform init -migrate-state. Partial state corruption recovery: use state versioning (S3 versioning enabled on the state bucket) to restore a previous state version. Always back up state before any manual state operations.

Open this question on its own page
06

How do you implement a CI/CD pipeline for Terraform?

A production Terraform CI/CD pipeline: PR checks: terraform fmt --check (formatting), terraform validate (syntax), tflint (linting), checkov (security scan), terraform plan (post plan as PR comment via Atlantis or GitHub Actions). Gate merging on a passing plan review. Merge to main: trigger terraform apply automatically (for lower environments) or with manual approval (for production). Separate pipelines per environment: dev applies automatically; staging requires approval; prod requires approval + change ticket. OIDC authentication: use GitHub Actions OIDC to authenticate to AWS/Azure without long-lived secrets — the pipeline assumes an IAM role via a short-lived token. State isolation: each environment's pipeline uses different backend config and IAM role. Blast radius limiting: use -target only in emergencies; normally apply entire configurations. Notifications: send apply results to Slack with resource counts and changes.

Open this question on its own page
07

What is Terraform's approach to secret management with Vault?

HashiCorp Vault integrates tightly with Terraform for secret management. Vault Provider: Terraform can read secrets from Vault: data "vault_generic_secret" "db_creds" { path = "secret/database/prod" }. Use the secret: resource "aws_db_instance" "main" { password = data.vault_generic_secret.db_creds.data["password"] }. Dynamic credentials: Vault's AWS secrets engine generates short-lived AWS credentials — Terraform can use these instead of long-lived IAM keys. Vault as Terraform Cloud backend: store Terraform state in Vault's storage backend. Security concerns: Vault secrets read by Terraform are stored in state — encrypt state and restrict access. Vault Agent: run Vault Agent as a sidecar to inject secrets into environment variables before Terraform runs, avoiding the secret ever appearing in state. This pattern is common in Kubernetes-based Terraform execution where Vault is the company-wide secrets manager.

Open this question on its own page
08

What are common Terraform anti-patterns and pitfalls?

Common Terraform anti-patterns to avoid: Storing secrets in state unencrypted: always encrypt remote backend and restrict access. Monolithic state file: one state for entire company infrastructure — blast radius is enormous; split by layer and team. No state locking: allows concurrent apply corruption. Manual changes to Terraform-managed resources: causes drift and confusion. count for non-homogeneous resources: causes destructive index shifts; use for_each. Hard-coded values: credentials, region, account IDs in .tf files; use variables and environment-specific configs. Missing version constraints: provider and module versions unpinned; next init may break everything. Committed terraform.tfvars with secrets: sensitive values in Git history. No destroy protection: databases without prevent_destroy. Using provisioners for everything: breaks idempotency. Missing tagging strategy: impossible to track cost and ownership without consistent tags. No testing: applying to prod without validate, tflint, checkov, or plan review.

Open this question on its own page
09

How does Terraform handle provider authentication in different environments?

Production Terraform provider authentication best practices by environment: Local development: AWS CLI credentials from ~/.aws/credentials or environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY). Use named profiles: provider "aws" { profile = "dev-account" }. CI/CD (GitHub Actions): use OIDC — configure GitHub Actions as a trusted IdP in AWS/Azure, then assume an IAM role using a short-lived token: aws-actions/configure-aws-credentials@v4 with role-to-assume. No long-lived secrets needed. EC2/ECS/Lambda: use Instance Profiles / Task Roles — IAM roles attached to the compute resource; Terraform automatically uses the metadata service. Kubernetes (EKS/GKE): Workload Identity (GKE) or IRSA (IAM Roles for Service Accounts on EKS) — bind the Terraform runner's service account to a cloud IAM role. Terraform Cloud: configure dynamic provider credentials via OIDC for all major clouds. The golden rule: no long-lived credentials stored in files, environment variables, or CI secrets — use OIDC or instance roles wherever possible.

Open this question on its own page
10

What is OpenTofu and how does it relate to Terraform?

OpenTofu is an open-source fork of Terraform maintained by the Linux Foundation's OpenTofu project. It was created in 2023 after HashiCorp changed Terraform's license from the open-source MPL 2.0 to the Business Source License (BSL/BUSL), which restricts commercial use competing with HashiCorp. OpenTofu forked from the last MPL 2.0 version (Terraform 1.5.7) and continues development under the MPL 2.0 license. Compatibility: OpenTofu is a drop-in replacement for Terraform 1.x — the same .tf files, state files, providers, and modules work without modification. OpenTofu has since added new features including improved state encryption, for_each in provider blocks, and enhanced testing capabilities. The community maintains both projects, but OpenTofu is gaining adoption among organizations concerned about the license change. Most Terraform skills and knowledge transfer directly to OpenTofu.

Open this question on its own page
Back to All Topics 45 questions total