A simplifed Terraform and AWS tutorial

A lot of tutorials and youtube videos about Terraform go through the process of downloading and installing Terraform. This process is essentially to download a single executable and make sure that this executable is in your path. This process is rather well described and so I will not waste any time on this setup.

If you are not somewhat familiar with Terraform it may be a surprise to learn Terraform is a command line program. There is no GUI, just a few basic commands that can be used but the lack of a GUI is a strength not a weakness. This makes it possible to use Terraform in batch processes. One obvious and common process would be to add Terraform as part of a CI/CD pipeline.

Terraform as previously mentioned allows you to create scripts that will describe your desired infrastructure. Running Terraform will compare your desired state against what is actually setup. This middleware layer does slightly abstract you from the underlying platform. It might not be totally clear from reading other articles but this abstraction doesn’t allow you to transparently and automatically change between AWS and Azure backend. The scripts are rather specific to which underlying platform you are writing them for. Yet, if you write your applications in a rather independent way, they can run on any cloud platform you choose.

This script actually doesn’t really create anything. Terraform uses the AWS CLI tools and so it is important to have these credentials available. The could be hard coded in a script, defined as a Terraform variable or even defined as an environment variable.

provider “aws” {
region = “eu-central-1”
access_key = var.AWS_ACCESS_KEY_ID
secret_key = var.AWS_SECRET_ACCESS_KEY
}

This example shows the access_key and secret_key being assigned from a variable. These values are typically saved in the .aws directory of the users home directory. The AWS CLI setup is not described here as there is plenty of documentation available from Amazon itself.

The first time you run Terraform you may see the following message.

> terraform plan

│ Error: Inconsistent dependency lock file

│ The following dependency selections recorded in the lock file are inconsistent with the current configuration:
│ – provider registry.terraform.io/hashicorp/aws: required by this configuration but no version is selected

│ To make the initial dependency selections that will initialize the dependency lock file, run:
│ terraform init
Terraform error if not properly initialized

This error is because Terraform either did not have the proper underlying provider defined or because the initialization using that provider was not done. The important first step once the provider has been defined is to run the initialization command.

Terraform init

The initialization step will produce output similar to the following.

Initializing the backend…
Initializing provider plugins…
– Finding latest version of hashicorp/aws…
– Installing hashicorp/aws v4.20.0…
– Installed hashicorp/aws v4.20.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider selections it made above. Include this file in your version control repository so that Terraform can guarantee to make the same selections by default when you run “terraform init” in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running “terraform plan” to see any changes that are required for your infrastructure. All Terraform commands should now work.
If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.
Output from Terraform initialize

First Terraform scripts

A lot of tutorials on Terraform start with a few scripts with all the values hard coded. I have even seen a few where the AWS CLI credentials are hard coded. These examples do explain quite a bit about Terraform but most do not go back and correct the credentials to a proper secure state. I would rather start with a slightly more complicated solution that is secure from the beginning.

In this tutorial there is a named development.tf where variables for a single environment can be defined. The file will contain all setup for creating a development environment. By separating the values for each environment into a separate file it is possible to have a single infrastructure setup defined which can be parameterized with differing infrastructure attributes. This makes it trivial to have a test environment that is identical to production or perhaps to create multiple but slightly smaller development environments – one for each developer.

When you separate out various infrastructure values as variables they can be passed to Terraform one by one but what is more common is to pass an entire file full of variables.

terraform plan -var-file=development.tfvars

The output of this command will show what, if any, changes will be performed. If the standard output does not alway provide enough information but it is possible to add additional types of output. This is an example with a few additional values being displayed in the output.

Changes to Outputs:
_environment = “development”
awskey = “AKI YOURKEYHERE PFZ9”
awssecret = “tnd your secret would be here 26362383 DS3Wk9C”
region = “us-east-1”
You can apply this plan to save these new output values to the Terraform state, without changing any real
infrastructure.
──────────────────────────────────────────────────────────────────────────
Note: You didn’t use the -out option to save this plan, so Terraform can’t guarantee to take exactly these actions if
you run “terraform apply” now.
Output from Terraform plan command

It is important to note, that setting up environment variables to hold the AWS key and AWS secret is super for security but displaying it like above is a totally bad idea in real life. It was done this way simply to show off an example of how to display Terraform variables.

Below is the example code. This example doesn’t actually create any infrastructure but does show everything necessary for using the AWS key and secret information from the environment. Yet, in order for this to work it is necessary to have two environment variables.

TF_VAR_AWS_ACCESS_KEY_ID
TF_VAR_AWS_SECRET_ACCESS_KEY

The TF_VAR is the key to allow Terraform to know which environment variables should be passed through to the scripts.

The next blog post will use this as the basis to build actual infrastructure.

main.tf
provider “aws” {
region = var.region
access_key = var.AWS_ACCESS_KEY_ID
secret_key = var.AWS_SECRET_ACCESS_KEY
}
inputs.tf
variable “environment” {
type = string
description = “what env we are using”
default = “Development”
}
variable “region” {
type = string
description = “in which region we will do all of our work”
default = “eu-central-1”
}
variable “AWS_ACCESS_KEY_ID” {
type = string
description = “user access_key”
}
variable “AWS_SECRET_ACCESS_KEY” {
type = string
description = “user secret access key”
}
output.tf
output “region” {
value = var.region
}
output “_environment” {
value = var.environment
}
output “awskey” {
value = var.AWS_ACCESS_KEY_ID
}
output “awssecret” {
value = var.AWS_SECRET_ACCESS_KEY
}
development.tfvars
region = “us-east-1”
environment = “development”
This entry was posted in Setup From Scratch. Bookmark the permalink.