Skip to content
Ravin Vasudev
Back to all articles

July 25, 2026 : 11 min read

Architecture Stack: Terraform & OpenTofu Fundamentals

Understanding Infrastructure as Code with Terraform: defining cloud infrastructure declaratively, managing state, and enabling reproducible deployments.

  • Architecture
  • Terraform

This is a conversation between Alex (Engineering Manager) and Jordan (Senior Architect) exploring Terraform and OpenTofu fundamentals.

Part 1: From Console Clicks to Code

Alex: "Jordan, we've built all this platform on AWS, Kubernetes, ArgoCD, Helm. But how do we actually create AWS resources? Do we log into AWS console and click buttons?"

Jordan: "God, no. That would be chaos. We define everything in code. Infrastructure as Code. Using Terraform."

Alex: "What's Terraform?"

Jordan: "Terraform is a tool that lets you define infrastructure declaratively. You write configuration files describing what resources you want. Terraform creates them on AWS (or any cloud). You can version control it, review changes, test it, deploy it."

Alex: "So it's like Helm but for infrastructure?"

Jordan: "Similar idea. Helm packages applications. Terraform defines infrastructure. Both are code-driven, version-controlled, and reproducible."

Alex: "What's the advantage?"

Jordan: "Huge advantages. Infrastructure is version-controlled like code. Changes are reviewed in pull requests. Rollbacks are instant (revert Git commit, reapply). Disaster recovery is automated (Terraform can recreate entire infrastructure from code). Documentation is the code itself."


Part 2: What Is Terraform?

Alex: "Define it."

Jordan: "Terraform is an Infrastructure as Code tool. You declare desired infrastructure state in HCL (HashiCorp Configuration Language, Terraform's DSL). Terraform compares desired state with actual cloud state. Creates, updates, or deletes resources to match desired state."

Alex: "Like Kubernetes?"

Jordan: "Exactly the same philosophy. Kubernetes reconciles container state. Terraform reconciles infrastructure state. Declare desired state, tool maintains it."

Alex: "What can you define?"

Jordan: "Anything in cloud infrastructure. AWS: VPCs, subnets, security groups, EC2 instances, RDS databases, S3 buckets, load balancers. Also works on other clouds (GCP, Azure). Also manages local infrastructure (VMware, on-premises)."

Alex: "One tool for everything?"

Jordan: "Essentially. Terraform understands hundreds of resource types across multiple clouds."


Part 3: HCL Syntax

Alex: "Show me what Terraform looks like."

Jordan: "Simple. Define resources in HCL:

resource \"aws_vpc\" \"main\" {
  cidr_block = \"10.0.0.0/16\"
  tags = {
    Name = \"main-vpc\"
  }
}

resource \"aws_subnet\" \"private\" {
  vpc_id = aws_vpc.main.id
  cidr_block = \"10.0.1.0/24\"
  tags = {
    Name = \"private-subnet\"
  }
}

resource \"aws_security_group\" \"app\" {
  vpc_id = aws_vpc.main.id

  ingress {
    from_port = 80
    to_port = 80
    protocol = \"tcp\"
    cidr_blocks = [\"0.0.0.0/0\"]
  }

  egress {
    from_port = 0
    to_port = 0
    protocol = \"-1\"
    cidr_blocks = [\"0.0.0.0/0\"]
  }
}

This creates VPC, subnet, and security group. Declarative, readable, version-controllable."

Alex: "How does Terraform know to use AWS?"

Jordan: "Provider configuration. At the top of the file:

terraform {
  required_providers {
    aws = {
      source = \"hashicorp/aws\"
      version = \"~> 5.0\"
    }
  }
}

provider \"aws\" {
  region = \"us-east-1\"
}

You specify which cloud, which region, which API credentials."


Part 4: Terraform Workflow

Alex: "How do you actually deploy?"

Jordan: "Three steps:

terraform init: Initialize Terraform. Download providers, set up backends.

terraform plan: Show what will change. Compares desired state (your HCL) with actual state (AWS). Shows additions, updates, deletions. Like a diff.

terraform apply: Make the changes. Create/update/delete resources to match desired state.

Additional commands:

terraform state: View current state. Debug issues.

terraform destroy: Delete all managed resources. Useful for cleanup.

terraform import: Import existing AWS resources into Terraform state (for resources created outside Terraform)."

Alex: "So you review the plan before applying?"

