- What is Terraform?
- Core Concepts
- Terraform Workflow
- Terraform Workspaces
- Terraform Modules
- Real-World Use Cases
- Best Practices
- Terraform Tools
- Certification & Learning References
- More Terraform Content on TechBeatly
What is Terraform?
Terraform is an open-source Infrastructure as Code (IaC) tool by HashiCorp that lets you define, provision, and manage infrastructure across multiple cloud providers and on-premises platforms using a declarative configuration language (HCL). Instead of clicking through consoles or running manual scripts, you describe the desired end state and Terraform figures out the steps to get there.
Key properties:
- Declarative — describe what you want, not how to build it
- Idempotent — run
terraform applymultiple times safely; only differences are acted on - Provider ecosystem — AWS, Azure, GCP, VMware, Cloudflare, Kubernetes, and hundreds more
- State management — Terraform tracks real-world infrastructure in a state file so it can plan incremental changes
Core Concepts
| Concept | Description |
|---|---|
| Provider | Plugin that talks to an API (AWS, Azure, Cloudflare, VMware…) |
| Resource | A managed infrastructure object (aws_instance, cloudflare_record…) |
| Variable | Input value, defined in variables.tf, passed via .tfvars or environment |
| Output | Exported value from a root or child module (IPs, DNS names, inventory) |
| Module | Reusable bundle of resources with inputs and outputs |
| State | terraform.tfstate — the live record of what Terraform manages |
| Workspace | Isolated state namespace for multi-environment deployments from one codebase |
| Data Source | Read-only lookup of existing infrastructure not managed by Terraform |
| Local | Computed value (locals.tf) to avoid repetition in resource definitions |
Terraform Workflow
# 1. Initialise — download providers and modules
terraform init
# 2. Validate — check HCL syntax and module references
terraform validate
# 3. Plan — dry-run: shows what will be created/changed/destroyed
terraform plan -var-file=<workspace>.tfvars
# 4. Apply — make it real
terraform apply -var-file=<workspace>.tfvars
# 5. Destroy — tear everything down
terraform destroy -var-file=<workspace>.tfvars
Always run
terraform planbeforeapplyin shared or production environments.
Terraform Workspaces
Workspaces let you manage completely independent deployments (different AWS accounts, different environments) from a single Terraform codebase, with isolated state per workspace.
terraform workspace list # show all workspaces
terraform workspace new new-account # create a workspace for a second AWS account
terraform workspace select new-account # switch to it
terraform plan -var-file=new-account.tfvars
Convention used in practice:
| Workspace | Var File | AWS Account |
|---|---|---|
default | default.tfvars | Existing environment |
new-account | new-account.tfvars | New / separate AWS account |
Rules to follow:
- Always pass
-var-file=<workspace>.tfvars— never rely on auto-loadedterraform.tfvarsacross workspaces - Set
AWS_PROFILEto match the active workspace before running any command - Keep all
*.tfvarsfiles gitignored — they contain account-specific values and credentials
Terraform Modules
Modules package a set of resources so they can be reused across environments or projects. A typical split for an AWS project:
project/
├── main.tf ← root module: VPC, security groups, jumpserver, DNS
├── variables.tf
├── output.tf
├── aap/ ← child module: AAP EC2 nodes, EFS
│ ├── ec2-aap.tf
│ ├── efs.tf
│ ├── variables.tf
│ └── output.tf
└── aapaio/ ← child module: AAP All-in-One node
├── ec2-aapaio.tf
├── variables.tf
└── output.tf
The root module calls child modules, passing variables and receiving outputs:
module "aap" {
source = "./aap"
vpc_id = aws_vpc.main.id
subnet_ids = aws_subnet.private[*].id
instance_type = var.aap_instance_type
ssh_key_name = aws_key_pair.deployer.key_name
}
output "aap_private_ips" {
value = module.aap.instance_private_ips
}
Real-World Use Cases
Ansible Lab on AWS
Provision a complete Ansible lab (control node + managed nodes + VPC networking) with a single terraform apply. The output includes ready-to-use ansible.cfg and inventory so you can start running playbooks immediately.
What it creates:
- VPC with public subnet
- Ansible control node (Fedora) with Ansible pre-installed
- Configurable number of managed nodes (Amazon Linux / RHEL)
- Security groups allowing SSH between control and managed nodes
- Dynamic inventory via Terraform outputs
terraform init && terraform apply -auto-approve
terraform output # get IPs
ssh fedora@<ANSIBLE_ENGINE_IP>
ansible all -m ping
Full article: Use Terraform to Create a FREE Ansible Lab in AWS
AAP All-in-One on AWS
A single c5.4xlarge instance in a public subnet with an Elastic IP — ideal for dev/test deployments of Ansible Automation Platform without the overhead of a full HA cluster.
Feature flag in terraform.tfvars:
enable_aapaio = true
enable_aap = false
What it creates:
c5.4xlargeEC2 instance (RHEL 9)- Elastic IP (with optional Cloudflare DNS auto-update)
- Security group: SSH (22), AAP UI (443, 8443), HTTP (80)
- SSH key pair from local
~/.ssh/id_rsa.pub
AAP HA Cluster on AWS
A production-grade 9-node Ansible Automation Platform cluster across two availability zones, accessed through a secure bastion host.
Feature flag:
enable_aapaio = false
enable_aap = true
Node layout:
| Node | Role | Count |
|---|---|---|
aap-ac1, aap-ac2 | Automation Controller | 2 |
aap-gw1, aap-gw2 | Automation Gateway | 2 |
aap-hub1, aap-hub2 | Automation Hub | 2 |
aap-eda1, aap-eda2 | Event-Driven Ansible | 2 |
aap-db1 | PostgreSQL Database | 1 |
Infrastructure:
- VPC with public (jumpserver) and private (AAP nodes) subnets across 2 AZs
- NAT Gateway for outbound internet from private nodes
- EFS shared storage mounted on Hub nodes
- Nginx reverse proxy on jumpserver with Let’s Encrypt SSL (
aap.lab.gineesh.com) - Terraform output generates a complete AAP installer inventory
# Generate AAP installer inventory
terraform output -raw aap_inventory > inventory-hosts.txt
# SSH to jumpserver
ssh -i ~/.ssh/id_rsa ec2-user@<jumpserver-eip>
# SSH to AAP nodes via bastion proxy
ssh -i ~/.ssh/id_rsa \
-o ProxyCommand="ssh -W %h:%p -i ~/.ssh/id_rsa ec2-user@<jumpserver-eip>" \
ec2-user@<aap-private-ip>
SSL — Nginx + Let’s Encrypt (not AWS ACM/ALB):
terraform output -raw aap_inventory > inventory.ini
cd playbooks
ansible-playbook -i ../inventory.ini setup-nginx-lb.yml
Nginx terminates HTTPS, load-balances to port 8446 across the two Gateway nodes using least_conn, and handles WebSocket for the AAP UI.
Terraform + Ansible Integration
A common pattern: Terraform provisions the infrastructure, then Ansible configures it. Terraform outputs feed directly into Ansible inventory.
# output.tf — emit a ready-to-use AAP inventory
output "aap_inventory" {
value = templatefile("${path.module}/ansible-inventory-template.ini", {
jumpserver_ip = aws_eip.jumpserver.public_ip
controller_ips = [for i in module.aap.controller_ips : i]
gateway_ips = [for i in module.aap.gateway_ips : i]
hub_ips = [for i in module.aap.hub_ips : i]
eda_ips = [for i in module.aap.eda_ips : i]
db_ip = module.aap.db_ip
efs_dns_name = module.aap.efs_dns_name
})
}
# Handoff from Terraform to Ansible
terraform output -raw aap_inventory > inventory.ini
ansible-playbook -i inventory.ini site.yml
Cloudflare DNS Automation
Instead of manually updating DNS after every infrastructure recreation (Elastic IPs change on destroy), Terraform manages Cloudflare DNS records automatically.
# cloudflare-dns.tf
resource "cloudflare_record" "aap" {
zone_id = var.cloudflare_zone_id
name = "aap.lab"
value = aws_eip.jumpserver.public_ip
type = "A"
proxied = false # must be false for Let's Encrypt to work
}
Credentials via environment variables (not in code):
export TF_VAR_cloudflare_api_token=$(cat ~/.config/cloudflare)
export TF_VAR_cloudflare_zone_id="your-zone-id"
After every terraform apply, DNS auto-updates to the new EIP — no manual steps.
Note: The zone must be the root domain (
gineesh.com), not the subdomain (lab.gineesh.com).
VMware Automation
Terraform with the VMware vSphere provider automates VM creation, cloning, and import workflows on-premises — useful for AAP lab environments without public cloud spend.
Use cases covered:
- Create VMs from templates (
vmware-create-vm) - Import existing VMs into Terraform state (
vmware-import) - Consistent naming and resource tagging across vSphere clusters
OpenShift on VMware
Provision the underlying VMware infrastructure (VMs, networks, storage) needed to run an OpenShift cluster on vSphere, then hand off to the OpenShift installer.
Best Practices
State management
- Use remote state (S3 + DynamoDB for AWS, Terraform Cloud) for team environments
- Never commit
terraform.tfstateorterraform.tfstate.d/to git - One state file per workspace — never share state across environments
Variables and secrets
- All
*.tfvarsfiles gitignored — use.tfvars.exampleas a template - Sensitive values (
cloudflare_api_token, AWS credentials) via environment variables or a secrets manager — never hardcoded - Mark sensitive outputs:
sensitive = true
Modules
- Root module for shared infrastructure (VPC, security groups, DNS)
- Child modules for logical groups of resources (compute cluster, storage, networking)
- Use feature flags in tfvars (
enable_aap = true/false) rather than editing module source
Naming conventions
- Resource names should encode role and index:
aap-ac1,aap-gw2,aap-hub1 - Tags on every resource:
Name,Environment,ManagedBy = Terraform
Documentation
- Always output a human-readable summary (
terraform output) after apply - Use
terraform-docsto auto-generate module documentation from variable and output blocks
Terraform Tools
| Tool | Purpose |
|---|---|
| terragrunt | DRY wrapper for Terraform — manages multiple module calls, remote state config, and environment promotion |
| terratest | Go-based framework for writing automated tests for Terraform modules |
| terrascan | Static analysis for security and compliance issues in Terraform code |
| terratag | Automatically add or enforce tags across all Terraform resources |
| tfswitch | Switch quickly between multiple installed Terraform versions |
| tflint | Linter for catching Terraform errors and enforcing best practices |
| terraform-docs | Auto-generate documentation from Terraform module variables and outputs |
| Inframap | Visualise a tfstate or HCL as a provider-specific dependency graph |
| Terraform Visual | Browser-based visualiser for terraform plan output |
Certification & Learning References
Official HashiCorp Resources
- Get Started with Terraform
- Terraform Commands (CLI)
- Install Terraform
- HashiCorp Infrastructure Automation Certification
- Study Guide – Terraform Associate Certification
- Exam Review – Terraform Associate Certification
- Sample Questions – Terraform Associate Certification
- HashiCorp Workshops
Concepts
- What is Mutable vs. Immutable Infrastructure? (HashiCorp)
- What Is Immutable Infrastructure? (DigitalOcean)
Practice and Community
- 250 Practice Questions For Terraform Associate Certification
- Terraform Beginners Track (collabnix – GitHub)
- terraform-beginner-to-advanced-resource (GitHub)
- 100DaysOfIaC (Ryan Irujo – GitHub)
- Guidance on HashiCorp Certified — Terraform Associate (Medium)
Video Courses
- HashiCorp Certified: Terraform Associate – KodeKloud
- HashiCorp Certified: Terraform Associate – Zeal Vora (Udemy)
- Terraform for Absolute Beginners with Labs – KodeKloud (Udemy)
- HashiCorp Certified: Terraform Associate Practice Exam – Bryan Krausen
- Learn DevOps: Infrastructure Automation With Terraform – Edward Viaene
- Terraform on Azure with IaC DevOps SRE – Real-World 25 Demos
- Terraform Course – Automate your AWS cloud infrastructure (freeCodeCamp.org)
- Manage Your Entire VMware Infrastructure as Code with HashiCorp Terraform (YouTube)
- Using Ansible to automate app deployment on Terraform-provided infrastructure (IBM Cloud)
- Writing Ansible Playbooks for New Terraform Servers (VictorOps)
More Terraform Content on TechBeatly
For in-depth articles, tutorials, and cheat sheets visit the Terraform section on TechBeatly: