Getting Started With Terraform

tech infrastructure-as-code devops terraform

Getting started with using Terraform for infrastructure can be a bit daunting if you’ve not dived into this stuff before. I put this together as a write up for those looking to get their feet wet and have a better idea of where to go for getting some momentum in starting. There are some assumptions in this, such as basic familiarity with git for source control automation, basic command line usage, and basic cloud familiarity.

If time permits, I plan on writing up some more detailed walk through in future posts on Terraform iteration methods, object types, dynamic data inputs, and other things I’ve explored. However, what I’ve found is just getting the initial start seems to be a blocker for many people interested in trying it. Hopefully, this will give someone a head start on getting a basic plan going so they can understand how this works a little better and the other more detailed tutorials that abound will make more sense then. Give this post a clap or leave a comment if it helps you or you have any feedback. Cheers! :cheers:

Purpose of This Post

In technical documentation, there is a difference between a tutorial and a getting started. The getting started here is going to focus just on getting up and running, not on all the concepts about infrastructure as code. I found that just doing it the first time was the hardest thing. Terminology about modules and re-usability at the beginning of my efforts with Terraform went straight over my head as I couldn’t fully wrap my understanding around how it would work. Now that I’ve gotten a lot more experience with Terraform for various projects, I’ve got some personal “best-practices” that I’ve found as well as insight from the community.

That’s for another day :grin:

Let’s just make sure you can get up and running with a basic deployment Terraform deployment from the scratch.

I had minimal Cloudformation authoring experience, so this was new stuff to me at the time.

What about Cloudformation?

More knowledgeable people than me have written about this. I’ll just say these personal subjective observations:

  1. Terraform is recognized for being a great tool in the industry, it’s not some “indie open source project about to fail”. Hashicorp has some serious vision.
  2. Just because you aren’t going “cross provider” with Azure and AWS doesn’t rule out Terraform. You aren’t necessarily gaining anything special by “sticking with native” AWS CF, like you might think.
  3. Terraform’s much more succinct, less prone to whitespace/indentation failures.
  4. IMO re-usability of Terraform provides itself to a better team collaborative experience.
  5. Terraform’s preview of changes is more intuitive to me. Less nervous to deploy stuff.
  6. I just like HCL (Hashicorps DSL) better than writing YAML docs.
  7. If you are writing YAML without any generator… just why!

Resources

LinksDescription
Terraform Documentation ReferenceTerraform Documentation for CLI
Terraform Documentation For AWSTerraform AWS Provider Documentation

Setup

Installation and setup

Install chocolatey via command prompt as administrator

@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"

For macOS

brew cask install terraform

Terraform Cloud Setup

Setup your Terraform App Account and make sure to enable 2FA.

Once you’ve been added, create a personal access token at your user settings (this is personal, not team based)

If you are using Terraform Cloud, run tf login to generate your local credential file to allow connecting to Terraform Cloud and easily using the registry and remote state workspaces provided.

Creating Your First Project

Create main.tf. It will be the first file you create.

Getting Started With Terraform Blog Post
# main.tf
terraform {
  required_version = ">= 0.12.9"
  backend "remote" {
    hostname     = "app.terraform.io"
    organization = "your-terraform-org-name-here"
    workspaces {
      # >>>>>>> THIS WILL CREATE A WORKSPACE FOR project-workspacetext
      # >>>>>>>  Recommend simplify with something consistent like "qa-initial-test-qa"
      prefix = "initial-test-"
    }
  }
}
# To trigger resources press ctrl+space, and then type `tf-` you'll see a ton of great snippets ready to go if you installed the terraform snippets visual studio code extensions

Create provider.tf

Getting Started With Terraform Blog Post

variable "allowed_aws_accounts" {
  default = ["123456789"] # Limits access to only our qa account so you can't easily goof and deploy to the wrong place
}

# PROVIDER: AWS https://www.terraform.io/docs/providers/aws/index.html
provider "aws" {
  version                 = "~> 2.7"
  region                  = "${lookup(var.region, var.env)}"
  profile                 = "${lookup(var.profilemap, var.env)}"
  shared_credentials_file = "%USERPROFILE%/.aws/credentials"

  #NOTE: for demo you can set these but don't ever consider it ok to leave this here other than for a quick test. Better to use named profiles to avoid accidentally committing IAM keys to your repo.
  # These in Terraform Cloud will be set as environment variables and automatically applied as to the provider when you use the correct naming per documentation
  #access_key = ""
  #secret_key = ""

  allowed_account_ids     = var.allowed_aws_accounts
}

