Test what you actually know about Infrastructure as Code. Free sample questions below, from easy to hard, with instant explanations.
Terraform needs some way to remember what it's already created and how that maps to your actual cloud resources, and that's exactly what the state file does. Without it, Terraform couldn't tell what's changed (drift) or compute an accurate plan for what to do next.
Copying module code into every repo means a bug fix has to be applied in a dozen places, and a plain relative path like ../local-module isn't something other teams can even reach. Publishing to a private registry or a version-tagged Git repo lets teams pull a specific, stable version of a shared module without duplicating any code.
Terraform's core idempotency guarantee is about its own resource lifecycle: reapplying the same configuration against infrastructure that already matches it produces no further changes, because Terraform compares desired state against actual state and only acts on differences. A local-exec provisioner is just an arbitrary shell command with no concept of desired versus actual state, so it reruns once per resource creation (or whenever its triggers change), but whether the script's own effect, like an INSERT statement, is safe to repeat is entirely up to whoever wrote it. null_resource is a normal, still-supported resource used specifically to attach provisioners without an underlying cloud object, and provisioners are treated as a last resort precisely because they sit outside Terraform's usual state-comparison model.
A module is a folder of configuration that groups related resources together, like a VPC module bundling subnets, route tables, and gateways, so that same bundle can be called repeatedly with different input variables instead of copy-pasting the same HCL for every environment or team. Encryption of state, locking concurrent runs, and rollback on failure are all real Terraform-adjacent concerns, but none of them are what a module is for. Modules exist purely for organizing and reusing configuration.
Terraform's state file is essentially a full JSON snapshot of every attribute of every managed resource, and that includes secrets like database passwords in plaintext, regardless of whether the source variable was marked sensitive. Marking a variable sensitive only suppresses it from being printed in CLI plan and apply output and logs, it does NOT remove or encrypt that value in state, which is why assuming otherwise is a common mistake. The real mitigation is treating the state file itself as a secret: an encrypted remote backend with strict access control, and never committing state to git.
Testing directly on production is exactly the risk you're trying to avoid. Molecule spins up disposable test instances (via Docker or Vagrant), runs your role against them, and checks the result, so you catch problems on a throwaway environment before the role ever touches a real server.
Declarative means you describe the outcome you want ('I want 3 servers running this image') and let the tool figure out how to get there, rather than writing out every individual step yourself like you would in an imperative script or by clicking through a console manually.
Modules like file, package, and service always check the current state of the system BEFORE making a change, so if something's already in the right state, they simply do nothing. That's what makes running a playbook twice as safe as running it once, versus a raw shell or command module that just blindly re-executes whatever you told it to.
terraform import is built exactly for this situation: it takes a resource address already declared in configuration plus an existing cloud resource's ID, and creates an entry for it in state so Terraform starts managing the real object instead of creating a competing duplicate. Deleting the working security group first is needlessly destructive and risks an outage if anything currently depends on it. terraform refresh only updates the recorded attributes of resources Terraform is already tracking in state, it can't adopt a resource with no state entry at all, and create_before_destroy is a lifecycle setting that governs replacement ordering, unrelated to adopting unmanaged resources.
AWS built CloudFormation to accept templates written in either JSON or YAML, it doesn't force you into just one. Most people end up preferring YAML since it supports comments and a shorter, more readable syntax for its special functions.
Real scenario-based DevOps questions, hands-on practice, and clear explanations for every answer.