Terraform Commands - Complete Cheatsheet
Master Terraform for Infrastructure as Code (IaC) - From basics to advanced enterprise usage
1. Initialization & Setup Commands
Command 1: Initialize Terraform working directory
terraform initCommand 2: Initialize with backend configuration
terraform init -backend-config="bucket=my-tf-state"Command 3: Initialize and upgrade provider versions
terraform init -upgradeCommand 4: Initialize without backend
terraform init -backend=falseCommand 5: Reconfigure backend
terraform init -reconfigureCommand 6: Migrate state to new backend
terraform init -migrate-stateCommand 7: Initialize with specific plugin directory
terraform init -plugin-dir=/path/to/plugins2. Planning Commands
Command 8: Create execution plan
terraform planCommand 9: Save plan to file
terraform plan -out=tfplanCommand 10: Plan with variable file
terraform plan -var-file="prod.tfvars"Command 11: Plan with inline variable
terraform plan -var="instance_type=t3.large"Command 12: Plan for specific resource
terraform plan -target=aws_instance.webCommand 13: Plan with detailed output
terraform plan -jsonCommand 14: Plan with refresh disabled
terraform plan -refresh=falseCommand 15: Plan and show resource addresses
terraform plan -no-color | grep "^[[:space:]]*[#~+-]"Command 16: Show saved plan
terraform show tfplanCommand 17: Show plan in JSON format
terraform show -json tfplan3. Apply & Deployment Commands
Command 18: Apply changes
terraform applyCommand 19: Apply without confirmation prompt
terraform apply -auto-approveCommand 20: Apply from saved plan
terraform apply tfplanCommand 21: Apply with variable file
terraform apply -var-file="prod.tfvars"Command 22: Apply specific resource only
terraform apply -target=aws_instance.webCommand 23: Apply with parallelism limit
terraform apply -parallelism=10Command 24: Apply and refresh state
terraform apply -refresh-only4. Destroy Commands
Command 25: Destroy all resources
terraform destroyCommand 26: Destroy without confirmation
terraform destroy -auto-approveCommand 27: Destroy specific resource
terraform destroy -target=aws_instance.webCommand 28: Destroy with variable file
terraform destroy -var-file="prod.tfvars"Command 29: Plan destroy (preview)
terraform plan -destroy5. State Management Commands
Command 30: List resources in state
terraform state listCommand 31: Show specific resource in state
terraform state show aws_instance.webCommand 32: Move resource in state
terraform state mv aws_instance.web aws_instance.web_serverCommand 33: Remove resource from state
terraform state rm aws_instance.webCommand 34: Pull remote state
terraform state pullCommand 35: Push local state to remote
terraform state push terraform.tfstateCommand 36: Replace provider in state
terraform state replace-provider hashicorp/aws registry.terraform.io/hashicorp/awsCommand 37: Backup state file
cp terraform.tfstate terraform.tfstate.backup6. State Refresh & Sync
Use refresh-only plan and apply flows instead of the deprecated terraform refresh command.
Command 38: Preview refresh-only changes
terraform plan -refresh-onlyCommand 39: Apply refresh-only changes with variable file
terraform apply -refresh-only -var-file="prod.tfvars"Command 40: Sync state without applying changes
terraform apply -refresh-only -auto-approve7. Output Commands
Command 41: Show all outputs
terraform outputCommand 42: Show specific output
terraform output instance_ipCommand 43: Show output in JSON
terraform output -jsonCommand 44: Show output raw value (no quotes)
terraform output -raw public_key8. Validation & Formatting
Command 45: Validate configuration
terraform validateCommand 46: Format configuration files
terraform fmtCommand 47: Format and show diff
terraform fmt -diffCommand 48: Format recursively
terraform fmt -recursiveCommand 49: Check formatting without changes
terraform fmt -check9. Workspace Commands
Command 50: List workspaces
terraform workspace listCommand 51: Create new workspace
terraform workspace new devCommand 52: Select workspace
terraform workspace select prodCommand 53: Show current workspace
terraform workspace showCommand 54: Delete workspace
terraform workspace delete dev10. Import Commands
Command 55: Import existing resource
terraform import aws_instance.web i-1234567890abcdef0Command 56: Import with variable file
terraform import -var-file="prod.tfvars" aws_instance.web i-1234567890abcdef0Command 57: Import to specific state file
terraform import -state=path/to/terraform.tfstate aws_instance.web i-1234567890abcdef011. Taint & Untaint Commands
Command 58: Taint resource (mark for recreation)
terraform taint aws_instance.webCommand 59: Untaint resource
terraform untaint aws_instance.webCommand 60: Taint resource in module
terraform taint module.vpc.aws_subnet.private12. Graph & Visualization
Command 61: Generate dependency graph
terraform graphCommand 62: Generate graph and create image
terraform graph | dot -Tpng > graph.pngCommand 63: Graph with plan operation
terraform graph -type=plan13. Provider Commands
Command 64: Show provider requirements
terraform providersCommand 65: Show provider schemas
terraform providers schemaCommand 66: Lock provider versions
terraform providers lockCommand 67: Mirror providers locally
terraform providers mirror /path/to/mirror14. Console & Testing
Command 68: Interactive console
terraform consoleCommand 69: Test expression in console
echo "var.instance_type" | terraform consoleCommand 70: Evaluate output expression
echo "aws_instance.web.public_ip" | terraform console15. Version & Help
Command 71: Show Terraform version
terraform versionCommand 72: Show detailed version info
terraform version -jsonCommand 73: Get help for command
terraform plan -helpCommand 74: List all commands
terraform -help16. Advanced State Operations
Command 75: Force unlock state
terraform force-unlock <lock-id>Command 76: Show state file version
terraform state pull | jq '.version'Command 77: List all resource addresses
terraform state list | sortCommand 78: Export state to JSON
terraform state pull > state.jsonCommand 79: Get specific attribute from state
terraform state show -json aws_instance.web | jq '.values.public_ip'17. Environment Variables
Command 80: Set log level
export TF_LOG=DEBUG
terraform applyCommand 81: Save logs to file
export TF_LOG_PATH=./terraform.log
export TF_LOG=TRACE
terraform applyCommand 82: Set variable via environment
export TF_VAR_instance_type=t3.large
terraform planCommand 83: Set credentials via environment
export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
terraform applyCommand 84: Disable color output
export TF_CLI_ARGS="-no-color"
terraform plan18. Testing & Validation (Terraform Test)
Command 85: Run Terraform tests
terraform testCommand 86: Run tests with specific filter
terraform test -filter=test_instanceCommand 87: Run tests with variable file
terraform test -var-file="test.tfvars"19. Configuration Management
Command 88: Get specific value from configuration
terraform console
> var.regionCommand 89: List all variables
grep -r "variable" *.tfCommand 90: Show required variables
terraform validate 2>&1 | grep "var."20. Remote Operations
Command 91: Force remote execution
terraform apply -lock=true -lock-timeout=5mCommand 92: Run with specific backend config
terraform plan -backend-config="key=prod/terraform.tfstate"21. Module Commands
Command 93: Get/update modules
terraform getCommand 94: Update modules to latest version
terraform get -updateCommand 95: Initialize and get modules
terraform init -get=true22. Login & Cloud Integration
Command 96: Login to Terraform Cloud
terraform loginCommand 97: Logout from Terraform Cloud
terraform logout23. Show & Inspect
Command 98: Show current state
terraform showCommand 99: Show in JSON format
terraform show -jsonCommand 100: Show specific resource
terraform state show aws_instance.web24. Replace & Recreate
Command 101: Replace resource
terraform apply -replace=aws_instance.webCommand 102: Replace multiple resources
terraform apply -replace=aws_instance.web -replace=aws_instance.db25. Metadata & Debugging
Command 103: Enable crash log
export TF_LOG_CORE=TRACE
export TF_LOG_PROVIDER=TRACE
terraform applyCommand 104: Validate JSON syntax
terraform providers schema -json | jq .Command 105: Check for circular dependencies
terraform graph | grep -i cycleAdvanced Terraform Concepts
State Locking
Command 106: Disable state locking
terraform apply -lock=falseCommand 107: Set lock timeout
terraform apply -lock-timeout=10mPartial Configuration
Command 108: Apply with partial backend config
terraform init \
-backend-config="bucket=my-bucket" \
-backend-config="key=terraform.tfstate" \
-backend-config="region=us-east-1"Parallelism Control
Command 109: Limit concurrent operations
terraform apply -parallelism=5Command 110: Disable parallelism
terraform apply -parallelism=1Interview Q&A Scenarios
Scenario 1: State file is corrupted or locked
# Check lock status
cat .terraform/terraform.tfstate
# Force unlock (use with caution!)
terraform force-unlock <lock-id>
# Pull state from remote
terraform state pull > backup.tfstate
# If corrupted, restore from backup
terraform state push backup.tfstate
# Re-initialize if needed
terraform init -reconfigureScenario 2: Need to import existing infrastructure
# Step 1: Write configuration for the resource
cat > main.tf <<EOF
resource "aws_instance" "web" {
# Configuration will be populated after import
lifecycle {
prevent_destroy = false
}
}
EOF
# Step 2: Import the resource
terraform import aws_instance.web i-1234567890abcdef0
# Step 3: Get current state
terraform state show aws_instance.web
# Step 4: Update configuration to match state
# Step 5: Plan to verify no changes
terraform planScenario 3: Move resources between modules
# Move resource from one module to another
terraform state mv module.old.aws_instance.web module.new.aws_instance.web
# Verify the move
terraform plan # Should show no changesScenario 4: Resource drift detected
# Detect drift
terraform plan -refresh-only
# Sync state with actual infrastructure
terraform apply -refresh-only
# Or fix the drift by reapplying
terraform applyScenario 5: Upgrade Terraform version
# Step 1: Backup state
terraform state pull > pre-upgrade-state.json
# Step 2: Upgrade Terraform binary
# (download new version)
# Step 3: Upgrade provider versions
terraform init -upgrade
# Step 4: Verify with plan
terraform plan
# Step 5: Test in non-prod first
terraform workspace select dev
terraform planScenario 6: Multiple environments (workspaces vs directories)
# Option 1: Workspaces
terraform workspace new prod
terraform workspace new staging
terraform workspace select prod
terraform apply -var-file=prod.tfvars
# Option 2: Directories (preferred for different backends)
cd environments/prod
terraform init -backend-config=backend-prod.hcl
terraform applyScenario 7: Sensitive data in state
# Mark outputs as sensitive
output "db_password" {
value = random_password.db.result
sensitive = true
}
# Enable encryption at rest for remote backend
terraform {
backend "s3" {
bucket = "my-tf-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
kms_key_id = "arn:aws:kms:us-east-1:123456789012:key/abcd1234"
dynamodb_table = "terraform-locks"
}
}
# Never commit state files to git
echo "*.tfstate" >> .gitignore
echo "*.tfstate.*" >> .gitignoreScenario 8: Stuck in a pending state
# Check for locks
terraform force-unlock <lock-id>
# If remote backend, check backend storage
# For S3:
aws s3 ls s3://my-tf-state-bucket/
# For Azure:
az storage blob list --account-name mystorageaccount --container-name tfstate
# Verify state file integrity
terraform state pull | jq .Terraform Best Practices
1. State Management Best Practices
Always use remote state for teams
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}Enable state locking
- S3 backend: Use DynamoDB table
- Azure: Built-in locking
- GCS: Built-in locking
Enable versioning on state bucket
aws s3api put-bucket-versioning \
--bucket my-terraform-state \
--versioning-configuration Status=EnabledNever commit state files
# .gitignore
*.tfstate
*.tfstate.*
.terraform/
*.tfvars # if contains secrets2. Code Organization Best Practices
Use modules for reusability
module "vpc" {
source = "./modules/vpc"
version = "1.0.0"
cidr_block = var.vpc_cidr
environment = var.environment
}Separate environments properly
terraform/
├── modules/
│ ├── vpc/
│ ├── eks/
│ └── rds/
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ │ └── terraform.tfvars
│ ├── staging/
│ └── prod/
└── global/
└── iam/Use consistent naming conventions
# Resource naming
resource "aws_instance" "web_server" { # snake_case
tags = {
Name = "web-server-${var.environment}" # kebab-case for AWS
Environment = var.environment
ManagedBy = "Terraform"
}
}3. Security Best Practices
1. Never hardcode credentials
# Bad
provider "aws" {
access_key = "AKIAIOSFODNN7EXAMPLE"
secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
}
# Good - use environment variables or IAM roles
provider "aws" {
region = var.aws_region
}2. Mark sensitive variables
variable "db_password" {
type = string
sensitive = true
}
output "db_password" {
value = var.db_password
sensitive = true
}3. Use data encryption
resource "aws_db_instance" "main" {
storage_encrypted = true
kms_key_id = aws_kms_key.db.arn
}4. Implement least privilege
resource "aws_iam_role_policy" "example" {
role = aws_iam_role.example.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = ["ec2:DescribeInstances"]
Resource = "*"
}
]
})
}5. Enable deletion protection
resource "aws_db_instance" "production" {
deletion_protection = true
lifecycle {
prevent_destroy = true
}
}4. Version Control Best Practices
Pin provider versions
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0" # Allow patch updates only
}
}
}Use version constraints wisely
# Pessimistic constraint (recommended)
version = "~> 1.0" # >= 1.0, < 2.0
# Exact version (most restrictive)
version = "1.2.3"
# Greater than
version = ">= 1.0"
# Range
version = ">= 1.0, < 2.0"5. Performance Best Practices
Use depends_on sparingly
# Terraform usually auto-detects dependencies
# Use depends_on only when needed
resource "aws_instance" "web" {
depends_on = [aws_security_group.web]
}Limit parallelism for API rate limits
terraform apply -parallelism=5Use count vs for_each appropriately
# for_each - better for managing individual resources
resource "aws_instance" "web" {
for_each = toset(["web-1", "web-2", "web-3"])
tags = {
Name = each.key
}
}
# count - simpler for identical resources
resource "aws_instance" "app" {
count = 3
tags = {
Name = "app-${count.index}"
}
}6. Testing Best Practices
Validate before applying
terraform validate
terraform fmt -check
terraform planUse terraform test (Terraform 1.6+)
# tests/main.tftest.hcl
run "verify_instance_type" {
assert {
condition = aws_instance.web.instance_type == "t3.micro"
error_message = "Instance type must be t3.micro"
}
}Implement pre-commit hooks
# .pre-commit-config.yaml
repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.83.0
hooks:
- id: terraform_fmt
- id: terraform_validate
- id: terraform_docs7. Documentation Best Practices
Document variables
variable "instance_type" {
description = "EC2 instance type for web servers"
type = string
default = "t3.micro"
validation {
condition = contains(["t3.micro", "t3.small", "t3.medium"], var.instance_type)
error_message = "Instance type must be t3.micro, t3.small, or t3.medium."
}
}Use meaningful outputs
output "web_server_public_ip" {
description = "Public IP address of the web server"
value = aws_instance.web.public_ip
}Add README with examples
# VPC Module
## Usage
```hcl
module "vpc" {
source = "./modules/vpc"
cidr_block = "10.0.0.0/16"
environment = "production"
}
### 8. CI/CD Best Practices
**Implement automated planning**
```yaml
# GitHub Actions example
- name: Terraform Plan
run: |
terraform init
terraform plan -out=tfplan
- name: Save Plan
uses: actions/upload-artifact@v4
with:
name: tfplan
path: tfplanRequire approvals for applies
- name: Terraform Apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: terraform apply -auto-approve tfplan
environment: productionUse Terraform Cloud/Enterprise for teams
- Remote state management
- Policy as code (Sentinel)
- Private module registry
- Cost estimation
- Audit logs
Common Pitfalls & Solutions
Pitfall 1: Not using remote state
Problem: Team members overwrite each other’s changes
Solution: Use remote backend with locking
terraform {
backend "s3" {
bucket = "terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}Pitfall 2: Hardcoding values
Problem: Configuration not reusable, copying errors
Solution: Use variables and tfvars files
# variables.tf
variable "instance_type" {
type = string
}
# prod.tfvars
instance_type = "t3.large"Pitfall 3: Not using modules
Problem: Code duplication, inconsistent configurations
Solution: Create reusable modules
module "vpc" {
source = "./modules/vpc"
cidr = var.vpc_cidr
}Pitfall 4: Ignoring state file security
Problem: Sensitive data exposed in state
Solution: Encrypt state, use sensitive variables
variable "db_password" {
sensitive = true
}Pitfall 5: Not pinning versions
Problem: Breaking changes from provider updates
Solution: Pin provider versions
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}Pitfall 6: Destroying production by mistake
Problem: Accidental terraform destroy
Solution: Use lifecycle prevent_destroy
resource "aws_db_instance" "prod" {
lifecycle {
prevent_destroy = true
}
}Pitfall 7: Not validating input
Problem: Invalid configurations deployed
Solution: Use variable validation
variable "environment" {
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}Pitfall 8: Monolithic configuration
Problem: Hard to manage, slow planning
Solution: Split into multiple state files
environments/
├── networking/
├── compute/
├── database/
└── security/Pitfall 9: Not using .gitignore
Problem: Committing sensitive state files
Solution: Proper .gitignore
*.tfstate
*.tfstate.*
.terraform/
.terraform.lock.hcl # optional
*.tfvars # if contains secretsPitfall 10: No testing before prod
Problem: Breaking changes in production
Solution: Use workspaces or separate directories
terraform workspace select staging
terraform plan
terraform apply
# Test thoroughly
terraform workspace select prod
terraform applyKey Differences (Interview Questions)
terraform plan vs terraform apply
| Feature | plan | apply |
|---|---|---|
| Purpose | Preview changes | Execute changes |
| State modification | No | Yes |
| Resource creation | No | Yes |
| Safe to run | Always | Only when ready |
| Output | Execution plan | Applied changes |
count vs for_each
| Feature | count | for_each |
|---|---|---|
| Input type | Number | Set or map |
| Addressing | Index (0, 1, 2) | Key/value |
| Resource removal | Risky (shifts indexes) | Safe (by key) |
| Best for | Identical resources | Named resources |
# count - index-based
resource "aws_instance" "app" {
count = 3
# Accessed as aws_instance.app[0]
}
# for_each - key-based (preferred)
resource "aws_instance" "web" {
for_each = toset(["web-1", "web-2"])
# Accessed as aws_instance.web["web-1"]
}Variables vs Locals
| Feature | Variables | Locals |
|---|---|---|
| Input | External (CLI, tfvars) | Internal calculation |
| Override | Yes | No |
| Usage | User-provided values | Computed values |
# Variable - user input
variable "environment" {
type = string
}
# Local - computed
locals {
common_tags = {
Environment = var.environment
ManagedBy = "Terraform"
}
}terraform import vs writing config
| Approach | Import | Write Config |
|---|---|---|
| Speed | Fast | Slower |
| Accuracy | Requires manual config | Intentional design |
| Use case | Existing infrastructure | New infrastructure |
Workspaces vs Directories
| Feature | Workspaces | Directories |
|---|---|---|
| Same backend | Yes | No |
| State isolation | Separate state | Completely separate |
| Code reuse | Yes | Via modules |
| Best for | Simple env differences | Complex environments |
# Workspaces - same backend, different state
terraform workspace new prod
terraform workspace new staging
# Directories - separate backends
cd environments/prod
terraform init -backend-config=backend-prod.hclModules vs Resources
| Feature | Modules | Resources |
|---|---|---|
| Purpose | Grouping & reuse | Individual components |
| Instances | Can create multiple | One per block |
| Versioning | Yes | N/A |
| Source | Local or registry | Provider |
Data Sources vs Resources
| Feature | Data Source | Resource |
|---|---|---|
| Purpose | Read existing | Create new |
| Modifies infra | No | Yes |
| Naming | data.type.name | resource.type.name |
# Data source - read existing
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"]
}
# Resource - create new
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
}terraform taint vs -replace
| Feature | taint (deprecated) | -replace |
|---|---|---|
| Terraform version | < 1.0 | >= 0.15.2 |
| Approach | Mark then apply | Apply with flag |
| Recommended | No | Yes |
# Old way (deprecated)
terraform taint aws_instance.web
terraform apply
# New way (preferred)
terraform apply -replace=aws_instance.webProduction-Ready Terraform Structure
terraform-infrastructure/
├── .gitignore
├── README.md
├── versions.tf # Terraform & provider versions
├── main.tf # Main configuration
├── variables.tf # Input variables
├── outputs.tf # Output values
├── locals.tf # Local values
├── data.tf # Data sources
├── terraform.tfvars # Default values (non-sensitive)
├── backend.tf # Backend configuration
│
├── modules/
│ ├── vpc/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ │ └── README.md
│ ├── eks/
│ ├── rds/
│ └── security-group/
│
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── terraform.tfvars
│ │ └── backend.hcl
│ ├── staging/
│ └── prod/
│ ├── main.tf
│ ├── variables.tf
│ ├── prod.tfvars
│ ├── backend.hcl
│ └── README.md
│
└── tests/
├── main.tftest.hcl
└── integration/Complete Example: Production VPC Module
modules/vpc/versions.tf
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}modules/vpc/variables.tf
variable "environment" {
description = "Environment name (dev, staging, prod)"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
variable "vpc_cidr" {
description = "CIDR block for VPC"
type = string
validation {
condition = can(cidrhost(var.vpc_cidr, 0))
error_message = "Must be a valid IPv4 CIDR block."
}
}
variable "availability_zones" {
description = "List of availability zones"
type = list(string)
default = ["us-east-1a", "us-east-1b", "us-east-1c"]
}
variable "private_subnet_cidrs" {
description = "CIDR blocks for private subnets"
type = list(string)
}
variable "public_subnet_cidrs" {
description = "CIDR blocks for public subnets"
type = list(string)
}
variable "enable_nat_gateway" {
description = "Enable NAT Gateway for private subnets"
type = bool
default = true
}
variable "single_nat_gateway" {
description = "Use single NAT Gateway for all private subnets"
type = bool
default = false
}
variable "tags" {
description = "Additional tags for resources"
type = map(string)
default = {}
}modules/vpc/main.tf
locals {
common_tags = merge(
var.tags,
{
Environment = var.environment
ManagedBy = "Terraform"
Module = "vpc"
}
)
}
# VPC
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = merge(
local.common_tags,
{
Name = "${var.environment}-vpc"
}
)
}
# Internet Gateway
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = merge(
local.common_tags,
{
Name = "${var.environment}-igw"
}
)
}
# Public Subnets
resource "aws_subnet" "public" {
count = length(var.public_subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnet_cidrs[count.index]
availability_zone = var.availability_zones[count.index]
map_public_ip_on_launch = true
tags = merge(
local.common_tags,
{
Name = "${var.environment}-public-subnet-${count.index + 1}"
Type = "public"
}
)
}
# Private Subnets
resource "aws_subnet" "private" {
count = length(var.private_subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = var.private_subnet_cidrs[count.index]
availability_zone = var.availability_zones[count.index]
tags = merge(
local.common_tags,
{
Name = "${var.environment}-private-subnet-${count.index + 1}"
Type = "private"
}
)
}
# Elastic IPs for NAT Gateways
resource "aws_eip" "nat" {
count = var.enable_nat_gateway ? (var.single_nat_gateway ? 1 : length(var.private_subnet_cidrs)) : 0
domain = "vpc"
tags = merge(
local.common_tags,
{
Name = "${var.environment}-nat-eip-${count.index + 1}"
}
)
depends_on = [aws_internet_gateway.main]
}
# NAT Gateways
resource "aws_nat_gateway" "main" {
count = var.enable_nat_gateway ? (var.single_nat_gateway ? 1 : length(var.private_subnet_cidrs)) : 0
allocation_id = aws_eip.nat[count.index].id
subnet_id = aws_subnet.public[count.index].id
tags = merge(
local.common_tags,
{
Name = "${var.environment}-nat-${count.index + 1}"
}
)
depends_on = [aws_internet_gateway.main]
}
# Public Route Table
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
tags = merge(
local.common_tags,
{
Name = "${var.environment}-public-rt"
Type = "public"
}
)
}
# Public Route
resource "aws_route" "public_internet_gateway" {
route_table_id = aws_route_table.public.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
# Public Route Table Associations
resource "aws_route_table_association" "public" {
count = length(var.public_subnet_cidrs)
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
# Private Route Tables
resource "aws_route_table" "private" {
count = var.enable_nat_gateway ? (var.single_nat_gateway ? 1 : length(var.private_subnet_cidrs)) : length(var.private_subnet_cidrs)
vpc_id = aws_vpc.main.id
tags = merge(
local.common_tags,
{
Name = "${var.environment}-private-rt-${count.index + 1}"
Type = "private"
}
)
}
# Private Routes to NAT Gateway
resource "aws_route" "private_nat_gateway" {
count = var.enable_nat_gateway ? (var.single_nat_gateway ? 1 : length(var.private_subnet_cidrs)) : 0
route_table_id = aws_route_table.private[count.index].id
destination_cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.main[count.index].id
}
# Private Route Table Associations
resource "aws_route_table_association" "private" {
count = length(var.private_subnet_cidrs)
subnet_id = aws_subnet.private[count.index].id
route_table_id = var.single_nat_gateway ? aws_route_table.private[0].id : aws_route_table.private[count.index].id
}
# VPC Flow Logs
resource "aws_flow_log" "main" {
iam_role_arn = aws_iam_role.flow_log.arn
log_destination = aws_cloudwatch_log_group.flow_log.arn
traffic_type = "ALL"
vpc_id = aws_vpc.main.id
tags = merge(
local.common_tags,
{
Name = "${var.environment}-vpc-flow-log"
}
)
}
resource "aws_cloudwatch_log_group" "flow_log" {
name = "/aws/vpc/${var.environment}"
retention_in_days = 30
tags = local.common_tags
}
resource "aws_iam_role" "flow_log" {
name = "${var.environment}-vpc-flow-log-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "vpc-flow-logs.amazonaws.com"
}
}
]
})
tags = local.common_tags
}
resource "aws_iam_role_policy" "flow_log" {
name = "${var.environment}-vpc-flow-log-policy"
role = aws_iam_role.flow_log.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams"
]
Effect = "Allow"
Resource = "*"
}
]
})
}modules/vpc/outputs.tf
output "vpc_id" {
description = "ID of the VPC"
value = aws_vpc.main.id
}
output "vpc_cidr" {
description = "CIDR block of the VPC"
value = aws_vpc.main.cidr_block
}
output "public_subnet_ids" {
description = "IDs of public subnets"
value = aws_subnet.public[*].id
}
output "private_subnet_ids" {
description = "IDs of private subnets"
value = aws_subnet.private[*].id
}
output "nat_gateway_ids" {
description = "IDs of NAT Gateways"
value = aws_nat_gateway.main[*].id
}
output "internet_gateway_id" {
description = "ID of Internet Gateway"
value = aws_internet_gateway.main.id
}environments/prod/main.tf
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {} # Configuration in backend.hcl
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = "production"
Project = "my-project"
ManagedBy = "Terraform"
CostCenter = "engineering"
}
}
}
module "vpc" {
source = "../../modules/vpc"
environment = var.environment
vpc_cidr = var.vpc_cidr
availability_zones = var.availability_zones
public_subnet_cidrs = var.public_subnet_cidrs
private_subnet_cidrs = var.private_subnet_cidrs
enable_nat_gateway = true
single_nat_gateway = false
tags = var.additional_tags
}environments/prod/backend.hcl
bucket = "my-terraform-state-prod"
key = "prod/vpc/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-state-lock-prod"
kms_key_id = "arn:aws:kms:us-east-1:123456789012:key/abc-def-ghi"environments/prod/prod.tfvars
aws_region = "us-east-1"
environment = "prod"
vpc_cidr = "10.0.0.0/16"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
public_subnet_cidrs = [
"10.0.1.0/24",
"10.0.2.0/24",
"10.0.3.0/24"
]
private_subnet_cidrs = [
"10.0.11.0/24",
"10.0.12.0/24",
"10.0.13.0/24"
]
additional_tags = {
Owner = "platform-team"
CostCenter = "engineering"
Compliance = "pci"
}.gitignore
# Local .terraform directories
**/.terraform/*
# .tfstate files
*.tfstate
*.tfstate.*
# Crash log files
crash.log
crash.*.log
# Exclude all .tfvars files (if they contain secrets)
*.tfvars
*.tfvars.json
# Ignore override files
override.tf
override.tf.json
*_override.tf
*_override.tf.json
# Include example tfvars
!example.tfvars
# Ignore CLI configuration files
.terraformrc
terraform.rc
# Ignore plan files
*.tfplan
# Ignore lock files (optional)
.terraform.lock.hclAdvanced Terraform Patterns
1. Dynamic Blocks
resource "aws_security_group" "web" {
name = "web-sg"
vpc_id = var.vpc_id
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.port
to_port = ingress.value.port
protocol = "tcp"
cidr_blocks = ingress.value.cidr_blocks
}
}
}2. Conditional Resources
resource "aws_instance" "web" {
count = var.create_instance ? 1 : 0
ami = var.ami_id
instance_type = var.instance_type
}3. Data Lookups
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}
}4. Remote State Data Sources
data "terraform_remote_state" "vpc" {
backend = "s3"
config = {
bucket = "my-terraform-state"
key = "vpc/terraform.tfstate"
region = "us-east-1"
}
}
resource "aws_instance" "app" {
subnet_id = data.terraform_remote_state.vpc.outputs.private_subnet_ids[0]
}5. Provider Aliases
provider "aws" {
alias = "us_east_1"
region = "us-east-1"
}
provider "aws" {
alias = "us_west_2"
region = "us-west-2"
}
resource "aws_instance" "east" {
provider = aws.us_east_1
}
resource "aws_instance" "west" {
provider = aws.us_west_2
}26. Drift Detection & Management
Command 111: Detect configuration drift
terraform plan -refresh-onlyCommand 112: Show drift in detail
terraform plan -refresh-only -out=drift.tfplan
terraform show drift.tfplanCommand 113: Apply refresh to sync state
terraform apply -refresh-only -auto-approveCommand 114: Compare state with actual resources
terraform state pull | jq '.resources[] | {type: .type, name: .name}'27. Multi-Cloud Commands
Command 115: Set multiple provider credentials
# AWS
export AWS_PROFILE=production
export AWS_DEFAULT_REGION=us-east-1
# Azure
export ARM_SUBSCRIPTION_ID="xxx"
export ARM_TENANT_ID="xxx"
export ARM_CLIENT_ID="xxx"
export ARM_CLIENT_SECRET="xxx"
# GCP
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/key.json"
export GOOGLE_PROJECT="my-project-id"
terraform planCommand 116: Initialize with multiple providers
terraform initCommand 117: Plan multi-cloud deployment
terraform plan -out=multi-cloud.tfplan28. Import Block (Terraform 1.5+)
Command 118: Import with import block
# main.tf
import {
to = aws_instance.web
id = "i-1234567890abcdef0"
}
resource "aws_instance" "web" {
# Configuration
}terraform plan -generate-config-out=generated.tf
terraform applyCommand 119: Import multiple resources
import {
to = aws_instance.web1
id = "i-111111111"
}
import {
to = aws_instance.web2
id = "i-222222222"
}Command 120: Generate config from import
terraform plan -generate-config-out=imported.tf29. Check Blocks (Terraform 1.5+)
Command 121: Add runtime assertions
check "health_check" {
data "http" "example" {
url = "https://${aws_instance.web.public_ip}"
}
assert {
condition = data.http.example.status_code == 200
error_message = "Website is not responding"
}
}Command 122: Validate with check blocks
terraform plan # Runs checks
terraform apply # Runs checks again30. Moved Blocks (Refactoring)
Command 123: Rename resource without recreation
moved {
from = aws_instance.web
to = aws_instance.web_server
}Command 124: Move to module
moved {
from = aws_instance.web
to = module.web.aws_instance.main
}Command 125: Verify moved block
terraform plan # Should show no changes31. Removed Blocks (Terraform 1.7+)
Command 126: Remove from state without destroying
removed {
from = aws_instance.old_server
lifecycle {
destroy = false
}
}Command 127: Remove and destroy
removed {
from = aws_instance.temporary
lifecycle {
destroy = true
}
}32. Advanced Debugging
Command 128: Enable detailed logging
export TF_LOG=TRACE
export TF_LOG_CORE=DEBUG
export TF_LOG_PROVIDER=TRACE
export TF_LOG_PATH=./terraform-debug.log
terraform applyCommand 129: Debug specific operation
TF_LOG=DEBUG terraform plan 2>&1 | tee plan-debug.logCommand 130: Trace provider API calls
export TF_LOG_PROVIDER=TRACE
terraform apply -auto-approveCommand 131: Debug state locking issues
export TF_LOG=DEBUG
terraform apply 2>&1 | grep -i "lock"Command 132: Inspect provider plugin cache
ls -la ~/.terraform.d/plugin-cache/
terraform providers33. Performance Optimization
Command 133: Reduce parallelism for rate limiting
terraform apply -parallelism=3Command 134: Optimize for large states
terraform plan -target=module.specific_moduleCommand 135: Skip provider validation
terraform init -backend=false -get=false -verify-plugins=falseCommand 136: Use compact warnings
terraform apply -compact-warnings34. State Backup & Recovery
Command 137: Create state backup
terraform state pull > "backup-$(date +%Y%m%d-%H%M%S).tfstate"Command 138: Restore from backup
terraform state push backup-20240101-120000.tfstateCommand 139: Compare state files
diff <(terraform state pull | jq -S .) <(cat backup.tfstate | jq -S .)Command 140: Export state for migration
terraform state pull | jq '.resources' > resources.json35. Credential & Secret Management
Command 141: Use AWS SSM Parameter Store
data "aws_ssm_parameter" "db_password" {
name = "/prod/db/password"
with_decryption = true
}
resource "aws_db_instance" "main" {
password = data.aws_ssm_parameter.db_password.value
}Command 142: Use Azure Key Vault
data "azurerm_key_vault_secret" "db_password" {
name = "db-password"
key_vault_id = data.azurerm_key_vault.main.id
}Command 143: Use HashiCorp Vault
data "vault_generic_secret" "db_creds" {
path = "secret/database/prod"
}
resource "aws_db_instance" "main" {
username = data.vault_generic_secret.db_creds.data["username"]
password = data.vault_generic_secret.db_creds.data["password"]
}36. Resource Targeting
Command 144: Target module
terraform apply -target=module.vpcCommand 145: Target multiple resources
terraform apply \
-target=aws_instance.web \
-target=aws_security_group.webCommand 146: Target resource in module
terraform apply -target=module.eks.aws_eks_cluster.mainCommand 147: Destroy specific module
terraform destroy -target=module.old_infrastructure37. JSON Configuration
Command 148: Write config in JSON
# main.tf.json
{
"resource": {
"aws_instance": {
"web": {
"ami": "ami-12345678",
"instance_type": "t3.micro"
}
}
}
}Command 149: Validate JSON configuration
terraform validateCommand 150: Convert HCL to JSON
# No native command, use tools like hcl2json38. Private Module Registry
Command 151: Use Terraform Cloud registry
module "vpc" {
source = "app.terraform.io/my-org/vpc/aws"
version = "1.0.0"
}Command 152: Authenticate to private registry
terraform login app.terraform.ioCommand 153: Publish module to registry
# Tag version in Git
git tag v1.0.0
git push origin v1.0.0
# Registry auto-publishes39. Override Files
Command 154: Create override file for development
# override.tf
resource "aws_instance" "web" {
instance_type = "t2.micro" # Override for dev
}Command 155: Use multiple override files
# Terraform automatically loads:
# - override.tf
# - override.tf.json
# - *_override.tf
# - *_override.tf.json40. External Data Sources
Command 156: Call external program
data "external" "example" {
program = ["python3", "${path.module}/script.py"]
query = {
environment = var.environment
}
}
output "result" {
value = data.external.example.result
}Command 157: Use template file
data "template_file" "user_data" {
template = file("${path.module}/user_data.sh")
vars = {
environment = var.environment
region = var.region
}
}41. Null Resources & Provisioners
Command 158: Trigger on changes
resource "null_resource" "example" {
triggers = {
always_run = timestamp()
}
provisioner "local-exec" {
command = "echo 'Resource updated'"
}
}Command 159: Remote execution
resource "aws_instance" "web" {
# ...
provisioner "remote-exec" {
inline = [
"sudo apt-get update",
"sudo apt-get install -y nginx"
]
connection {
type = "ssh"
user = "ubuntu"
private_key = file("~/.ssh/id_rsa")
host = self.public_ip
}
}
}Command 160: File provisioner
resource "aws_instance" "web" {
# ...
provisioner "file" {
source = "app.conf"
destination = "/etc/app/app.conf"
connection {
type = "ssh"
user = "ubuntu"
host = self.public_ip
}
}
}42. Terraform Cloud / Enterprise
Command 161: Configure Terraform Cloud backend
terraform {
cloud {
organization = "my-org"
workspaces {
name = "production"
}
}
}Command 162: Use multiple workspaces
terraform {
cloud {
organization = "my-org"
workspaces {
tags = ["production", "us-east-1"]
}
}
}Command 163: Run remote operations
terraform init
terraform plan # Runs in Terraform CloudCommand 164: Force local execution
terraform plan -lock=false43. Cost Estimation
Command 165: Estimate costs (Terraform Cloud)
terraform plan
# Cost estimate appears in Terraform Cloud UICommand 166: Use Infracost (open source)
infracost breakdown --path .
infracost diff --path .44. Compliance & Policy
Command 167: Sentinel policy (Terraform Enterprise)
# Policy file
import "tfplan/v2" as tfplan
main = rule {
all tfplan.resource_changes as _, rc {
rc.type is "aws_instance" implies
rc.change.after.instance_type in ["t3.micro", "t3.small"]
}
}Command 168: OPA policy with Terraform
terraform plan -out=tfplan.binary
terraform show -json tfplan.binary > tfplan.json
opa eval --data policy.rego --input tfplan.json "data.terraform.deny"45. Advanced Import Scenarios
Command 169: Import AWS VPC and subnets
# Import VPC
terraform import aws_vpc.main vpc-12345678
# Import subnets
terraform import aws_subnet.public[0] subnet-11111111
terraform import aws_subnet.public[1] subnet-22222222
terraform import aws_subnet.private[0] subnet-33333333Command 170: Import with for_each
# For resources created with for_each
terraform import 'aws_instance.web["web-1"]' i-1234567890abcdef0
terraform import 'aws_instance.web["web-2"]' i-0987654321fedcba0Command 171: Import Azure resources
terraform import azurerm_resource_group.main /subscriptions/{subscription-id}/resourceGroups/{resource-group-name}
terraform import azurerm_virtual_network.main /subscriptions/{subscription-id}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet-name}Command 172: Import GCP resources
terraform import google_compute_instance.main projects/{project}/zones/{zone}/instances/{instance-name}
terraform import google_compute_network.vpc projects/{project}/global/networks/{network-name}46. State Migration Scenarios
Command 173: Migrate from local to S3
# Step 1: Add backend configuration
cat >> backend.tf <<EOF
terraform {
backend "s3" {
bucket = "my-tf-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
}
}
EOF
# Step 2: Migrate
terraform init -migrate-stateCommand 174: Migrate between S3 buckets
# Update backend configuration
terraform init -migrate-state -backend-config="bucket=new-bucket"Command 175: Migrate from Terraform Cloud to S3
# Update backend from cloud to s3
terraform init -migrate-state47. Module Development
Command 176: Initialize module
mkdir -p modules/my-module
cd modules/my-module
cat > main.tf
cat > variables.tf
cat > outputs.tf
cat > README.md
cat > versions.tfCommand 177: Test module locally
cd examples/basic
terraform init
terraform planCommand 178: Validate module
terraform validate
terraform fmt -check -recursiveCommand 179: Generate module documentation
terraform-docs markdown . > README.md48. GitOps Workflows
Command 180: Automated plan on PR
# .github/workflows/terraform-plan.yml
name: Terraform Plan
on: [pull_request]
jobs:
plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v2
- run: terraform init
- run: terraform plan -no-colorCommand 181: Automated apply on merge
# .github/workflows/terraform-apply.yml
name: Terraform Apply
on:
push:
branches: [main]
jobs:
apply:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v2
- run: terraform init
- run: terraform apply -auto-approve49. Local Values & Functions
Command 182: Use built-in functions
echo 'upper("hello")' | terraform console
# Output: HELLO
echo 'cidrsubnet("10.0.0.0/16", 8, 1)' | terraform console
# Output: 10.0.1.0/24
echo 'jsondecode("{\"key\": \"value\"}")' | terraform console
# Output: {"key" = "value"}Command 183: Test conditional expressions
echo 'var.environment == "prod" ? "t3.large" : "t3.micro"' | terraform consoleCommand 184: Evaluate complex expressions
cat > test.tf <<EOF
locals {
subnets = {
public = cidrsubnet(var.vpc_cidr, 8, 1)
private = cidrsubnet(var.vpc_cidr, 8, 2)
}
}
output "test" {
value = local.subnets
}
EOF
echo 'local.subnets' | terraform console50. Terraform Aliases (Productivity)
Command 185: Create shell aliases
# Add to ~/.bashrc or ~/.zshrc
alias tf='terraform'
alias tfi='terraform init'
alias tfp='terraform plan'
alias tfa='terraform apply'
alias tfd='terraform destroy'
alias tfo='terraform output'
alias tfs='terraform state'
alias tfsl='terraform state list'
alias tfss='terraform state show'
alias tfv='terraform validate'
alias tff='terraform fmt'
alias tfiu='terraform init -upgrade'
alias tfpn='terraform plan -out=tfplan'
alias tfan='terraform apply tfplan'
alias tfaa='terraform apply -auto-approve'
alias tfda='terraform destroy -auto-approve'
alias tfws='terraform workspace'
alias tfwl='terraform workspace list'
alias tfwn='terraform workspace new'
alias tfws='terraform workspace select'Command 186: Advanced aliases with functions
# Terraform plan and save
tfps() {
terraform plan -out="tfplan-$(date +%Y%m%d-%H%M%S)"
}
# Terraform apply from latest plan
tfal() {
local latest_plan=$(ls -t tfplan-* | head -1)
terraform apply "$latest_plan"
}
# Terraform state backup
tfsb() {
terraform state pull > "state-backup-$(date +%Y%m%d-%H%M%S).tfstate"
}
# Terraform import interactive
tfii() {
echo "Resource address (e.g., aws_instance.web):"
read resource_address
echo "Resource ID:"
read resource_id
terraform import "$resource_address" "$resource_id"
}51. Remote State Locking Deep Dive
Command 187: Configure DynamoDB for S3 locking
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-state-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
tags = {
Name = "Terraform State Lock Table"
}
}Command 188: Manually check lock status
# For S3 backend with DynamoDB
aws dynamodb get-item \
--table-name terraform-state-locks \
--key '{"LockID": {"S": "my-bucket/prod/terraform.tfstate-md5"}}'Command 189: Clear stuck lock
# Get lock ID from error message
terraform force-unlock <lock-id>
# Or delete from DynamoDB (dangerous!)
aws dynamodb delete-item \
--table-name terraform-state-locks \
--key '{"LockID": {"S": "<lock-id>"}}'52. Experimental Features
Command 190: Enable experimental features
terraform {
experiments = [module_variable_optional_attrs]
}Command 191: Use optional attributes
variable "server_config" {
type = object({
name = string
size = optional(string, "t3.micro")
tags = optional(map(string), {})
})
}53. Replace & Dependency Management
Command 192: Replace resource with dependencies
# This will also recreate dependent resources
terraform apply -replace=aws_security_group.webCommand 193: Show resource dependencies
terraform graph | grep aws_instance.webCommand 194: Create explicit dependency
resource "aws_instance" "web" {
# ...
depends_on = [aws_security_group.web]
}54. Meta-arguments
Command 195: Use lifecycle meta-argument
resource "aws_instance" "web" {
# ...
lifecycle {
create_before_destroy = true
prevent_destroy = true
ignore_changes = [tags]
}
}Command 196: Use timeouts
resource "aws_db_instance" "example" {
# ...
timeouts {
create = "60m"
update = "60m"
delete = "2h"
}
}55. Terraform Backends Comparison
Command 197: S3 Backend (AWS)
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
kms_key_id = "arn:aws:kms:..."
}
}Command 198: Azure Backend
terraform {
backend "azurerm" {
resource_group_name = "terraform-rg"
storage_account_name = "tfstate"
container_name = "tfstate"
key = "prod.terraform.tfstate"
}
}Command 199: GCS Backend (GCP)
terraform {
backend "gcs" {
bucket = "my-terraform-state"
prefix = "prod"
}
}Command 200: Terraform Cloud Backend
terraform {
cloud {
organization = "my-org"
workspaces {
name = "production"
}
}
}Bonus: Troubleshooting Commands
Command 201: Check Terraform installation
terraform version
which terraform
terraform -version -jsonCommand 202: Verify provider installation
ls -la .terraform/providers/
terraform providers schema -json | jq '.provider_schemas | keys'Command 203: Test provider connectivity
# AWS
aws sts get-caller-identity
# Azure
az account show
# GCP
gcloud auth list
gcloud config listCommand 204: Debug graph generation
terraform graph | dot -Tsvg > graph.svg
open graph.svgCommand 205: Clean and reinitialize
rm -rf .terraform .terraform.lock.hcl
terraform init -upgradeCommand 206: Compact state file
# State files can grow large with many operations
terraform state pull | jq -c > compact-state.tfstate
terraform state push compact-state.tfstatePractice Directory: ./terraform/
Related Folders: aks/, eks/, gke/
Interview Topics Covered:
✅ 200+ Terraform commands across 55+ categories
✅ State management (local & remote)
✅ Workspaces for environment management
✅ Import existing infrastructure (AWS, Azure, GCP)
✅ Module development & usage
✅ Remote backends (S3, Azure, GCS, Terraform Cloud)
✅ Provider version management
✅ Drift detection & management
✅ Multi-cloud deployments (AWS + Azure + GCP)
✅ Latest Terraform 1.5-1.7 features (import blocks, check blocks, moved blocks, removed blocks)
✅ Interview Q&A scenarios (8 real-world problems)
✅ Best practices (state, security, code organization, testing, CI/CD)
✅ Common pitfalls & solutions (10 critical mistakes)
✅ Key differences (plan vs apply, count vs for_each, workspaces vs directories)
✅ Production-ready VPC module (complete 400+ line example with flow logs, NAT, security)
✅ Advanced patterns (dynamic blocks, conditionals, remote state, for_each, functions)
✅ GitOps integration (GitHub Actions examples)
✅ Security practices (KMS encryption, secrets management, Vault integration)
✅ Cost estimation (Terraform Cloud, Infracost)
✅ Policy as Code (Sentinel, OPA)
✅ Productivity aliases (30+ shell aliases and functions)
Modern Terraform Features (1.5-1.7):
- ✅ terraform test framework
- ✅ import blocks (declarative imports)
- ✅ check blocks (runtime assertions)
- ✅ moved blocks (refactoring without recreation)
- ✅ removed blocks (state-only removal)
- ✅ -replace flag (taint replacement)
- ✅ -generate-config-out (auto-generate configs from imports)
- ✅ Native variable validation
- ✅ Optional object type attributes
- ✅ Sensitive values protection
- ✅ Enhanced provider functions
- ✅ Improved JSON output
Cloud Provider Coverage:
- ☁️ AWS: EC2, VPC, S3, RDS, EKS, IAM, DynamoDB, CloudWatch
- ☁️ Azure: Resource Groups, VNet, AKS, Key Vault, Storage
- ☁️ GCP: Compute Engine, VPC, GKE, Cloud Storage
Complete Workflow Coverage:
- ✅ Initialization & Setup (7 commands)
- ✅ Planning & Preview (10 commands)
- ✅ Apply & Deployment (7 commands)
- ✅ Destroy Operations (5 commands)
- ✅ State Management (40+ commands)
- ✅ Import Strategies (15+ commands)
- ✅ Module Development (10+ commands)
- ✅ Testing & Validation (8+ commands)
- ✅ Debugging & Troubleshooting (15+ commands)
- ✅ CI/CD Integration (5+ commands)