Jordan: "Always. terraform plan is your safety net. See exactly what will change before it happens. If wrong, fix HCL and re-plan."


Part 5: Terraform State

Alex: "What's 'state'?"

Jordan: "Terraform maintains a state file tracking actual infrastructure. When you create VPC with Terraform, it records 'I created vpc-12345'. Next time you plan, it checks AWS: does vpc-12345 still exist? If yes, no change. If deleted, Terraform will recreate it."

Alex: "Why is state needed?"

Jordan: "Because Terraform can't reliably query AWS to determine what was created by Terraform vs manually. State file is source of truth. It records what Terraform created."

Alex: "What's in the state file?"

Jordan: "Resource IDs, configuration, metadata. Example:

{
  \"resources\": [
    {
      \"type\": \"aws_vpc\",
      \"name\": \"main\",
      \"instances\": [
        {
          \"attributes\": {
            \"id\": \"vpc-12345\",
            \"cidr_block\": \"10.0.0.0/16\"
          }
        }
      ]
    }
  ]
}

Contains sensitive data (passwords, API keys), so it must be protected."

Alex: "Where's it stored?"

Jordan: "Local file by default (terraform.tfstate). But that's bad for teams (conflicts, no collaboration). Better: store in remote backend (S3, Terraform Cloud). Everyone uses same state, changes are atomic, encrypted."


Part 6: Remote State Backends

Alex: "How does remote state work?"

Jordan: "Configure backend in Terraform:

terraform {
  backend \"s3\" {
    bucket = \"my-terraform-state\"
    key = \"prod/terraform.tfstate\"
    region = \"us-east-1\"
    encrypt = true
    dynamodb_table = \"terraform-locks\"
  }
}

Terraform stores state in S3. DynamoDB table provides locking (prevents concurrent modifications)."

Alex: "So multiple people can use Terraform?"

Jordan: "Yes. Everyone runs same HCL, Terraform coordinates via remote state. If two people try to apply simultaneously, DynamoDB lock ensures only one wins."

Alex: "Safely?"

Jordan: "Safely. If someone leaves the apply halfway through, lock automatically releases."


Part 7: Problems Terraform Solves

Alex: "What real problems does this solve?"

Jordan: "Many:

Infrastructure Reproducibility: Disaster? Lost region? Re-run Terraform, identical infrastructure recreated in minutes.

Change Tracking: All changes in Git. Who changed what, when, why. Complete audit trail.

Environment Consistency: Dev, staging, prod use same Terraform code with different variables. Identical structure, different scale.

Preventing Manual Drift: Someone manually changes AWS console. Terraform plan shows it. Corrects it. Infrastructure stays in code.

Collaboration: Teams review and approve infrastructure changes via pull requests. Not one person's secret knowledge.

Cost Visibility: By versioning infrastructure, you see cost implications of changes before deploying.

Rollback Speed: Revert Git commit. Terraform reverts infrastructure. Seconds to minutes, not hours."

Alex: "This is all about control and visibility?"

Jordan: "Exactly. IaC gives you control (code) and visibility (Git history)."


Part 8: Why This Matters

Alex: "Operationally?"

Jordan: "Massively reduces operational burden. No more 'I don't know how this resource was created' or 'only Bob knows how to recreate this'. Everything is documented in code."

Alex: "Financially?"

Jordan: "Better visibility into infrastructure spending. Also prevents waste (resources created, forgotten, running indefinitely). Easier to clean up."

Alex: "Speed?"

Jordan: "Provision new infrastructure in minutes instead of days. New region? Re-run Terraform with different region variable. Done."


Part 9: Traditional Approach (Manual Infrastructure)

Alex: "What did people do before IaC?"

Jordan: "Log into AWS console. Click buttons to create resources. Document in spreadsheet (often forgot). Change something? Click more buttons. Delete something? Hope you remember what was depending on it."

Alex: "Seriously?"

Jordan: "Yes. I worked at companies like this. Infrastructure knowledge was in one person's head. That person leaves, panic."

Alex: "Scaling?"

Jordan: "Impossible at scale. Multiple environments became inconsistent. Updates took forever (manual across many regions). Rollbacks were nail-biters."

Alex: "So IaC is mandatory for modern infrastructure?"

Jordan: "Absolutely. Any serious company uses IaC."


Part 10: Terraform vs CloudFormation vs OpenTofu

Alex: "Are there alternatives?"