Create terraform.auto.tfvars

Note that if you try to create this file with the terraform.tfvars name, it won’t work if using Terraform Cloud, as tfvars get generated dynamically from the variables setup in the Cloud workspace.

Getting Started With Terraform Blog Post
# VARIABLES: https://www.terraform.io/docs/cloud/workspaces/variables.
# Don't use terraform.tfvars with terraform cloud, only auto file is ok for this
username = "IForgotToFollowDirections"
tags = {
  Createdby = "IForgotToFollowDirections"
  ManagedBy = "terraform"
  Project
}

Create variables.tf which is going to house all the input variables we want to declare.

Getting Started With Terraform Blog Post
#variables.tf

# NOTE: "env" doesn't have a default value set. This means that you can't run the plan without setting the variable. This ensures the variable is set instead of defaulting and us forgetting
variable "env" { 
  type = string
  description = "This will be what you use to identify qa, uat, prod etc. Since we want to support terraform cloud we can't depend on string interpolation with terraform.workspace"
}

variable "region" {
  type = map(string)

  default = {
    qa   = "us-east-1"
    prod = "i-shouldnt-even-go-here-yet"
  }
}

variable "profilemap" {
  type = map(string)

  default = {
    qa   = "my-aws-named-profile-for-qa"
    prod = "i-shouldnt-even-go-here-yet"
  }
}


variable "username" {
    description = "this is my user name and required"

}
variable "tags" {
    description = "tags to apply to resources so people are happy"
}

Create iam.tf which will provide a nice low risk resource to create that will show you how to use string interpolation for dynamic names in the most simple way, as well as the way to leverage EOT syntax to easily escape mutliline strings. However, if you see yourself doing this constantly, you might reevaluate your approach to ensure you are using objects and properties as much as possible and not just strings.

Getting Started With Terraform Blog Post
resource "aws_iam_role" "role" {
  name = "terraform-test-${var.env}-iam-role-for-${var.username}"
  assume_role_policy =  <<-EOT
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "ec2:Describe*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
EOT
    tags = var.tags
}

You’ll likely want to use a workspace with Terraform to organize this work, so instead of using the default, use the command

terraform workspace new qa

Terraform should select this new workspace by default. You can list the current workspaces using terraform workspace list and then select another one later if you wish by running terraform workspace select qa.

Deploying Infrastructure

Deploying is as simple as running terraform apply. You’ll get a preview of the plan before apply, and then you can approve it to actually apply.

If You Connected This to Terraform Cloud

This is assuming you are running via Terraform Cloud. To run locally, you’ll want to go to the workspace you created in Terraform Cloud and in the General Settings set to run locally instead of remote.

This means you’ll be able to run the apply directly on your machine instead of running it from the remote location. Running remote is great, but for this to work you need to edit your Terraform remote cloud workspace and add the AWS access keys, as the job is actually running in the remote context and not using your local machine credentials.

Connecting your git repository to your Terraform workspace can also be done for automatically planning on commit. This forces changes to come through your git commits instead of being able to run locally, which can be great for ensuring source control truly is the equivalent of your release when working with a team.

Tearing Down Infrastructure

To tear down the infrastructure we just deployed, you can run: terraform destroy and approve the resulting preview it gives you.

If you are using Terraform Cloud, in order to destroy a remote workspace (by queuing the destroy then destroying the workspace fully), you’ll need to ensure the environment variable is set in the remote workspace for CONFIRM_DESTROY = 1

Wrap up

Terraform documentation is pretty solid on all the provider resources, so you can normally copy and paste (or use vscode extension mentioned). Another great way to learn is to look at github and the various Terraform modules that have been published. You can see how they structure their code a bit better and learn from that as well.

If you are using Visual Studio Code, also download the Hashicorp Terraform extension for extra support.

Good luck! If any steps were unclear or confusing please put in a comment and I’ll do my best to improve this for an initial on-boarding experience for a new Terraform user.