Terraform
Summary
Terraform is an open-source Infrastructure as Code (IaC) tool developed by HashiCorp. It allows you to define and provision infrastructure using a declarative configuration language called HCL (HashiCorp Configuration Language).
Best Practices
Use Remote Backend for State Management
Terraform stores state to track infrastructure changes. A remote backend (e.g., S3 + DynamoDB) ensures consistency and team collaboration.
Example (backend.tf):
terraform { backend "s3" { bucket = "my-terraform-state" key = "envs/prod/terraform.tfstate" region = "us-east-1" dynamodb_table = "terraform-lock" encrypt = true } }
Use Modules for Reusability
Organizing infrastructure as modules makes it easier to maintain and reuse components.
Example Directory Structure:
terraform/ ├── modules/ │ ├── vpc/ │ ├── ec2/ │ ├── rds/ │ ├── s3/ ├── environments/ │ ├── dev/ │ ├── prod/ │ ├── test/
Use Workspaces for Multi-Environment Management
Workspaces allow Terraform to manage multiple environments within the same configuration.
Commands to Create and Switch Workspaces:
terraform workspace new dev terraform workspace select dev terraform apply
To switch to a different environment:
terraform workspace select prod terraform apply
Using workspaces ensures that your environments (e.g., dev, prod, test) are separated, and each has its own isolated state file. This approach is particularly useful when you want to use the same configuration for different environments, but each environment's state is kept separate.
Example of Workspace-specific Variables:
# terraform.tfvars for dev aws_region = "us-east-1" cidr_block = "10.0.0.0/16" # terraform.tfvars for prod aws_region = "us-west-2" cidr_block = "10.1.0.0/16"
Now, you can have different sets of configurations for dev, prod, and test environments with environment-specific variables that can be managed with different workspaces.
Secure Secrets and Sensitive Data
Use Terraform variables with `sensitive = true` and AWS Secrets Manager.
Example (variables.tf):
variable "db_password" { description = "Database password" type = string sensitive = true }
Essential Terraform Commands
These commands are used in most Terraform workflows.
Initialization:
terraform init
Plan the deployment:
terraform plan -var="aws_region=us-east-1"
Apply changes:
terraform apply -var="aws_region=us-east-1" -auto-approve
Check Terraform state:
terraform state list
Destroy resources:
terraform destroy -var="aws_region=us-east-1" -auto-approve
Deploying an AWS VPC
This example provisions a VPC with public and private subnets.
VPC Module (vpc.tf):
module "vpc" { source = "./modules/vpc" vpc_name = "prod-vpc" cidr_block = "10.0.0.0/16" public_subnets = ["10.0.1.0/24", "10.0.2.0/24"] private_subnets = ["10.0.3.0/24", "10.0.4.0/24"] }
VPC Module (modules/vpc/main.tf):
resource "aws_vpc" "main" { cidr_block = var.cidr_block tags = { Name = var.vpc_name } }
Variables (modules/vpc/variables.tf):
variable "vpc_name" { type = string } variable "cidr_block" { type = string } variable "public_subnets" { type = list(string) } variable "private_subnets" { type = list(string) }
Deploying a Terraform CI/CD Pipeline
A Terraform CI/CD pipeline ensures consistent and automated deployments. This example uses AWS CodePipeline.
Pipeline Stages:
- Source – Fetch Terraform code from Bitbucket.
- Plan – Run `terraform plan`.
- Approve – Manual approval for `prod`.
- Apply – Run `terraform apply`.
Pipeline Definition (pipeline.tf):
resource "aws_codepipeline" "terraform_pipeline" { name = "terraform-deploy" role_arn = aws_iam_role.pipeline_role.arn artifact_store { location = "my-codepipeline-bucket" type = "S3" } stage { name = "Source" action { name = "FetchSource" category = "Source" owner = "AWS" provider = "CodeCommit" version = "1" configuration = { RepositoryName = "terraform-repo", BranchName = "main" } output_artifacts = ["source_output"] } } stage { name = "Plan" action { name = "TerraformPlan" category = "Build" owner = "AWS" provider = "CodeBuild" version = "1" input_artifacts = ["source_output"] configuration = { ProjectName = aws_codebuild_project.terraform_plan.name } } } stage { name = "Approve" action { name = "ManualApproval" category = "Approval" owner = "AWS" provider = "Manual" version = "1" } } stage { name = "Apply" action { name = "TerraformApply" category = "Build" owner = "AWS" provider = "CodeBuild" version = "1" input_artifacts = ["source_output"] configuration = { ProjectName = aws_codebuild_project.terraform_apply.name } } } }
Security Best Practices
- Enable AWS Config & GuardDuty – Monitor changes and security threats.
- Encrypt sensitive data – Use AWS KMS for encrypting resources.
- Use private subnets – Keep sensitive resources off the public internet.
- Use IAM roles with least privilege access.
Conclusion
By following these Terraform best practices for AWS, you ensure a secure, scalable, and efficient infrastructure. Keep your Terraform setup modular, automated, and well-documented.
Deploying with Workspaces for Environment Separation
Workspaces are useful when you want to maintain environment separation in a single Terraform configuration. For example, each environment (dev, test, prod) would have its own workspace, ensuring separate state files and variable configurations.
Steps to Deploy Using Workspaces: 1. Create and switch to a workspace:
terraform workspace new dev terraform workspace select dev terraform apply
2. Apply changes in the dev environment:
terraform apply
3. Switch to the production workspace and apply:
terraform workspace select prod terraform apply
By using workspaces, you separate your environments' state files, making it easier to manage infrastructure across multiple environments. Each workspace can have different configurations or even different variables.
Deploying Without Workspaces
If you don't want to use workspaces and want to deploy in different environments without this separation, you can use distinct `terraform.tfvars` files or specify variables directly in the command line.
For example: 1. In the dev environment, you could specify variables like so:
terraform apply -var="aws_region=us-east-1" -var="cidr_block=10.0.0.0/16"
2. For production, you can specify a different set of variables:
terraform apply -var="aws_region=us-west-2" -var="cidr_block=10.1.0.0/16"
This method doesn’t use workspaces but still allows different configurations for different environments by passing the relevant variables during the apply phase.
---
Retrieved from your Terraform Wiki