Common Terraform Mistakes You Should Avoid!

Common Terraform Mistakes You Should Avoid!


Terraform is an open-source Infrastructure as Code (IaC) tool that allows you to define, provision, and manage cloud resources using declarative configuration files.

DevOps engineers use Terraform to automate and manage cloud infrastructure efficiently, but first-time users often make common mistakes like below:

1) Hardcoding values: Using hardcoded values instead of variables makes your infrastructure less reusable and difficult to manage across environments. Always leverage variables and locals.

?

resource "aws_instance" "example" {
  instance_type = "t2.micro"
  ami           = "ami-123456"
}
        

?

variable "instance_type" {
  default = "t2.micro"
}

variable "ami" {
  default = "ami-123456"
}

resource "aws_instance" "example" {
  instance_type = var.instance_type
  ami           = var.ami
}
        

2) Ignoring state file security: Failing to secure your Terraform state file (e.g., storing it locally or in unsecured S3 buckets) can expose sensitive data like secrets, passwords, and infrastructure details. Ensure the state file is encrypted and stored in a secure backend.

?

terraform {
  backend "local" {
    path = "terraform.tfstate"
  }
}
        

?

terraform {
  backend "s3" {
    bucket         = "my-secure-state-bucket"
    key            = "terraform/state"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-lock"
  }
}
        

3) Not using remote state: Keeping Terraform state files locally can lead to issues in collaboration and infrastructure drift. Use remote backends like S3 with state locking (e.g., DynamoDB) to ensure consistent updates and state management.

?

terraform {
  backend "local" {
    path = "terraform.tfstate"
  }
}
        

?

terraform {
  backend "s3" {
    bucket         = "my-remote-backend"
    key            = "prod/terraform.tfstate"
    region         = "us-west-2"
    encrypt        = true
    dynamodb_table = "terraform-state-lock"
  }
}        

4) Resource name collisions: Using the same resource names across different Terraform modules or workspaces can cause conflicts. Ensure that resources have unique names or use dynamic naming conventions with interpolation.

?

resource "aws_s3_bucket" "bucket" {
  bucket = "my-bucket"
}
        

?

resource "aws_s3_bucket" "bucket" {
  bucket = "my-bucket-${var.environment}"
}
        

5) Forgetting to plan before applying: Skipping terraform plan and directly running terraform apply can lead to unintended changes. Always review the plan output before applying any changes to your infrastructure.

?

 terraform apply
        

?

$ terraform plan -out=tfplan
$ terraform apply tfplan
        

6) Poor module design: Modules should be reusable, but overly complex or rigid modules can lead to maintainability issues. Strive for simplicity and flexibility when designing Terraform modules.

?

module "network" {
  source = "./modules/network"
  vpc_cidr = "10.0.0.0/16"
  public_subnets = ["10.0.1.0/24"]
  private_subnets = ["10.0.2.0/24"]
  enable_nat_gateway = false
}
        

?

variable "enable_nat_gateway" {
  type    = bool
  default = false
}

module "network" {
  source           = "./modules/network"
  vpc_cidr         = var.vpc_cidr
  public_subnets   = var.public_subnets
  private_subnets  = var.private_subnets
  enable_nat_gateway = var.enable_nat_gateway
}
        

7) Not pinning provider versions: Failing to specify the exact version of the Terraform provider can result in unexpected behavior when a new provider version introduces breaking changes. Always pin your provider versions using required_providers.

?

provider "aws" {}        

?

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

provider "aws" {}        

8) Not managing drift: Not running the Terraform plan periodically to check for drift between the actual infrastructure and the Terraform configuration can lead to infrastructure inconsistencies.

Always run "terraform plan" to check for drift

9) Incorrect use of depends_on: Sometimes, implicit dependencies are misunderstood, leading to errors. Using depends_on correctly ensures proper resource creation order, especially for resources with indirect dependencies.

?

resource "aws_instance" "example" {
  ami           = "ami-123456"
  instance_type = "t2.micro"
}

resource "aws_eip" "example_eip" {
  instance = aws_instance.example.id
}
        

?

resource "aws_instance" "example" {
  ami           = "ami-123456"
  instance_type = "t2.micro"
}

resource "aws_eip" "example_eip" {
  instance = aws_instance.example.id
  depends_on = [aws_instance.example]
}
        

