Manage your cloud infrastructure
as code using Terraform

Nic Wortel
@nicwortel

About me

  • Software Consultant, Trainer, Coach
  • PHP, Symfony, DevOps, Kubernetes, DDD, Agile
  • Squad Leader / Instructor (reservist) at Royal NL Army

nicwortel.nl     @nicwortel

Goal of this talk

After this talk, you will...

  • Know what Infrastructure as Code & Terraform are
  • Understand the core Terraform workflow
  • Understand how Terraform uses state
  • Understand simple Terraform configurations

What is Infrastructure as Code?

  • Describe infrastructure using configuration files
  • Automate provisioning and configuration

Why use Infrastructure as Code?

  • Remove (error-prone) manual work
  • Track configuration using version control
  • Make infrastructure configuration reproducible
  • Create and destroy environments easily
  • Stop configuration drift
  • Always up-to-date documentation

Example use cases

  • Keep your test env in sync with production
  • Test infrastructure changes before applying them
  • Automate disaster recovery
  • Easily scale up or down
  • Automatically point DNS to new instances
  • Create a managed database instance and inject the credentials into the application
  • Manage GitHub organization members using pull requests

What is Terraform?

  • Infrastructure as Code tool by HashiCorp
  • Supports many cloud providers
  • Human-readable, declarative configuration
  • Uses state to track managed resources
  • Open source Business Source License

OpenTofu

  • Open-source fork of Terraform
  • Created as a response to HashiCorp's license change
  • Part of the Linux Foundation

Other IaC tools

  • Pulumi
  • CloudFormation (AWS)
  • Azure Resource Manager (Azure)
  • Deployment Manager (GCP)
  • Ansible
  • etc.

Building infrastructure

Providers

Providers are plugins that Terraform uses to interact with infrastructure providers

Terraform Registry

Provider examples

  • AWS
  • Azure
  • Google Cloud
  • DigitalOcean
  • Cloudflare
  • Kubernetes
  • Helm
  • GitHub
  • GitLab
  • Datadog
  • Okta
  • OneLogin
  • etc.

Requiring the AWS provider


                              terraform {
                                required_providers {
                                  aws = {
                                    source  = "hashicorp/aws"
                                    version = "~> 4.16"
                                  }
                                }
                              }
                        
Terraform init

Configuring the AWS provider


                              variable "aws_access_key" {
                                type = string
                                sensitive = true
                              }
                              
                              variable "aws_secret_key" {
                                type = string
                                sensitive = true
                              }
                              
                              provider "aws" {
                                region = "eu-central-1"
                                access_key = var.aws_access_key
                                secret_key = var.aws_secret_key
                              }
                        

                            # terraform.tfvars
                            aws_access_key = "xxxxx"
                            aws_secret_key = "xxxxxxx"
                        

Defining the EC2 resource


                              resource "aws_instance" "vm" {
                                ami = "ami-06dd92ecc74fdfb36"
                                instance_type = "t2.micro"
                              
                                tags = {
                                  Name = "DemoInstance"
                                }
                              }
                        
Terraform plan
Terraform demo 1
AWS Console EC2 instance

Making changes

State


                            resource "aws_instance" "vm" {
                           -  ami = "ami-0aa6457dc2d115893" # 20.04 LTS
                           +  ami = "ami-06461d2b867abebf0" # 22.04 LTS
                              instance_type = "t2.micro"
                            
                              tags = {
                                Name = "DemoInstance"
                              }
                            }
                      
Terraform changes
Terraform demo 2

Lifecycle Meta-Argument


                            resource "aws_instance" "vm" {
                              ami = "ami-06461d2b867abebf0"
                              instance_type = "t2.micro"

                              tags = {
                                Name = "DemoInstance"
                              }

                           +  lifecycle {
                           +    create_before_destroy = true
                           +  }
                            }
                      
Create before destroy

Destroying infrastructure

Data sources


                              data "aws_ami" "ubuntu" {
                                most_recent = true
                                owners      = ["amazon"]
                              
                                filter {
                                  name   = "name"
                                  values = [
                                    "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"
                                  ]
                                }
                              }
                        

                              resource "aws_instance" "vm" {
                             -  ami           = "ami-06461d2b867abebf0"
                             +  ami           = data.aws_ami.ubuntu.id
                                instance_type = "t2.micro"
                              
                                tags = {
                                  Name = "DemoInstance"
                                }
                              }
                        

Dependencies


                              terraform {
                                required_providers {
                                  aws = {
                                    source  = "hashicorp/aws"
                                    version = "~> 4.16"
                                  }
                             +    cloudflare = {
                             +      source  = "cloudflare/cloudflare"
                             +      version = "~> 3.0"
                             +    }
                                }
                              }
                        
Terraform init

                             +variable "cloudflare_api_token" {
                             +  type      = string
                             +  sensitive = true
                             +}
                              
                              provider "aws" {
                                region = "eu-central-1"
                              
                                access_key = var.aws_access_key
                                secret_key = var.aws_secret_key
                              }

                             +provider "cloudflare" {
                             +  api_token = var.cloudflare_api_token
                             +}
                        

                             # terraform.tfvars
                             aws_access_key       = "xxxx"
                             aws_secret_key       = "xxxx"
                            +cloudflare_api_token = "xxxx"
                        

                              resource "aws_instance" "vm" {
                                # ...
                              }

                              data "cloudflare_zone" "nicwortel" {
                                name = "nicwortel.nl"
                              }
                              
                              resource "cloudflare_record" "demo" {
                                zone_id = data.cloudflare_zone.nicwortel.id
                                name    = "demo"
                                type    = "A"
                                value   = aws_instance.vm.public_ip
                                proxied = true
                              }
                        

Replacing the dependency


                              data "aws_ami" "ubuntu" {
                                most_recent = true
                                owners      = ["amazon"]
                              
                                filter {
                                  name = "name"
                                  values = [
                             -      "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"
                             +      "ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"
                                  ]
                                }
                              }
                        

Modules

Modules allow you to:

  • Organize your code
  • Reuse pieces of configuration
  • Encapsulate configuration

Calling a module


                            module "database" {
                              source = "./modules/database"

                              db_name = "demo"
                            }
                        

Module outputs


                            module "database" {
                              source = "./modules/database"

                              db_name = "demo"
                            }

                            resource "aws_instance" "vm" {
                              user_data = templatefile("./templates/user-data.sh", {
                                db_host     = module.database.db_host
                                db_username = module.database.db_username
                                db_password = module.database.db_password
                                db_name     = module.database.db_name
                              })
                            }
                        

We always have at least one module: the root module

Recap

  • What is Infrastructure as Code?
  • What is Terraform?
  • Building infrastructure
  • Providers
  • Making changes
  • State
  • Destroying infrastructure
  • Data sources
  • Dependencies
  • Modules

Want to learn more?

Terraform tutorials

Terraform cheat sheet

Terraform cheat sheet

nicwortel.nl/cheat-sheets

Questions?

nicwortel.nl     @nicwortel

Please give me feedback!

nicwortel.nl     @nicwortel