Jordan: "Yes. CloudFormation is AWS-native IaC (JSON/YAML). Works well if you're AWS-only. But less flexible than Terraform."

Alex: "How?"

Jordan: "CloudFormation is tightly integrated with AWS. Terraform is cloud-agnostic. Write once, deploy to AWS, GCP, Azure. Also Terraform is more popular, more community modules."

Alex: "What about OpenTofu?"

Jordan: "OpenTofu is Terraform fork (open-source). Created because Terraform changed its license (controversy). OpenTofu is free forever, no licensing concerns. Compatible with Terraform."

Alex: "Which do we use?"

Jordan: "Terraform. It's the standard. We monitor OpenTofu for drift, but Terraform is our primary."


Part 11: Variables & Environments

Alex: "How do you handle dev vs prod?"

Jordan: "Variables. Define in HCL:

variable \"environment\" {
  type = string
}

variable \"instance_count\" {
  type = number
  default = 1
}

variable \"instance_type\" {
  type = string
  default = \"t2.micro\"
}

resource \"aws_instance\" \"web\" {
  count = var.instance_count
  instance_type = var.instance_type
  tags = {
    Environment = var.environment
  }
}

Variables have default values, types, validation."

Alex: "Where do you set values?"

Jordan: "Terraform var files (tfvars):

# prod.tfvars
environment = \"prod\"
instance_count = 10
instance_type = \"t3.large\"

# dev.tfvars
environment = \"dev\"
instance_count = 1
instance_type = \"t2.micro\"

Then deploy: terraform apply -var-file=prod.tfvars (production) terraform apply -var-file=dev.tfvars (development)"

Alex: "Same code, different values?"

Jordan: "Exactly. DRY (Don't Repeat Yourself) infrastructure."


Part 12: Outputs & Dependencies

Alex: "How do services reference each other?"

Jordan: "Outputs. Export values from Terraform:

resource \"aws_rds_instance\" \"db\" {
  engine = \"postgres\"
  instance_class = \"db.t3.micro\"
}

output \"db_endpoint\" {
  value = aws_rds_instance.db.endpoint
}

Other Terraform code can reference this output. Or humans can look at terraform output to find the endpoint."

Alex: "Dependencies?"

Jordan: "Terraform tracks them automatically. If you reference a resource's attribute, Terraform knows the dependency. Creates resources in correct order."

resource \"aws_instance\" \"app\" {
  vpc_id = aws_vpc.main.id  # Dependency: VPC must exist first
}

resource \"aws_security_group\" \"sg\" {
  vpc_id = aws_vpc.main.id  # Same dependency
}

Terraform sees you need VPC first. Creates VPC, then instances and security groups."


Part 13: Modules for Reusability

Alex: "Can you package Terraform code?"

Jordan: "Yes. Modules. Reusable Terraform code. Example:

module \"vpc\" {
  source = \"./modules/vpc\"

  cidr_block = \"10.0.0.0/16\"
  region = \"us-east-1\"
}

module \"database\" {
  source = \"./modules/rds\"

  engine = \"postgres\"
  vpc_id = module.vpc.id
}

Modules encapsulate complexity. Use externally published modules (AWS ECS module, VPC module) or write custom modules."

Alex: "Who writes modules?"

Jordan: "Platform teams. Create reusable building blocks. Application teams use them. 'I need VPC, RDS, and ALB for my app?' Use our modules."


Part 14: Terraform Cloud/Enterprise

Alex: "What about enterprise features?"

Jordan: "Terraform Cloud (hosted) or Terraform Enterprise (self-hosted). Features:

Remote execution: terraform apply runs on Terraform Cloud, not your laptop. Consistent environment.

State management: Secure remote state storage.

Access control: Who can plan/apply to which workspaces.