10) Improper handling of secrets: Storing secrets directly in Terraform code or in plain text (like variables.tf) can compromise security. Use secret management tools like AWS Secrets Manager, Vault, or environment variables to handle sensitive data securely.

?

variable "db_password" {
  default = "SuperSecretPassword"
}

resource "aws_db_instance" "example" {
  password = var.db_password
}
        

?

variable "db_password" {
  type      = string
  sensitive = true
}

resource "aws_db_instance" "example" {
  password = var.db_password
}
        

11) Overlooking terraform destroy: Forgetting to set up proper dependencies and lifecycle rules can cause Terraform to delete critical infrastructure when running terraform destroy. Always review the destroy plan to avoid accidental deletion.

?

resource "aws_s3_bucket" "example" {
  bucket = "my-app-bucket"
}
        

?

resource "aws_s3_bucket" "example" {
  bucket = "my-app-bucket"

  lifecycle {
    prevent_destroy = true
  }
}        

12) Not using output values properly: Neglecting to use output values can make it hard to expose and use necessary data (e.g., IP addresses, DNS names) from your Terraform configuration.

?

resource "aws_instance" "example" {
  ami           = "ami-123456"
  instance_type = "t2.micro"
}
        

?

resource "aws_instance" "example" {
  ami           = "ami-123456"
  instance_type = "t2.micro"
}

output "instance_id" {
  value = aws_instance.example.id
}        

13) Improper resource lifecycle management: Using create_before_destroy and ignore_changes incorrectly can lead to resource downtime or unwanted changes. Use these lifecycle options carefully to control behavior during updates.

?

resource "aws_instance" "example" {
  ami           = "ami-123456"
  instance_type = "t2.micro"
}
        

?

resource "aws_instance" "example" {
  ami           = "ami-123456"
  instance_type = "t2.micro"

  lifecycle {
    create_before_destroy = true
  }
}
        

14) Exceeding API rate limits: Running Terraform on large infrastructures without adjusting provider limits or splitting resources into manageable chunks can cause API throttling issues, especially with cloud providers.

? Use:

 terraform apply -parallelism=5        


All in all, these are mistakes that intentionally / unintentionally create a huge impact, by taking care of all these you can achieve error-free infrastructure management, and setting the foundation is the path toward stable production infrastructure!

? Repost and give it a like if you have found these useful!

Follow Sandip Das and subscribe to this newsletter for useful Cloud, DevOps, MLOps, AIOps, and programming content!



Vijay P.

Azure Solutions Architect | Driving Cloud Transformation initiatives for enterprise clients | Manufacturing, Life Sciences, Energy & Insurance | Self-driven, Attention to detail and Technology passionate

1 个月

Sandip Das - Thanks very much for sharing this, you have put up great! i have few clarifications, in #2 about encrypting the state file when storing in S3 bucket - do we need to setup an encryption keys and manage with vault and enable RBAC for access? OR is this an automated way on cloud once we enable the "encrypt = true" using the keyword? Would be glad if you could further explanation on this please.

回复
Balraj Singh

Terraform | Cloud and Infrastructure Engineer | Cloud Transformation & Migration | DevOps

1 个月

Very informative

回复
Mohammed Tanvir

Certified Cloud Architect (OCI, AWS, Azure) | Expert in DevOps, Docker, Kubernetes, CI/CD, Ansible & Terraform | Unix/Solaris Specialist | Oracle SuperCluster M8 Architect

1 个月

Kudos to you for that wise sharing Sir!

回复
Rohan Agarwal

Business Automation | Data Science | I help Professionals and Entrepreneurs with Digital Marketing Services and Lead Generation | LinkedIn Marketing | FinTech | AI ML | Cosmology | Networking | Brand Strategy??

1 个月

Insightful

Darshan Wadekar

Skills Ontario Contestant | Cloud Computing | Certified Scrum Master | AWS | Git | Linux | Terraform | Docker | VMware

1 个月

Great insights, Sandip! This list highlights common pitfalls that many DevOps professionals, especially those new to Terraform, may overlook. Addressing issues like state file security, proper use of variables, and pinning provider versions are crucial for maintaining robust, scalable, and secure infrastructure. A well-structured Terraform setup not only prevents errors but also streamlines collaboration across teams. Thanks for sharing such valuable advice!

要查看或添加评论,请登录

社区洞察

其他会员也浏览了