- Chapter
- Chapter 1 — Infrastructure as Code
- Prerequisites
- Volume II; basic Git
- You will be able to
- Explain what IaC is and why it matters architecturally, apply IaC properties to real estates, compare IaC tools, design a safe IaC delivery workflow, decide what to codify first, adopt IaC for existing infrastructure, and measure IaC maturity
- Covers
- IaC fundamentals
On this page
- 1. Concept / Definition
- 2. Why It Exists
- 3. Core Concepts — IaC Fundamentals
- 4. How It Works Internally — The Change Pipeline
- 4A. Deep Dive — ShopNow IaC Estate
- 4B. Deep Dive — IaC Maturity Journey
- 4C. Deep Dive — What to Codify First
- 5. APIs / Features / Syntax
- 6. Practical Examples
- 7. Common Problems & Mistakes
- 8. Performance & Production Considerations
- 9. Architecture & Design Considerations
- 10. Interview Questions & Answers
1Concept / Definition
Infrastructure as Code (IaC) is the practice of defining infrastructure — networks, compute, databases, IAM, DNS, monitoring — in machine-readable files kept in version control and applied by automated tools, instead of configuring it manually through consoles or ad hoc scripts. The code becomes the source of truth for what infrastructure should exist.


| Vocabulary | Meaning |
|---|---|
| Idempotent | Applying the same code twice yields the same result |
| Plan | Preview of changes before applying |
| Drift | Reality differs from code |
| ClickOps | Manual console changes |
2Why It Exists
| ClickOps problem | IaC answer |
|---|---|
| Can't reproduce environments | Same code, new environment |
| No review of risky changes | PR + plan review |
| No audit trail | Git history |
| Slow, error-prone provisioning | Automated, consistent |
| Knowledge in people's heads | Documented as code |
3Core Concepts — IaC Fundamentals
| Property | Meaning | Practice |
|---|---|---|
| Repeatable | Same inputs → same infrastructure | Modules, variables |
| Idempotent | Safe to re-run | Declarative tools |
| Reviewable | Humans see changes before they happen | Plans in PRs |
| Auditable | Who changed what and why | Git + pipeline logs |
| Testable | Validate before prod | Lint, policy, test envs |
| Recoverable | Rebuild from code | DR drills |