Policy as Code: Sentinel policies enforce rules (can't create unencrypted databases, must tag resources, etc.).

VCS integration: Git webhooks trigger Terraform plans automatically.

Notifications: Slack alerts on plan/apply events."

Alex: "Is it necessary?"

Jordan: "For enterprise, yes. For small projects, local Terraform works. But at scale, Cloud/Enterprise adds governance and safety."


Part 15: Challenges & Best Practices

Alex: "What goes wrong?"

Jordan: "Several pitfalls:

State Conflicts: Multiple people apply simultaneously, state becomes inconsistent. Solution: always use remote backend with locking.

Manual Changes Forgotten: Someone changes AWS console, Terraform plan shows drift. Solution: discipline (never manually change resources) and automation (regular terraform plan checks).

State File Damage: Corruption or deletion is catastrophic. Solution: encryption, backup, DynamoDB locks.

Secrets in Code: Hardcode database passwords in HCL. If committed, everyone sees them. Solution: use Terraform variables with sensitive flag, external secret management.

Module Sprawl: Too many custom modules, inconsistent. Solution: governance, central module repository, code review.

Provider Drift: AWS changes API, Terraform provider doesn't update immediately. Solution: monitor releases, test upgrades.

Performance: Large Terraform states slow down plan/apply. Solution: split into multiple smaller projects (workspaces), use remote execution."

Alex: "These are all best practice issues?"

Jordan: "Yes. Terraform is powerful but requires discipline."


Part 16: Terraform Testing & Validation

Alex: "How do you test Terraform?"

Jordan: "Several approaches:

terraform validate: Check syntax and configuration consistency.

terraform plan: Show changes (dry-run).

Manual review: terraform plan output is reviewed in pull requests.

Automated testing: Tools like Terratest write Go tests for Terraform. Run test, Terraform provisions, test validates, cleanup.

Policy as Code: Sentinel policies prevent bad configurations before apply.

State validation: Verify actual infrastructure matches expected state."

Alex: "Catch errors before production?"

Jordan: "The goal. terraform plan is your safeguard. Never apply without reviewing plan first."


Part 17: Terraform Integration with ArgoCD

Alex: "How does this connect to what we discussed before?"

Jordan: "Terraform and Kubernetes are separate layers. Terraform provisions AWS infrastructure (VPCs, EKS cluster, RDS database). Then Kubernetes (and ArgoCD/Helm) run on that infrastructure."

Alex: "So Terraform creates the foundation?"

Jordan: "Exactly. Terraform creates: EKS cluster, VPC, load balancer, RDS database. ArgoCD deploys applications into that infrastructure."

Alex: "Can Terraform manage Kubernetes resources?"

Jordan: "Yes. Terraform can create Kubernetes resources via Kubernetes provider. But typically: Terraform creates cluster, ArgoCD manages cluster contents."


Part 18: Bridging to Landing Zones

Alex: "We've covered Terraform fundamentals. What's next in L3?"

Jordan: "Landing Zones. Multi-account AWS architecture. One VPC isn't enough for enterprise. You need multiple accounts (dev, staging, prod, security, shared services). Landing Zones define that structure and guardrails. Terraform implements Landing Zones at scale."

Alex: "So Landing Zones are the organization layer?"

Jordan: "Yes. Terraform is the tool. Landing Zones are the pattern (how to organize accounts and resources)."


Part 19: The Bottom Line

Alex: "If I pitch this?"

Jordan: "Terraform is Infrastructure as Code. Define all AWS resources in code instead of clicking console. Version control infrastructure like application code. Review changes in pull requests. Test infrastructure changes before deploying. Rollback infrastructure in seconds by reverting Git commits. Entire infrastructure is reproducible from code. Disaster recovery is automated. Compliance and auditing are built-in."

Alex: "And the commitment?"

Jordan: "We're saying: never manually create infrastructure again. Everything is code. Everything is reviewed. Everything is version-controlled. Infrastructure is as professional as application code."


Key Takeaways

| Aspect | Details | | ------------------- | ----------------------------------------------------------------------------------- | | Core Concept | Define infrastructure declaratively in code; Terraform maintains desired state | | Primary Benefit | Reproducibility, version control, change tracking, disaster recovery, collaboration | | Best For | Any infrastructure management, cloud-native, multi-environment deployments | | Main Challenge | State management, secrets handling, large state performance, manual drift | | Workflow | init (setup), plan (dry-run), apply (deploy), destroy (cleanup) | | Key Concepts | Resources, providers, variables, outputs, modules, state, backends | | Remote State | S3 backend with DynamoDB locking for team collaboration | | Environments | Use variables and tfvars files for dev/staging/prod consistency | | Enterprise | Terraform Cloud/Enterprise for governance, policy, remote execution |


L3 Series Progress

  1. Terraform & OpenTofu (infrastructure definition language) ← You are here
  2. Landing Zones (account structure and guardrails)
  3. Modules & Reusable Patterns (DRY infrastructure)

Ready for Landing Zones and multi-account AWS architecture?