Terraform in Real Life & the Associate Exam: interview questions
The question you are most likely to get for each topic, a model answer, and what else comes up. From chapter 14 of the course.
How would you set up Terraform for a team that runs dev, test and prod? Mid
- Layout: shared code in
modules/, and one thin root per environment (envs/dev,envs/prod): a provider, a backend, one module call, values interraform.tfvars. Not CLI workspaces - they share one backend and one set of credentials, and the environment is invisible in the path. - State: one backend key per environment; prod ideally in its own storage account, readable only by prod's pipeline identity.
- Checks on every PR:
terraform fmt -check -recursive,terraform validate,tflint,checkov- no cloud login needed. - Pipeline:
plan -out=tfplanas an artifact, a scan and a jq gate on the plan JSON, a human approval, thenapply tfplan- exactly what was reviewed. Login with OIDC, no stored secrets. The pipeline is the only way to prod. - Secrets: generated into a secret store, referenced by apps, never in tfvars.
- Versions pinned:
required_version, provider constraints plus the lock file, module refs; upgrades in PRs, dev first. - A nightly
plan -detailed-exitcodeper environment for drift.
Also asked: How do you keep secrets out of Terraform? · What does "plan as an artifact" mean? · What is the difference between terraform fmt, validate and tflint?
How do you manage dev and prod with Terraform: separate directories or workspaces? Mid
Directory per environment for real environments: shared code in modules/, one thin root per environment (envs/dev, envs/prod) with its own backend key and its own terraform.tfvars.
Why not CLI workspaces (terraform workspace new prod, one folder, one state per workspace):
- Hidden state - which environment you are in lives in
.terraform/environment, not in the path. An apply in the wrong workspace looks like the right one. - One backend, one set of credentials for all workspaces - prod cannot get stronger protection than dev.
- Same code, forced - you cannot try a new module version in dev only; differences become
terraform.workspace == "prod" ? ... : ...everywhere. - A PR or a pipeline cannot show or gate "this touches prod".
Workspaces are fine for short-lived copies of one environment: a preview per branch, a load-test copy. And promotion becomes visible: bump the module ?ref= in dev, then test, then prod - three PRs.
Also asked: What are Terraform workspaces, and when would you use them? · How do you keep several environments from drifting apart? · What is the difference between a CLI workspace and an HCP Terraform workspace?
Learn it: 14.1 Environments: directory per environment vs workspaces
You are reviewing a platform module that creates a network, a managed identity, a container cluster and a Key Vault. What do you look for? Mid
- Hidden dependencies: the cluster references the identity, and the role assignment references the identity, but nothing links the cluster to the role assignment. Terraform may create them at the same time and the cluster fails without permission -
depends_on = [azurerm_role_assignment.aks_subnet]is the textbook fix. - Least privilege: role assignments scoped to the subnet or the one vault, not the resource group or subscription.
- Arguments that force replacement:
nameanddns_prefixmust never be built from anything that could change. - Sizing through validated inputs:
node_count,vm_size,sku_tier,zonesset per environment in tfvars, withvalidationblocks so a typo fails at plan. - Key Vault: globally unique name (hence a random suffix), purge protection in prod, no public network access, RBAC authorization.
- Outputs: IDs and names callers wire up; the cluster login file marked
sensitive- and remembered to still be in state. - Provider version: argument names match the pinned major version.
Also asked: What is a managed identity, and why use a user-assigned one? · What is least privilege, and how does it apply to role assignments? · Why does a subnet NSG association exist as its own resource?
Learn it: 14.2 The platform module: network, identity, cluster (AKS), Key Vault
What is the difference between terraform fmt, terraform validate and tflint? Junior
Three layers, cheapest first, none needs a cloud login:
terraform fmt -check -recursive- style only: the one canonical layout. Exits 3 if a file needs formatting; without-checkit fixes them. Never changes meaning.terraform validate- is this correct Terraform? Syntax, references, types and argument names against the provider schemas. Needsterraform init -backend=falsefirst. It does not read tfvars and does not know whether a VM size or SKU is real.tflint- a linter: valid but probably wrong. The built-in terraform ruleset finds unused variables, missing version constraints, modules pinned to a branch; the azurerm plugin knows allowed values, soStandard_D4sv5fails in a second instead of ten minutes into an apply. Configured in.tflint.hcl, plugins installed withtflint --init; exits 2 on issues.
Chain them in a script with set -euo pipefail, run it in CI on every PR and in a pre-commit hook.
Also asked: What can these static checks not catch? · What is a pre-commit hook, and why do you still need CI? · How would you introduce tflint on a repo with hundreds of warnings?
Learn it: 14.6 Code quality: fmt, validate, tflint
What is policy as code, and how would you use it with Terraform? Junior
Policy as code means security and organisation rules ("storage must not be public", "no SSH open to the internet") written as machine-checked rules that run on every change, instead of hoping a reviewer remembers them.
With Terraform, a scanner like checkov:
checkov -d .scans the code. Each result has a stable check ID (CKV_AZURE_59), a title that states the fix, the resource address and the file. Exit 1 on any failure stops the pipeline;--soft-failto introduce it gradually.- Fix findings in the configuration. A justified exception gets a skip with a reason and a ticket inside the resource:
#checkov:skip=CKV_AZURE_59:Static website, public by design (ARCH-212). - Scan the plan too:
terraform show -json tfplan > tfplan.json && checkov -f tfplan.json. A static scan only sees defaults and auto-loaded tfvars; the plan has the real values from-var-file.
Custom rules (an owner tag on everything) go in your own policies; Sentinel or OPA do the same in other tools.
Also asked: A checkov scan fails on a storage account. How do you handle it? · Why scan the plan as well as the code? · What can a security scanner not tell you about a change?
Learn it: 14.10 Security scanning: checkov on code and on plans
What does a good CI setup for Terraform look like? Mid
On every pull request: fmt -check, validate, tflint, checkov, and a plan per environment posted on the PR for reviewers.
On merge to main, per environment:
terraform plan -input=false -lock-timeout=10m -out=tfplan- the plan is saved as an artifact, with a text version for the approver and JSON for tools.- Gates on that exact plan: a checkov plan scan, and a jq policy gate that fails if
resource_changeswould delete anything stateful. - A human approval of that specific plan.
terraform apply tfplan- the file reviewed is the file applied. If state changed in between, it fails with Saved plan is stale: re-plan and re-approve, never switch to-auto-approve.
Around it: login with OIDC (no stored secret), separate identities for plan and apply and per environment, one run per state at a time, never cancel an apply halfway, short retention on plan artifacts (they contain secrets). The pipeline is the only path to prod.
Also asked: What does "plan as an artifact" mean? · How do you authenticate a Terraform pipeline without a stored secret? · The apply fails with "Saved plan is stale". What happened, and what do you do?
Learn it: 14.15 The pipeline: plan as an artifact, gates, approval, apply
How do you keep secrets out of Terraform? Mid
First know where they leak: committed tfvars (git history, forever), -var on a command line (CI logs), outputs without sensitive, state and saved plans (every value in plain text), TF_LOG=TRACE. sensitive = true only fixes the screen output.
Then design them away, strongest first:
- No secret at all - managed identities: the pipeline logs in with OIDC, the app reads storage or the database as its identity.
- Generated where they live -
random_passwordwritten straight into Key Vault withazurerm_key_vault_secret(with an expiry); no human sees it. - References, not values - the app setting holds a Key Vault reference to the secret's
versionless_id, and the app's identity gets Key Vault Secrets User on that vault only. Rotation then needs no Terraform change. - Protect what is unavoidable - state in a locked-down backend, short plan retention.
Rotate on exposure: terraform apply -replace=random_password.db. Newer Terraform adds ephemeral values and write-only arguments that never reach state.
Also asked: Where can secrets leak in a Terraform setup? · Does sensitive = true keep a value out of state? · What should you do when a password appears in a CI log?
How do you pin versions in Terraform, and how do you upgrade them safely? Junior
Three things get pinned, each in its own place:
- Terraform itself -
required_version = "~> 1.9.0"in the root, the same version in CI and on laptops (a version manager reading.terraform-version). State is forward-only: once a newer binary writes it, older ones cannot read it. - Providers -
required_providerswith~> 4.14in the root (a minimum like>= 4.0in modules), plus the committed.terraform.lock.hclwith the exact version and checksums. - Modules - an exact registry
versionor a git?ref=tag. Not in the lock file.
Upgrading: one PR. terraform init -upgrade, read the lock-file diff, read the changelog or upgrade guide for a major version, fix what terraform validate reports, then plan every environment - the target is No changes. Roll out dev first, prod last. Renovate or Dependabot can open these PRs; a human reads the plans.
Also asked: What does ~> 4.14 allow, and what does ~> 4.14.0 allow? · Someone applied with a newer Terraform from a laptop and now CI cannot read state. What do you do? · Why do modules state a minimum provider version instead of a tight pin?
Learn it: 14.23 Pinning and upgrading Terraform, providers and modules
What is HCP Terraform, and what does it add over running Terraform in your own pipeline? Junior
HCP Terraform (formerly Terraform Cloud) is HashiCorp's hosted service for running Terraform; Terraform Enterprise is the self-hosted version. It bundles what you would otherwise build from parts:
- Remote state, versioned and locked per workspace (one state plus its variables, permissions and run history - not a CLI workspace).
- Remote runs, started three ways: VCS-driven (a PR gets a speculative plan, a merge a real run), CLI-driven (the
cloudblock andterraform login;terraform planruns remotely and streams back), API-driven. - Variables and variable sets, sensitive ones write-only; a priority set overrides everything.
- Governance: Sentinel or OPA policies between plan and apply (advisory, soft-mandatory, hard-mandatory), run tasks for scanners.
- A private registry, drift detection and continuous validation.
The model is organisation, project, workspace. Mapping it onto your own pipeline (storage account, approvals, checkov, drift job) is the useful skill.
Also asked: What are the three HCP Terraform workflows? · What is the difference between an HCP workspace and a CLI workspace? · What are the Sentinel enforcement levels?
What are the benefits of Infrastructure as Code? Junior
Infrastructure described in text files in git, applied by a tool, gives you:
- Reproducible - the same code builds the same environment, again and again: dev, test and prod really match, and a lost environment can be rebuilt.
- Reviewable - a change is a diff and a plan someone reads before it happens, instead of clicks nobody sees.
- Versioned - history, blame and revert; you know who changed what and why.
- Automated - a pipeline applies it the same way every time, with checks (
fmt,validate,tflint,checkov) and approvals. - Self-documenting - the code is the up-to-date description of what exists.
Terraform adds being declarative and idempotent (describe the end state; applying twice changes nothing), one workflow across many providers, and state that maps code to real objects - which is also what you must protect.
Also asked: What happens when you run terraform apply while someone else is applying the same configuration? · Which command replaced terraform taint? · What does the dependency lock file record, and should it be committed?
Learn it: 14.29 The Terraform Associate (004) exam
Practise these answers with flashcards and labs Free, in your browser - a real Ubuntu terminal to try it in, with missions that check your work.