4How It Works Internally — The Change Pipeline
| Stage | Detail |
|---|---|
| Author | Change HCL in a branch |
| CI: static checks | fmt, validate, tflint, Checkov/Trivy, OPA/Conftest |
| CI: plan | Against target environment with read-only role |
| Review | Plan output posted to PR; CODEOWNERS approve |
| Apply | Merge → pipeline applies saved plan with write role (OIDC) |
| Observe | Drift detection, cost reports |
4ADeep Dive — ShopNow IaC Estate
| Layer | Tool | Repos | Resources managed |
|---|---|---|---|
| Organisation & accounts | Terraform + Account Factory for Terraform (AFT) | org-infra | 42 accounts, SCPs, Identity Center |
| Networking | Terraform | network-infra | VPCs, TGW, endpoints, Route 53 |
| Platform (EKS) | Terraform + Helm via Argo CD | platform-infra | 6 clusters, Karpenter, add-ons |
| Data services | Terraform modules | domain repos | Aurora, DynamoDB, MSK, ElastiCache |
| Service infra | Composition module via Backstage | per service | Queues, buckets, roles |
| Total | — | ~40 repos | ~18,000 resources |
4BDeep Dive — IaC Maturity Journey
| Level | Characteristics | ShopNow timeline |
|---|---|---|
| 0 ClickOps | Console changes | Year 0 |
| 1 Scripts | CLI scripts, some CloudFormation | Year 1 |
| 2 IaC per team | Terraform from laptops, local state | Year 2 |
| 3 Pipeline IaC | Remote state, PR plans, CI applies | Year 3 |
| 4 Governed platform | Modules, policy as code, drift detection, self-service | Year 4 (now) |
4CDeep Dive — What to Codify First
| Priority | Resource type | Reason |
|---|---|---|
| 1 | IAM, SCPs, security baselines | Highest risk if wrong |
| 2 | Networking (VPC, TGW, DNS) | Foundational, hard to change |
| 3 | Data stores | Durability settings, encryption, backups |
| 4 | Compute platforms (EKS, ECS) | Rebuildability |
| 5 | Monitoring and alarms | Consistency |
| 6 | Application-level resources | Self-service via modules |
5APIs / Features / Syntax
# Minimal Terraform root: encrypted, versioned S3 bucket with standard tags
terraform {
required_version = ">= 1.9"
required_providers { aws = { source = "hashicorp/aws", version = "~> 5.80" } }
backend "s3" {
bucket = "shopnow-tfstate-prod"
key = "prod/aps1/media/terraform.tfstate"
region = "ap-south-1"
use_lockfile = true
encrypt = true
}
}
provider "aws" {
region = "ap-south-1"
default_tags {
tags = { env = "prod", owner = "catalog-team", managed-by = "terraform" }
}
}
resource "aws_s3_bucket" "media" { bucket = "shopnow-media-prod-aps1" }
resource "aws_s3_bucket_versioning" "media" {
bucket = aws_s3_bucket.media.id
versioning_configuration { status = "Enabled" }
}# GitHub Actions: plan on PR, apply on merge, OIDC credentials (no static keys)
jobs:
plan:
if: github.event_name == 'pull_request'
permissions: { id-token: write, contents: read, pull-requests: write }
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::111122223333:role/tf-plan-prod
aws-region: ap-south-1
- run: terraform init -input=false && terraform plan -out=tfplan -input=false
- run: terraform show -no-color tfplan > plan.txt # posted to PR by a later step# Local workflow for a change
terraform fmt -recursive && terraform validate
tflint --recursive && checkov -d .
terraform plan -out=tfplan && terraform show tfplan | less6Practical Examples
6.1 Rebuilding staging in 40 minutes
A misconfigured cleanup script deleted the staging VPC. Because staging was fully codified, the pipeline recreated network, EKS and data services in 40 minutes (data restored from snapshots).
6.2 Security group opened by hand
An engineer opened port 22 to 0.0.0.0/0 via the console "temporarily". Nightly drift detection flagged it; the pipeline reverted it and an SCP now blocks console writes in prod.
6.3 New region in two weeks
Adding ap-south-2 for DR reused network, EKS and data modules with new variables — two weeks instead of the quarter estimated for manual build.
6.4 Worked example — idempotency
Scenario. A ShopNow engineer was nervous about running terraform apply twice, worried it might create duplicate VPCs and databases.
| Run | Result |
|---|---|
| First apply | Creates 42 resources |
| Second apply (no changes) | "No changes. Your infrastructure matches the configuration." |
What it shows. Running the same configuration twice shows idempotency in practice. The first apply created 42 resources. The second, with no code changes, reported "No changes. Your infrastructure matches the configuration." Terraform compares the desired state in code with the real state and changes only the differences, so repeated runs are safe and the pipeline can apply on every merge. The engineer then added the apply step to the pipeline, which now runs safely on every merge to main and reports zero changes when nothing has changed.
Common mistake. Writing imperative scripts that create resources every time they run. Re-running them creates duplicates or fails halfway.
Takeaway. Rely on declarative, idempotent tools so infrastructure can be applied repeatedly and safely.
6.5 Worked example — tool choice
Scenario. Three ShopNow teams each wanted a different IaC tool, and the platform team needed a principled way to decide.
| Context | Choice |
|---|---|
| Multi-cloud + SaaS (GitHub, Datadog) | Terraform |
| AWS-only team loving TypeScript | CDK |
| Kubernetes-native control plane | Crossplane/ACK |
| OS configuration on legacy VMs | Ansible (or better: images) |
What it shows. The table matches tool to context. For multi-cloud and SaaS resources such as GitHub and Datadog, Terraform fits because of its broad provider ecosystem. An AWS-only team that prefers TypeScript may choose the AWS CDK. Kubernetes-native teams may prefer tools that run as controllers inside the cluster. The context, not personal taste, decides. ShopNow standardised on Terraform for shared infrastructure and allowed CDK only for one AWS-only team, with the decision recorded in an ADR and reviewed yearly.
Common mistake. Allowing every team to choose freely. The organisation then maintains several tools, pipelines and skill sets for the same job.
Takeaway. Choose IaC tools by scope, team skills and ecosystem, and standardise on as few as possible.
6.6 Worked example — what not to put in IaC
Scenario. ShopNow's Terraform repository had grown to include application deployments and secret values, and every plan took a long time and exposed sensitive data.
| Item | Better place |
|---|---|
| Application deployments (frequent) | GitOps (Argo CD) |
| Secret values | Secrets Manager (IaC creates the container, not the value) |
| Data in databases | Migrations |
What it shows. The table separates what belongs in IaC from what does not. Frequent application deployments are better handled by GitOps tools such as Argo CD. Secret values belong in Secrets Manager, with IaC creating only the secret container. Data belongs in databases and backups, not in code. After the split, plans for the infrastructure repository dropped from twelve minutes to two, and no secret values appeared in state files again.
Common mistake. Putting everything into one IaC repository. Plans become slow and risky, and secrets end up in state files.
Takeaway. Keep IaC for slow-changing infrastructure, and use dedicated tools for deployments, secrets and data.
6.7 Worked example — interview whiteboard
Scenario. In interviews, ShopNow asks, "Explain IaC and how you'd run it in an organisation."
| Prompt | Answer outline |
|---|---|
| "Explain IaC and how you'd run it in an organisation." | "Infrastructure defined declaratively in version-controlled code, applied by pipelines. Properties: repeatable, idempotent, reviewable, auditable, testable, recoverable. Workflow: branch → CI static checks and policy → plan with read-only role posted on PR → approval → apply saved plan with OIDC-assumed write role → drift detection. Remote encrypted, locked state; reusable versioned modules; consoles read-only in prod; codify IAM and networking first; import existing resources." |
Why it works. The outline defines IaC as infrastructure described declaratively in version control and applied by tools. It then explains the operating model: reusable modules owned by a platform team, plans reviewed in pull requests, applies only from pipelines with short-lived credentials, remote locked state, and drift detection. It ends with outcomes such as faster provisioning and auditable change. Mentioning metrics such as provisioning time and drift incidents shows the candidate thinks about outcomes as well as tooling.
Common mistake. Describing only the tool syntax. Interviewers want to hear how IaC is governed at scale.
Takeaway. Explain both the concept and the operating model around it.
6.8 Worked example — PayGrid IaC controls
Scenario. PayGrid's infrastructure for card data is regulated, so IaC changes needed extra controls to satisfy auditors.
| Control | Detail |
|---|---|
| Two-person review for CDE repos | Branch protection |
| Apply only from pipeline account | SCP denies other principals |
| Plans archived 7 years | Audit evidence |
What it shows. The table lists PayGrid's controls. Repositories for the cardholder-data environment require two-person review through branch protection. Applies run only from a dedicated pipeline account; a service control policy denies changes from anywhere else. Every change has an approval trail in Git and logs in the pipeline. In the next PCI audit, PayGrid produced change evidence in minutes by exporting pull-request approvals and pipeline logs.
Common mistake. Relying on manual approval emails for regulated changes. Evidence is scattered and easy to bypass.
Takeaway. Build regulatory controls into the IaC workflow itself, so compliance evidence is produced automatically.
6.9 Worked example — anti-patterns
Scenario. An audit of ShopNow's IaC practices found several habits that caused incidents and security risks.
| Anti-pattern | Effect |
|---|---|
| Applying from laptops | Unaudited, inconsistent |
| Local state files | Loss, conflicts |
| Static access keys in CI | Credential leaks |
| Copy-paste per environment | Drift |
What it shows. The table lists anti-patterns. Applying from laptops makes changes unaudited and inconsistent. Local state files get lost or conflict between engineers. Static access keys in CI can leak and are hard to rotate. Each has a standard fix: pipeline applies, remote locked state and OIDC federation. Within a quarter, all applies ran from pipelines, state moved to S3 with DynamoDB locking, and CI used OIDC roles instead of stored keys.
Common mistake. Treating these as minor habits. Each one has caused real outages or breaches in many organisations.
Takeaway. Eliminate laptop applies, local state and static keys as basic IaC hygiene.
6.10 Worked example — importing existing resources
Scenario. ShopNow had an S3 bucket created by hand years ago and wanted to manage it with Terraform without deleting and recreating it.
import {
to = aws_s3_bucket.legacy_reports
id = "shopnow-reports-legacy"
}
resource "aws_s3_bucket" "legacy_reports" { bucket = "shopnow-reports-legacy" }^Adopt without recreation
What it shows. An import block tells Terraform that an existing bucket, shopnow-reports-legacy, corresponds to the resource aws_s3_bucket.legacy_reports in code. The next plan adopts the bucket instead of creating a new one, and from then on it is managed like any other resource. The import produced a plan with no changes, confirming that the code matched the existing bucket exactly before anything else was modified.
Common mistake. Deleting and recreating existing resources to bring them under IaC. For stateful resources this risks data loss and downtime.
Takeaway. Use import blocks to bring existing resources under IaC safely, without recreating them.
6.11 Worked example — code generation for imports
Scenario. ShopNow had hundreds of hand-made resources to import, and writing configuration for each by hand would take weeks.
| Command | Effect |
|---|---|
| terraform plan -generate-config-out=generated.tf | Drafts HCL for import blocks |
What it shows. Running terraform plan with -generate-config-out drafts HCL configuration for every import block. Engineers then review and tidy the generated code instead of writing it from scratch, which makes large imports practical. ShopNow imported about 300 legacy resources in two weeks instead of the two months originally estimated.
Common mistake. Committing generated code without review. It often contains defaults and hard-coded values that should be cleaned up.
Takeaway. Use generated configuration to speed up imports, then refine it like any other code.
6.12 Worked example — reviewing a plan
Scenario. A Terraform change at ShopNow looked harmless in code but would have replaced a production database.
| Look for | Why |
|---|---|
| -/+ replacements on stateful resources | Data loss risk |
| Destroys | Unexpected removal |
| IAM policy changes | Privilege changes |
| Counts (e.g., 3 to add, 0 to destroy) | Sanity |
What it shows. Reviewers now check plans for specific risks. A "-/+" replacement on a stateful resource, such as a database, signals data-loss risk. Destroys signal unexpected removals. IAM policy changes affect security. Reviewing the plan, not just the code, shows what will really happen. The reviewer spotted the database replacement in the plan, and the change was rewritten to modify the instance in place instead.
Common mistake. Approving pull requests by reading the code diff alone. Small code changes can produce large, destructive plans.
Takeaway. Always review the plan output, with special attention to replacements, destroys and permission changes.
6.13 Worked example — tagging standards
Scenario. ShopNow's cost and security teams could not tell who owned many resources or what data they held.
| Tag | Purpose |
|---|---|
| env, owner, cost-center | Cost, ownership |
| managed-by=terraform | Detect unmanaged resources |
| data-class | Security controls |
What it shows. Tagging standards are enforced through IaC modules. Environment, owner and cost-centre tags support cost and ownership reporting. A managed-by=terraform tag helps detect resources created outside IaC. A data-class tag supports security controls based on data sensitivity. Untagged resources dropped to almost zero, and cost reports by team became accurate for the first time.
Common mistake. Defining tags in a policy document but not enforcing them in modules. Compliance quickly drops.
Takeaway. Encode tagging standards into shared modules so every resource is tagged consistently.
6.14 Worked example — pipeline roles
Scenario. ShopNow's CI pipeline used one powerful role for both planning and applying infrastructure changes.
| Role | Permissions |
|---|---|
| tf-plan-<env> | Read-only + state read |
| tf-apply-<env> | Write, assumed only from main branch workflow |
What it shows. Separating roles limits risk. tf-plan roles have read-only access plus state reading, so plans can run on every pull request safely. tf-apply roles can write, but can be assumed only from the main-branch workflow, so unreviewed code cannot change production. A later compromised dependency in a pull-request build could read infrastructure, but could not change anything.
Common mistake. Giving pull-request pipelines write access. A malicious or mistaken branch could then change production.
Takeaway. Use separate least-privilege roles for planning and applying, with apply restricted to reviewed code.
6.15 Worked example — cost visibility
Scenario. A ShopNow engineer increased instance sizes in a pull request without realising it would add lakhs to the monthly bill.
| Tool | Use |
|---|---|
| Infracost in PR | Cost delta of the change |
What it shows. Infracost runs in each pull request and comments with the cost difference of the change. Reviewers see, for example, that the change adds a certain amount per month, and can question it before merging. In its first month, Infracost comments led to two oversized changes being reduced before merge, saving several lakhs a month.
Common mistake. Discovering cost changes only on the next monthly bill, when the resources are already running.
Takeaway. Show cost impact in code review so cost becomes part of every infrastructure decision.
6.16 Worked example — documentation from code
Scenario. ShopNow's infrastructure documentation was always out of date, so new engineers relied on asking colleagues.
| Tool | Output |
|---|---|
| terraform-docs | Module READMEs |
| Architecture diagrams from state (e.g., Rover/InfraMap) | Visual inventory |
What it shows. Documentation is now generated from code. terraform-docs produces READMEs for each module, listing inputs and outputs. Tools that read Terraform state produce diagrams of deployed infrastructure. Because they are generated, they stay current. New engineers now find module inputs and a current diagram in each repository, and questions to the platform team dropped noticeably.
Common mistake. Writing infrastructure documentation by hand in wikis, where it drifts within weeks.
Takeaway. Generate infrastructure documentation from code and state to keep it accurate.
6.17 Worked example — DR drills with IaC
Scenario. ShopNow claimed it could rebuild its environment from code, but had never tried.
| Drill | Result |
|---|---|
| Build full stack in empty account | 3 h 20 m |
| Gaps found | 2 manual steps → codified |
What it shows. A drill built the full stack in an empty account. It took 3 hours 20 minutes and found two manual steps not in code, which were then codified. The drill proved recoverability and improved the code. The next drill, after the gaps were codified, rebuilt the stack in under three hours with no manual steps.
Common mistake. Assuming IaC guarantees recoverability without testing. Hidden manual steps only appear during a real rebuild.
Takeaway. Run regular rebuild drills from code to prove recoverability and find gaps.
6.18 Worked example — organisational model
Scenario. As ShopNow grew, it was unclear who owned which parts of the IaC code base.
| Team | Responsibility |
|---|---|
| Platform | Modules, pipelines, policies |
| Service teams | Service infra via modules |
| Security | Policies, reviews for sensitive changes |
What it shows. The organisational model divides responsibilities. The platform team owns modules, pipelines and policies. Service teams manage their own infrastructure using those modules. The security team owns policies and reviews. Each team knows its role. Service teams now ship infrastructure changes the same day, while platform and security keep consistent guardrails through modules and policies.
Common mistake. Centralising all infrastructure changes in one team. It becomes a bottleneck for every service team.
Takeaway. Give service teams ownership through well-designed modules, with platform and security setting guardrails.
6.19 Worked example — metrics
Scenario. ShopNow's leadership wanted to know whether IaC adoption was actually complete and effective.
| Metric | Target |
|---|---|
| Resources managed by IaC | > 98% |
| Console changes in prod | 0 |
| Mean time to provision environment | < 4 h |
What it shows. Metrics track progress: more than 98% of resources managed by IaC, zero console changes in production, and a mean time under four hours to provision a new environment. Trends show where adoption is lagging. The dashboard showed one team still making console changes, which led to targeted help rather than an organisation-wide mandate.
Common mistake. Measuring only the number of IaC repositories. It says nothing about coverage or effect.
Takeaway. Track IaC coverage and outcomes, such as provisioning time and console changes.
6.20 Worked example — OpenTofu
Scenario. After Terraform's licence change, ShopNow's legal team asked whether the company should switch to OpenTofu.
| Fact | Relevance |
|---|---|
| Open-source fork of Terraform (MPL) | Licensing choice |
| Largely compatible HCL | Migration feasible |
What it shows. The table summarises the facts. OpenTofu is an open-source fork of Terraform under the MPL licence, and its HCL is largely compatible, so migration is feasible. The decision depends on licensing policy, ecosystem support and features needed. ShopNow ran a two-week trial migrating one repository to OpenTofu, which confirmed compatibility, before deciding on its long-term tool.
Common mistake. Switching tools in a hurry without testing providers, modules and pipelines.
Takeaway. Evaluate tool changes such as OpenTofu on licensing and compatibility, and test before migrating.
6.21 Worked example — CDK comparison snippet
Scenario. A team using the AWS CDK wanted to compare its approach with Terraform's.
new s3.Bucket(this, 'Media', {
versioned: true,
encryption: s3.BucketEncryption.KMS_MANAGED,
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
});^Same intent, general-purpose language
What it shows. The TypeScript snippet creates an S3 bucket with versioning, KMS encryption and blocked public access in a few lines. CDK uses a general-purpose language with constructs that bundle best practices, then generates CloudFormation. Terraform uses declarative HCL. The team kept CDK for its AWS-only service but used Terraform elsewhere, so the comparison helped document when each fits.
Common mistake. Choosing a tool only because its syntax looks familiar. Ecosystem, multi-cloud needs and governance matter more.
Takeaway. Compare IaC tools on how they encode best practices and fit your organisation, not only on syntax.
6.22 Worked example — interview follow-ups
Scenario. In interviews, ShopNow asks follow-up questions to test whether a candidate has really used IaC.
| Follow-up | Answer |
|---|---|
| "Why not scripts?" | Scripts aren't idempotent or diffable; no plan |
| "Who can apply to prod?" | Only the pipeline, after approval |
Why it works. Typical follow-ups have crisp answers. Why not scripts? Scripts are not idempotent or diffable, and give no plan. Who can apply to production? Only the pipeline, after review. How do you handle drift? Detect it regularly and remediate through code. Candidates who answered these follow-ups concretely, with examples from their own work, consistently did better in the design exercise.
Common mistake. Answering follow-ups vaguely. Concrete practices show real experience.
Takeaway. Prepare concise, practical answers to common IaC follow-up questions.
6.23 Worked example — secrets in IaC
Scenario. A security scan found a database password inside ShopNow's Terraform state file.
| Practice | Why |
|---|---|
| Create secret containers, not values | Values stay out of state/Git |
| manage_master_user_password (RDS) | AWS manages password in Secrets Manager |
What it shows. Secret values should never pass through IaC. IaC creates secret containers, not their values. For RDS, manage_master_user_password lets AWS generate and store the password in Secrets Manager, so it never appears in code or state. After rotating the leaked password and switching to managed passwords, the next security scan found no secrets in any state file.
Common mistake. Passing secrets as Terraform variables. They end up in state, logs and sometimes Git history.
Takeaway. Keep secret values out of IaC and state; let managed services generate and store them.
6.24 Worked example — change size discipline
Scenario. Large IaC pull requests at ShopNow were hard to review, and mistakes slipped through.
| Guideline | Why |
|---|---|
| Small PRs, one concern | Readable plans |
| Separate refactors from behaviour changes | Safer reviews |
What it shows. Guidelines keep changes small: one concern per pull request, so plans stay readable, and refactors separated from behaviour changes, so reviewers can tell what really changes. Review times dropped, and the number of IaC changes rolled back after merge fell by more than half.
Common mistake. Combining module refactoring with real infrastructure changes. Destructive changes hide among cosmetic ones.
Takeaway. Keep IaC changes small and focused so plans are easy to review safely.
6.25 Worked example — incident: accidental destroy
Scenario. A ShopNow engineer renamed a Terraform resource, and the plan destroyed and recreated a database.
| Event | Prevention now |
|---|---|
| Renamed resource → plan destroyed and recreated DB | moved blocks, prevent_destroy on stateful resources, plan checks for destroys |
What it shows. Terraform treats a renamed resource as a new one unless told otherwise. Now, moved blocks record renames so Terraform updates its state instead of recreating resources, and prevent_destroy protects stateful resources from accidental deletion. Since the change, refactors are applied without recreating resources, and an attempt to delete a protected database fails safely at plan time.
Common mistake. Renaming resources without moved blocks, assuming Terraform will understand the intent.
Takeaway. Use moved blocks for refactors and prevent_destroy on stateful resources.
6.26 Worked example — checklist
Scenario. ShopNow reviews each team's IaC maturity with a checklist.
| Item | ✔ |
|---|---|
| All prod infra in code | ✔ |
| Pipeline-only applies with OIDC | ✔ |
| Remote locked state | ✔ |
| Plans reviewed in PRs | ✔ |
| Policy checks | ✔ |
| Drift detection | ✔ |
What it shows. The checklist confirms that all production infrastructure is in code, applies happen only from pipelines with OIDC, state is remote and locked, and plans are reviewed in pull requests. Gaps become improvement items with owners. Teams that ticked every item had far fewer infrastructure incidents than teams with gaps, which encouraged adoption.
Common mistake. Using the checklist as a one-off audit rather than a recurring review.
Takeaway. Review IaC practices regularly against a checklist to keep standards from slipping.
7Common Problems & Mistakes
| Mistake | Fix |
|---|---|
| Partial IaC (some ClickOps) | Import, read-only consoles |
| Unreviewed applies | PR plans |
| Secrets in code/state | External secrets |
| Monolithic state | Split by blast radius |
8Performance & Production Considerations
| Consideration | Practice |
|---|---|
| Plan time on large states | Split stacks |
| API rate limits | Parallelism tuning |
| Pipeline availability | Break-glass procedure |
9Architecture & Design Considerations
| Guideline | Detail |
|---|---|
| Code is the source of truth | Everywhere |
| Pipelines as the only writer | Governance |
| Modules for reuse | Consistency |
10Interview Questions & Answers
What is Infrastructure as Code?
Infrastructure as Code is the practice of defining and managing infrastructure, such as networks, servers, databases and permissions, through code stored in version control and applied by automated tools, rather than through manual console changes. Tools such as Terraform, OpenTofu, AWS CDK and CloudFormation read the desired state and create or change resources to match it. IaC makes infrastructure changes reviewable, repeatable and auditable, allows identical environments to be created, and enables recovery by rebuilding from code. It also lets infrastructure follow the same engineering practices as application code.
What does idempotent mean in IaC?
Idempotent means that applying the same configuration again produces no further changes once the infrastructure already matches it. The tool compares the desired state in code with the actual state and changes only the differences. Running terraform apply twice without code changes therefore reports "no changes". This makes it safe to apply repeatedly, for example on every merge in a pipeline, and to recover from interrupted runs. Imperative scripts lack this property, which is why they create duplicates or fail when run again.
Why review plans in pull requests?
A plan shows exactly what the tool will create, change, replace or destroy before anything happens. Reviewing it in a pull request lets teammates catch dangerous changes, such as replacing a production database or widening IAM permissions, that may not be obvious from the code diff. It also documents the intended change and its approval. Many teams post the plan output automatically as a pull-request comment, so review is part of the normal workflow and nothing is applied without being seen. Reviewers should pay special attention to replacements and permission changes.
How should CI authenticate to AWS?
CI should use OIDC federation: the CI system, such as GitHub Actions, issues a signed identity token for each job, and AWS exchanges it for short-lived credentials of a specific IAM role. Trust policies can restrict which repositories, branches or environments may assume each role. No long-lived access keys are stored in CI, so there is nothing to leak or rotate. Separate roles for planning and applying, with apply limited to the main branch, add further protection. This also gives a clear audit trail of which job assumed which role and when.
How do you adopt IaC for existing resources?
Use Terraform's import blocks to map existing resources to resource addresses in code, so Terraform adopts them instead of creating new ones. For many resources, terraform plan with -generate-config-out drafts the configuration automatically, which engineers then review and clean up. After import, run a plan to confirm there are no unexpected changes. Proceed incrementally, starting with low-risk resources, and protect stateful ones with prevent_destroy. Finally, restrict console changes so the imported resources stay managed by code. Import in small batches, so each plan stays reviewable and any surprise is easy to trace.
What belongs outside IaC?
Some things change too often or are too sensitive for infrastructure code. Frequent application deployments are better handled by CI/CD or GitOps tools such as Argo CD, which are designed for rapid releases. Secret values belong in a secrets manager; IaC should create only the secret container and access policies, so values never appear in code or state files. Data itself, such as database contents, belongs in data stores with backups, not in IaC. Keeping these out makes plans faster and safer. Clear boundaries keep each tool doing what it does best.
How do you prevent ClickOps drift?
Prevent drift by making manual changes difficult and detecting the rest. Give engineers read-only console access in production, with break-glass procedures for emergencies. Use service control policies to restrict who can change resources outside pipelines. Run scheduled drift detection, such as regular terraform plan runs, and alert on differences. Remediate drift through code, either by applying the code or by updating it to reflect an intentional change. Tags such as managed-by help find resources created outside IaC. Treat recurring drift as a signal that a process or permission needs to change.
How do you choose an IaC tool?
Choose by scope, skills and governance. If you manage multiple clouds or SaaS services, such as GitHub and Datadog, a tool with a broad provider ecosystem like Terraform or OpenTofu fits. If you are AWS-only and your team prefers general-purpose languages, AWS CDK may suit. Kubernetes-centric teams may prefer controllers such as Crossplane. Consider licensing, community, module availability, testing support and how well the tool supports policy and review. Standardise on as few tools as possible. Run a small pilot before committing, so the decision is based on experience rather than marketing.
What business value does IaC bring?
IaC brings faster provisioning, so new environments and features are ready in hours instead of weeks. Changes are safer because they are reviewed and planned before applying, which reduces incidents. Every change is auditable, which helps compliance. Environments are consistent, reducing "works in staging" problems. Infrastructure can be rebuilt from code after disasters or mistakes. And engineers spend less time on repetitive manual work. These benefits translate into faster delivery, lower risk and lower operational cost. Measuring provisioning time and change failure rate before and after adoption makes the value visible.
What would you codify first?
Codify the foundations that everything else depends on and that carry the most risk: IAM and security baselines, such as roles, permission boundaries, service control policies and logging, and networking, such as VPCs, subnets, routing and connectivity. These are shared by all workloads, so mistakes there have the widest impact, and they are hard to fix later. Once the foundation is in code, service-level infrastructure can be added through reusable modules, building on a secure and consistent base. Starting with these areas also builds the team's IaC skills on high-value work.