Infrastructure as Code with Terraform: Managing Cloud Resources Declaratively | SoniNow Blog

Limited TimeLearn More

terraforminfrastructure as codeiacclouddevops

Infrastructure as Code with Terraform: Managing Cloud Resources Declaratively

Published

2026-06-23

Read Time

3 mins

Infrastructure as Code with Terraform: Managing Cloud Resources Declaratively

Clicking around a cloud console to provision infrastructure is fast for a single server but catastrophic at scale. Terraform flips the model: you declare what your infrastructure should look like in HCL (HashiCorp Configuration Language), and it converges reality to match. No drift, no undocumented manual changes, no "who created this bucket?"

Core Terraform Concepts

Every Terraform project begins with a provider configuration and a set of resources:

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

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

resource "aws_s3_bucket" "app_assets" {
  bucket = "myapp-assets-production"
  tags = {
    Environment = "production"
    ManagedBy   = "terraform"
  }
}

resource "aws_s3_bucket_versioning" "app_assets" {
  bucket = aws_s3_bucket.app_assets.id
  versioning_configuration {
    status = "Enabled"
  }
}

The key insight: Terraform builds a dependency graph from resource references. aws_s3_bucket_versioning.app_assets depends on aws_s3_bucket.app_assets because it references its id. Terraform resolves these automatically and creates resources in the correct order.

State Management and Remote Backends

Terraform stores the mapping between your configuration and real-world resources in a state file. Never store this file locally—that's a disaster waiting to happen when a laptop dies or a teammate overwrites the file.

Always use a remote backend:

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

The DynamoDB table provides state locking so two team members can't run terraform apply simultaneously. For GCP, use a GCS bucket with object versioning. For Azure, use Azure Storage with blob leasing. If you're using Terraform Cloud or Enterprise, state is managed for you with built-in locking and history.

Modules for Reusable Infrastructure

Modules are the building blocks of scalable Terraform code. A well-designed module encapsulates a logical unit of infrastructure:

module "vpc" {
  source = "./modules/vpc"
  
  name          = "main"
  cidr_block    = "10.0.0.0/16"
  public_subnets  = ["10.0.1.0/24", "10.0.2.0/24"]
  private_subnets = ["10.0.10.0/24", "10.0.20.0/24"]
  enable_nat_gateway = true
  tags = {
    Environment = "production"
  }
}

Publish modules to a private registry (or the public Terraform Registry) so multiple projects share the same VPC, database, and security group patterns. Version your modules with semver tags so consuming projects pin to stable releases.

Workspaces and Environment Isolation

Use workspaces—or better yet, separate directory configurations—to isolate environments:

# environments/production/main.tf
module "app" {
  source = "../../modules/app"
  environment = "production"
  instance_type = "t3.medium"
  min_size      = 3
  max_size      = 10
}

# environments/staging/main.tf
module "app" {
  source = "../../modules/app"
  environment = "staging"
  instance_type = "t3.micro"
  min_size      = 1
  max_size      = 3
}

This pattern makes it obvious which environment you're deploying to. Each directory has its own state file and remote backend key. Never use a single set of Terraform files for both staging and production—the blast radius of a misapplied change is too large.

Plan, Apply, and Drift Detection

Terraform's plan output is your safety net. CI/CD pipelines should run terraform plan on every pull request and post the output as a comment. A human reviews the diff to catch unintended changes before terraform apply runs.

Enable drift detection: run terraform plan on a schedule (daily, hourly) and alert when the plan shows changes. This catches resources modified outside Terraform—someone increasing an RDS instance size through the console, a developer tweaking a security group manually.

Declare Your Infrastructure with SoniNow

Terraform turns infrastructure management from a fragile manual process into a version-controlled, reviewable, and repeatable workflow. Our DevOps engineers at SoniNow build Terraform configurations that keep your cloud infrastructure predictable and auditable.