logo

Cheatsheet - Terraform / OpenTofu

This is a cheatsheet of Terraform and OpenTofu configurations.

Terraform Blocks

Hierarchy:

terraform => provider => resource
                      => data
  • Resource: Generate; e.g. generate a local file resource "local_file" "foo" {}
  • Data Source: Read; e.g. read a local file data "local_file" "foo" {} , then content can be referenced by data.local_file.foo.content

3 types of values:

  • variable: input variable (like the arguments of a func)
  • output: output variable (like the return value of a func)
  • locals: local values (like temp / local vars in a func)

Terraform

Top level configs, e.g. required_providers, required_version, etc.

terraform {
  required_version = "1.5.7"
  required_providers {
    docker = {
      source  = "kreuzwerker/docker"
      version = "2.15.0"
    }
  }
}

Providers

providers = terraform plugins; Each provider adds a set of resource types and/or data sources that Terraform can manage.

The Terraform Registry is the main directory of publicly available Terraform providers

official: hashicorp

  • source address: registry.terraform.io/hashicorp/http
  • default registry host: registry.terraform.io
  • namespace: hashicorp
  • type: http

For example:

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

required provider:

terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = ">=x.y.0"
    }
  }
  ...
}

provider "google" {
  ...
}

hashicorp/google, its preferred local name is google

if you do not use the preferred local name, must use a meta-argument provider = <local name> to specify the provider in data and resource etc.

version:

  • >= minimum version
  • ~> only allowing the rightmost component of a version to increment

version = "~> 1.0.4" allow only patch releases within a specific minor release:

Built-in Providers do not need to be declared in required_providers

Resource

Each resource block describes one or more infrastructure objects, such as virtual networks, compute instances, or higher-level components such as DNS records.

Format:

resource <type> <local_name> {}

For example:

resource "aws_instance" "example" {
  ami           = "ami-0abcdef1234567890"
  instance_type = "t2.micro"
  tags = {
    Name = "MyExampleInstance"
  }
}

Most arguments in this section depend on the resource type

Each resource type is implemented by a provider; By convention, resource type names start with their provider's preferred local name.

Variable

Input values for your Terraform configuration. Defined in variables.tf (or inline).

variable "instance_type" {
  description = "The type of EC2 instance to create"
  type        = string
  default     = "t2.micro"
}

To use: var.instance_type To set: terraform apply -var="instance_type=t2.small" or terraform.tfvars file.

Data

Data sources allow Terraform to use information defined outside of Terraform, defined by another separate Terraform configuration, or modified by functions. Read from data_source and export the result under local_name

data <data_source> <local_name> {

}

For example:

data "aws_ami" "ubuntu" {
  most_recent = true
  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }
  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
  owners = ["099720109477"] # Canonical
}

Output

Values that are exported by a Terraform configuration. Defined in outputs.tf.

output "instance_id" {
  description = "The ID of the EC2 instance"
  value       = aws_instance.example.id
}

Output value can be referenced by module.<MODULE NAME>.<OUTPUT NAME>, e.g. module.web_server.instance_ip_addr.

Check

The check block can validate your infrastructure outside the usual resource lifecycle.

Import blocks

available in >=1.5

Module

A Module is a collection of .tf and/or .tf.json files kept together in a directory.

Reusable, encapsulated configurations.

module "vpc" {
  source = "./modules/vpc" # Local path
  # source = "terraform-aws-modules/vpc/aws" # Registry module
  cidr_block = "10.0.0.0/16"
  # ... other module inputs
}

State File

terraform.tfstate: A JSON file that maps real-world resources to your configuration. Crucial for Terraform's operation. Do not edit manually. Store remotely for team collaboration (e.g., S3, Azure Blob, GCS).

terraform {
  backend "s3" {
    bucket = "my-terraform-state-bucket"
    key    = "path/to/my/key.tfstate"
    region = "us-east-1"
  }
}

Advanced Features

  • count: Creates multiple instances of a resource based on a numerical count.

    resource "aws_instance" "app_server" {
      count = 3
      ami = "ami-0abcdef1234567890"
      instance_type = "t2.micro"
      tags = {
        Name = "AppServer-${count.index}"
      }
    }
    
  • for_each: Creates multiple instances of a resource based on a map or set of strings, providing more stable identifiers.

    variable "regions" {
      type = map(string)
      default = {
        "us-east-1" = "ami-0abcdef1234567890"
        "us-west-2" = "ami-0fedcba9876543210"
      }
    }
    
    resource "aws_instance" "region_instance" {
      for_each = var.regions
      ami           = each.value
      instance_type = "t2.micro"
      tags = {
        Name    = "Instance-${each.key}"
        Region  = each.key
      }
    }
    
  • depends_on: Explicitly specifies resource dependencies when Terraform cannot infer them.

    resource "aws_instance" "web" {
      # ...
      depends_on = [
        aws_db_instance.main
      ]
    }
    
  • Tainting: terraform taint [resource_address] marks a resource for recreation on the next apply.

  • Untainting: terraform untaint [resource_address] removes a tainting mark.

  • Import: terraform import [resource_address] [resource_id] imports existing infrastructure into Terraform state.

Functions

Terraform provides many built-in functions for manipulating data.

  • concat(list1, list2)
  • merge(map1, map2)
  • lookup(map, key, [default])
  • file(path)
  • length(collection)
  • join(separator, list)
  • split(separator, string)
  • lower(string), upper(string)
  • cidrsubnet(prefix, newbits, netnum)

Registries

When HashiCorp changed its license from the open-source Mozilla Public License to the more restrictive Business Source License, it also put the future of the Terraform Registry under the same license. For OpenTofu to be a viable long-term solution, it needed an independent source for providers and modules that would remain free and open.

Providers

Built-in providers:

  • hashicorp/local
  • hashicorp/http
  • hashicorp/tls
  • hashicorp/random

Public Cloud providers:

  • hashicorp/aws
  • hashicorp/google
  • hashicorp/azurerm
  • aliyun/alicloud
  • oracle/oci

Kubernetes / container / VM providers:

  • hashicorp/kubernetes
  • kreuzwerker/docker
  • vmware/nsxt (for NSX-T virtualization platform)