Declarative infrastructure, state, and the ways it goes wrong.
74 items · all topics
A team is replacing a set of shell scripts that call cloud provider CLIs. The scripts have to be read top to bottom to work out what infrastructure currently exists, and re-running one usually fails because a resource it tries to create is already there. Which characteristic of Terraform addresses both problems?
Scripts describe steps, Terraform describes an end state. That single difference is what removes the "work out what already exists" reading and the "fails on the second run" problem at the same time.
A colleague asks what a Terraform provider actually is, given that Terraform can manage AWS, GitHub and PagerDuty without knowing anything about them. What is the accurate answer?
A provider is a plugin that Terraform downloads and runs. It defines the resource and data source types for one platform and makes the API calls that create, read, update and destroy them.
An application stores objects in AWS, resolves DNS through Cloudflare, and routes alerts through PagerDuty. The team wants one workflow that provisions all three and understands the ordering between them, for example creating the DNS record only after the load balancer exists. Which statement best describes how Terraform supports this?
Terraform is service-agnostic because it speaks to every platform through a provider plugin, not because it hides the platforms behind a generic resource type. One configuration, many providers, one dependency graph.
A platform team is writing the case for moving provisioning out of the cloud console and into version-controlled Terraform configuration. Which TWO of the following are advantages of the infrastructure as code pattern itself, rather than claims about a particular cloud provider or tool?
The real advantages of IaC are the ones that come from infrastructure being a file: it can be reviewed like code, and it can be applied again to produce another identical environment.
An organisation already runs a configuration management tool that installs packages and manages files on long-lived virtual machines. They are introducing Terraform alongside it. Which division of responsibility matches the design intent of the two tools?
Terraform provisions and owns the lifecycle of the infrastructure. A configuration management tool configures what runs inside it. The exam checks that you do not reach for provisioners to blur the line.
Changing an EC2 instance's tags updates it in place, but changing its AMI produces a plan showing the instance destroyed and recreated. What decides which of the two happens?
The provider's schema marks which arguments force a new resource. Terraform updates in place where the API supports it, and plans a replacement where the argument cannot be changed on a live object.
A developer applies a configuration successfully. They then run terraform apply a second time, having made no edits to the configuration and no changes to the infrastructure outside Terraform. What does Terraform report, and why?
The second apply reports no changes, and the reason matters as much as the verdict. Terraform refreshes the real resources first, then compares them with the configuration, and only the gap becomes actions.
True or false: Terraform can only manage infrastructure that it created itself, so a resource built by hand in a cloud console can never be brought under Terraform management.
False. Importing is a supported part of the workflow, and it is how teams adopt Terraform for infrastructure that already exists rather than starting from an empty account.
Someone widens a security group rule in the cloud console. The Terraform configuration is unchanged. What is this called, and what does the next terraform plan show?
A change made outside Terraform is drift. The refresh at the start of a plan notices it, and the plan proposes changing the rule back to match the configuration.
A configuration has both a required_providers entry for aws and a provider "aws" block setting a region. A reviewer asks whether one of them is redundant. What does each one do?
required_providers declares which providers the module needs, with their source address and version constraint. A provider block configures one of them, with settings such as region.
A team needs the DigitalOcean provider, published in the public registry as digitalocean/digitalocean. They add resource blocks using the digitalocean_droplet type and a provider "digitalocean" block, but no required_providers entry. terraform init fails, reporting that it could not find the provider in the registry. What is the cause?
With no source address to go on, Terraform fills in the hashicorp namespace and looks for a provider that was never published there. Any provider outside that namespace has to name its source in required_providers.
An engineer runs terraform init in a second project on the same laptop and watches it download the same AWS provider again. They ask whether the first download was wasted. What is happening?
Providers are installed per working directory, under .terraform, so each project gets its own copy. A shared plugin cache directory can be configured to avoid re-downloading the same package.
A single root module has to create an S3 bucket in us-east-1 and a replica bucket in eu-west-1 during the same apply. How should the two AWS provider configurations be set up?
Two configurations of the same provider need an alias, and resources opt in to the non-default one with the provider meta-argument. Terraform never picks a provider by matching arguments on the resource.
A team notices a .terraform.lock.hcl file appear after their first terraform init and is deciding how to treat it. Which TWO statements about the dependency lock file are correct?
The lock file records which provider versions Terraform chose and the checksums it will verify later. It belongs in version control, and it covers providers only, never remote modules.
A module declares the AWS provider with version = "~> 4.16". Provider releases 4.16.0, 4.17.2, 4.40.0 and 5.0.0 are all available in the registry. Which version does terraform init select?
The pessimistic operator lets only the rightmost component in the constraint move. Written with two components, ~> 4.16 allows any 4.x at or above 4.16 and stops before 5.0.
A module sets required_version = ">= 1.5.0" in its terraform block and version = "~> 5.0" in required_providers for aws. Which does each constrain?
required_version constrains the version of the Terraform CLI itself. The version argument inside required_providers constrains the provider plugin, and the two are checked at different moments.
A developer clones a repository holding a Terraform configuration and immediately runs terraform plan. Terraform stops with an error saying the working directory has not been initialized. Which of the following does terraform init do that plan depends on?
Init is the setup step: it configures the backend, downloads the provider plugins and fetches the modules into the working directory. None of that is in the repository, which is why a fresh clone cannot plan.
A new engineer asks what the core Terraform workflow is, having only ever run terraform apply. Which sequence describes it, and what does the middle stage add?
The core workflow is write, plan, apply. Plan is the review stage: it shows exactly what would change before anything is changed, which is what makes an apply predictable.
A developer has already initialized a working directory and applied a configuration. They now add a new module block and a new provider to the configuration. A colleague warns that running terraform init again could wipe the existing state. What is the correct assessment?
Init is safe to run as often as you like. It brings the working directory up to date with the configuration and never deletes configuration or state, which is why it is the normal first step after adding a module or a provider.
A CI pipeline should reject a pull request that references an attribute that does not exist on a resource type, without contacting any cloud API and without needing credentials. Which command fits, and what does it require?
terraform validate catches configuration that is syntactically invalid or internally inconsistent, with no calls to remote services. It still needs an initialized directory, which init -backend=false can provide.
A plan prints a line reading -/+ resource "aws_db_instance" "main" and a comment saying forces replacement beside one argument. What is Terraform going to do?
The symbols are + create, - destroy, ~ update in place and -/+ destroy then recreate. A forces replacement comment names the argument that cannot be changed on the existing object.
A release process requires that the exact set of changes a reviewer approved is what gets applied, with no possibility of the configuration or infrastructure shifting between review and apply. Which approach meets this?
Save the plan to a file with terraform plan -out, then pass that file to terraform apply. Terraform applies the saved plan without prompting and without recomputing it.
A repository holds Terraform configuration in a root directory plus several subdirectories of modules. A pipeline step should fail when any file anywhere in the repository is not in canonical style, without rewriting files in CI. Which command does this?
terraform fmt only visits the directory you point it at, so subdirectories need -recursive. Pair it with -check so the step reports a non-zero exit status instead of editing files.
Which TWO of the following Terraform commands read the current status of the real resources and update the state accordingly, without any additional flags or arguments being supplied?
Refreshing is part of building a plan, so the two commands that build one are the two that refresh. The state inspection and output commands read the state file as it stands and never contact a provider.
An apply is failing on one broken resource and a colleague suggests routinely using -target to apply the rest. What does HashiCorp say about that flag, and why?
-target is documented for exceptional recovery situations, not routine use. It applies part of the graph, so the resulting state can be inconsistent with the configuration as a whole.
True or false: terraform destroy is the only way to destroy infrastructure that Terraform manages.
False. terraform destroy is a convenience alias for terraform apply -destroy, and removing a resource from the configuration and applying destroys it just as effectively.
A configuration repeats the expression "${var.project}-${var.env}" in eleven resource names. The team wants to write it once. Should that be a variable or a local value?
A local value names an expression for reuse inside one module and cannot be set from outside. An input variable is a value the caller supplies, so it cannot be computed from other variables.
A configuration needs the ID of a VPC that another team created and manages in a separate Terraform workspace. The VPC must not be modified or destroyed by this configuration under any circumstances. Which block type should be used to obtain the ID?
A data block reads an existing object without taking ownership of it. A resource block declares something this configuration creates and destroys, so using one here would put another team's VPC into your state.
A subnet resource needs the id of a VPC declared in the same configuration as aws_vpc.main. Which expression provides it, and what side effect does writing it have?
Write aws_vpc.main.id to read the attribute. The reference also creates an implicit dependency, so Terraform creates the VPC before the subnet without any depends_on.
A variable named instance_count has a default of 2 in its variable block. A terraform.tfvars file sets it to 4. The environment variable TF_VAR_instance_count is set to 6. The run is started with terraform apply -var="instance_count=8". Which value does Terraform use?
Command line flags win. The documented order runs from the variable default, through environment variables and tfvars files, to -var and -var-file, with the last of those taking precedence over everything before it.
An input variable for an environment name must only ever be dev, staging or prod, and a wrong value should fail immediately with a clear message. Which feature does this?
A validation block inside the variable declaration checks the value with a condition and reports error_message when it fails. It runs before planning, so a bad value never reaches a provider.
A configuration declares variable "vpc_cidrs" with type = map(string) and a default of { us-east-1 = "10.0.0.0/16", eu-west-1 = "10.1.0.0/16" }. Which expression returns the CIDR block for us-east-1?
Map values are read with bracket syntax and a key in quotes. Dot notation cannot carry a key containing hyphens, and the other forms address the variable rather than an element of it.
Three S3 buckets are created from a list variable using count and its index. A developer removes the first element from the list. The plan now shows the two surviving buckets being destroyed and recreated as well. Which change prevents this class of problem?
count addresses instances by position, so removing an element shifts every later index and Terraform sees a different resource at each address. for_each keys instances by a stable string instead.
An EC2 instance resource references an aws_security_group id in its arguments. A separate IAM policy resource must also exist before the instance is created, but nothing in the instance's arguments refers to it. How should the configuration express each ordering requirement?
A reference between resources creates the dependency automatically. depends_on exists for the ordering that is real but invisible, where no attribute of one resource appears in the other.
A database password is passed in as a variable marked sensitive = true and used to set an RDS instance's master password. A security reviewer asks where that password can be read after an apply. Which statement is accurate?
sensitive = true redacts CLI output. It does nothing to the state file, where the value is still stored in plain text, so the protection that matters is on the backend holding that state.
A team wants two guarantees. An apply must fail outright if an AMI passed into a module is not owned by an approved account. Separately, they want a health endpoint to be reported as a warning after every apply without ever blocking the run. Which custom conditions fit?
Preconditions and postconditions stop the operation when they fail. A check block reports a warning and lets the run continue, which is the only one of the three that is non-blocking by design.
A security group resource needs one ingress block per entry in a list of port and CIDR pairs, where the number of entries is not known until the variable is supplied. The ingress block is a nested block of the resource, not an argument. Which language feature produces them?
Repeating a nested block from a collection is what dynamic blocks are for. count and for_each repeat whole resources, and neither can produce several nested blocks inside one resource.
A team has copied the same twelve resource blocks into four environment directories. What does packaging them as a module change, and which files does the standard structure expect?
A module packages resources behind an interface of variables and outputs, so the four callers share one definition. The standard structure expects main.tf, variables.tf and outputs.tf.
A module block sources a module from a Git repository over SSH and also sets version = "~> 2.0". terraform init reports that the version argument is not valid for this source. Why, and how should the version be pinned instead?
The version argument works only for modules that come from a registry. Every other source pins itself through its own addressing, which for Git means a ref argument naming a tag.
A child module declares variable "instance_type" with no default. The caller's module block omits it. What happens, and how should the caller supply the value?
A variable with no default is required, so Terraform errors out naming the missing argument. The caller sets it as an argument inside the module block, alongside source.
A root module calls a child module that creates a VPC. The root module needs the VPC id to attach a subnet. The child module's aws_vpc resource exists and applies successfully, but referring to it from the root module produces an error. What is required?
A child module's resources are not visible to its caller. The child has to declare an output, and the caller reads it as module.NAME.OUTPUT.
One module creates a complete network stack. Three of them are needed, one per region, from a single configuration. Which approach avoids writing three near-identical module blocks?
count and for_each work on module blocks as well as resources. Using for_each over a map keyed by region gives one instance per key, addressed as module.network["eu-west-1"].
A working directory contains main.tf, variables.tf and outputs.tf, and main.tf includes two module blocks that point at directories under ./modules. Which statement correctly describes the module structure?
The working directory is itself a module, the root module. Every module it calls is a child module, and a directory only becomes a module by being called.
A root module declares a default aws provider and a second one with alias = "dr" for the recovery region. A child module needs to create resources in both regions. What does the child module receive by default, and what has to be done explicitly?
Default provider configurations are inherited by child modules automatically. Aliased ones never are, so the child declares a configuration alias and the caller passes it through the providers argument.
A developer adds a new module block pointing at ./modules/networking, a directory that already exists in the repository. Running terraform plan immediately afterwards fails with an error stating that the module is not installed. What should they do?
Adding a module always requires another terraform init, even for a local path. Terraform records module installation in the working directory, and plan will not do that work implicitly.
A state file has an obviously wrong attribute after a failed apply. An engineer proposes opening terraform.tfstate in an editor to correct it. Why is that discouraged, and what exists instead?
State is an internal format that Terraform expects to own, and hand edits bypass every check. The state subcommands, and terraform apply -refresh-only, are the supported ways to change it.
A new team member asks why Terraform keeps a state file at all, given that the configuration describes the desired infrastructure and the cloud provider's API can be queried for what exists. What is the primary reason?
State is the mapping between a resource address in your configuration and the real object it refers to. Without it Terraform could see the objects but would not know which of them is which.
One working directory needs separate state for dev and prod without copying the configuration. A colleague runs terraform workspace new dev. What does that actually give them, and what does it not?
A CLI workspace is an additional named state file for the same working directory and the same configuration. It separates state only, sharing the backend, the providers and the code.
Four engineers share a configuration whose state file is committed to the Git repository. They regularly hit merge conflicts in terraform.tfstate, and two of them once applied at the same time and corrupted it. Which TWO benefits does moving to a supported remote backend give them?
A remote backend gives one shared copy of state that everyone reads and writes, and on the backends that support it, locking that stops two applies colliding.
A networking configuration exports a VPC id as an output. An application configuration in a different state needs that id at plan time. Which mechanism reads it?
The terraform_remote_state data source reads another configuration's root module outputs from its backend. Only outputs are exposed, so the producing configuration has to declare one.
An apply is interrupted when a CI runner is terminated mid-run. Subsequent runs fail immediately, reporting that the state is locked and showing a lock ID. The team has confirmed no other operation is running. What is the correct action?
A lock left behind by a killed process is exactly what terraform force-unlock is for. It takes the lock ID from the error message, and it is safe only once you are certain nothing is still running.
A team configures the S3 backend for a new project and wants state locking without provisioning extra infrastructure to support it. Which approach matches the current guidance for the S3 backend?
The S3 backend can lock using a lock file held in the bucket itself, enabled with use_lockfile. The DynamoDB table that used to be required is deprecated and slated for removal.
An engineer changed an instance's tags directly in the cloud console. The team wants Terraform's state to accept those tags as the new reality, without changing any infrastructure and without editing the configuration to match. Which command does this, and what should they expect?
terraform apply -refresh-only shows the drift it found and asks before recording it in state. A normal apply would do the opposite and revert the console change.
A project has been using the default local backend and has real infrastructure recorded in terraform.tfstate. The team adds an S3 backend block. They run terraform init and want the existing state copied into the new backend. Which option does that?
Changing the backend makes Terraform ask whether to copy the existing state across. -migrate-state answers yes non-interactively, while -reconfigure is the opposite answer and abandons it.
True or false: every Terraform backend supports state locking, so choosing any remote backend is enough to prevent two people applying at the same time.
False. Locking is per backend, and the documentation for each one states whether it supports locking. Remote storage on its own does not make concurrent applies safe.
An engineer wants to read the whole current state in human-readable form, and later wants the same information as JSON for a script. Which command covers both?
terraform show prints the current state in readable form, and -json produces a machine-readable version. It also reads a saved plan file, which is how a reviewer inspects a plan.
A production database was created by hand two years ago and now has to be managed by Terraform. Nobody wants to write its resource block from scratch, and the change must be reviewable before anything is written to state. Which approach fits?
Write an import block naming the resource address and the real object's id, run plan with -generate-config-out to have Terraform write the resource block, then review and apply.
A CI job needs the load balancer DNS name that a configuration exposes as an output, to pass into a smoke test. Which command retrieves just that value in a script-friendly way?
terraform output NAME prints one output value, and -raw prints it without quotes for use in a shell. The values come from state, so no provider call is made.
During an incident, an engineer needs two things quickly: the addresses of every resource Terraform is managing, and then the full set of recorded attributes for one specific instance. Which commands give them this?
terraform state list prints the addresses, terraform state show prints one resource's recorded attributes. Both read state and neither changes anything.
An engineer is unsure whether a for expression over a map produces the shape they expect, and wants to try it against real state without running a plan. Which tool does that?
terraform console opens an interactive shell for evaluating expressions against the current configuration and state. It is read-only, so it changes nothing while you experiment.
A provider is failing with an unhelpful error and HashiCorp support has asked for detailed logs of the API calls, saved to a file. Which environment variables produce this?
TF_LOG sets the verbosity, with TRACE the most verbose level. TF_LOG_PATH appends the output to a file, and it does nothing unless TF_LOG is also set.
A module author renames a resource from aws_instance.app to aws_instance.web. Callers who upgrade should not see their running instance destroyed and recreated, and should not have to run any CLI commands by hand. What should the author add to the module?
A moved block records the rename in configuration. Terraform renames the object in state during planning, so callers get the rename automatically with no destroy and recreate.
A storage bucket currently managed by Terraform is being handed to another team who will manage it with their own tooling. Terraform must stop managing it, the bucket and its data must survive, and the change must be visible in a plan before it takes effect. What should be done?
Replace the resource block with a removed block whose nested lifecycle sets destroy = false. Terraform drops it from state on apply and leaves the real bucket alone.
A virtual machine has been left in a broken state by a failed in-guest configuration step. Terraform reports no changes, because every argument still matches the configuration. The engineer wants Terraform to destroy and recreate that one instance, and wants to see the plan before it happens. What is the current recommended approach?
terraform apply -replace with the resource address forces one object to be replaced, and the plan is shown first. It is the documented replacement for terraform taint.
True or false: terraform state rm deletes the real infrastructure object as well as removing its record from the state file.
False. state rm only forgets the object. The real resource keeps running, unmanaged, which is useful when handing it over and dangerous when done by mistake.
A team already runs Terraform from laptops with state in an S3 bucket. What does moving to HCP Terraform add that a remote backend alone does not?
A remote backend gives shared state and locking. HCP Terraform adds a place runs execute, with run history, stored variables, access control, policy enforcement and a private module registry.
A team uses terraform workspace new to keep dev and prod state separate in one working directory. They are moving to HCP Terraform and assume its workspaces are the same feature under a different name. Which statement corrects them?
CLI workspaces are alternate state files inside one working directory. HCP Terraform workspaces are the organising unit itself, holding configuration, state, variables, credentials and run history, and they carry access control.
An HCP Terraform workspace needs an AWS access key for the provider and a value for an input variable named instance_count. How are the two categorised?
HCP Terraform workspace variables come in two categories. Terraform variables set input variables in the configuration; environment variables are exported into the run environment for providers.
An organisation wants runs triggered and recorded centrally in HCP Terraform, with policy checks applied, but Terraform itself must execute inside their private network because the target systems have no public endpoints. Which workspace execution mode fits?
Agent mode runs Terraform on a lightweight agent the organisation hosts inside its own network, while HCP Terraform still orchestrates the run. Remote mode runs on HCP Terraform's own machines, which cannot reach private endpoints.
A run is queued in an HCP Terraform workspace with auto apply turned off. The plan finishes successfully. What is the state of the run, and what happens next?
The run pauses after a successful plan and waits for confirmation. Someone with apply permission confirms or discards it, and only a confirmed run proceeds to change infrastructure.
An organisation adds a policy in HCP Terraform requiring that every resource carries a cost-centre tag. Runs that violate it should be stopped, but a platform team member with the right permission needs to be able to let an exceptional run proceed. Which enforcement level fits, and when is the policy evaluated?
Soft-mandatory stops a run but allows an override by users with permission. Policies are checked against the plan, so they run after the plan and before the apply.
A workspace in HCP Terraform is connected to a Git repository. A developer opens a pull request changing the configuration. What does HCP Terraform do, and what has to happen for the change to be applied?
A pull request triggers a speculative plan, which reports what would change without being applyable. Merging to the tracked branch queues a real run that can then be applied.
A platform team maintains approved modules for networking and databases. Application teams should discover and consume them with version constraints, without being given access to the underlying Git repositories. Which HCP Terraform capability fits?
The private registry publishes an organisation's own modules with documented versions, so consumers use a registry source and a version constraint instead of a repository URL.
An organisation in HCP Terraform has grown to over a hundred workspaces. They want to grant one business unit's engineers access to all of their own workspaces at once, without adding each team to every workspace individually. Which capability does this?
Projects group workspaces so permissions can be granted to the collection rather than to each workspace. Variable sets solve the neighbouring problem of sharing values, not access.