Skip to content


Our first stop is the Infrastructure As Code (IAC) that we wrote in Terraform. We're going to manually deploy this code from our local machines and review the results.


Before we can get started we're going to have to set up a few environment variables so that Terraform can do two things:

  1. Authenticate against the GitLab API and fetch/store/lock the remote state file
  2. And authenticate against the AWS API so it can actually manage our infrastructure for us

Without setting up the credentials needed to make this work we're not going to be able to get much done.

To help you get started, here is a quick snippet of shell code you can copy/paste, update and then apply to your local environment:

export TF_VAR_aws_region=
export TF_VAR_aws_access_key=
export TF_VAR_aws_secret_key=

Save this file as ~/.infrastructure.secrets.

You'll need to supply the values for each of the variables.


We're going to need access to the GitLab API. Without this access we cannot us our remote Terraform state storage inside of GitLab. Let's resolve this:



I recommend you do not use your literal GitLab password here. Instead create an access token, which we discussed here.


We need to ensure we've got a few environment variables set up for our AWS credentials:

export TF_VAR_aws_access_key=
export TF_VAR_aws_region=
export TF_VAR_aws_secret_key=

These are the values you will have set up and copied from the AWS console when you first created your account and then your first IAM user.

Update the Environment

Once this file has been created and set up, you can save is to disk and then apply it to your local (Linux/macOS) shell environment:

source ~/.infrastructure.secrets

Then use export to see a list of environment variable currently configured for your current shell/session. You should see your new infrastructure variables.

Now let's review the steps we're going to take to get Terraform to build out infrastructure.


So let's step through what we're going to be doing now that we've written all of our code:

  1. We're going to terraform init
  2. We're going to terraform plan -out latest.plan
  3. We will review the plan and discuss it
  4. Finally we will execute terraform apply latest.plan

Once we've deployed all of our Terraform code, we will move onto the application and then, finally, Ansible.

Terraform Flow

When we use terraform plan, this is what's happening behind the scenes (in a simplified manner):

graph LR
    a[Plan] --> b[GitLab API]
    b[Fetch Terraform State] --> c[AWS API]
    c --> d[Fetch Remote State]
    d --> e[Compare States]
    e --> f[Output Plan File]

The plan file that is output (latest.plan) contains everything Terraform knows about our current state, the remote state in AWS, the differences between the two and how-to align what exists remotely with what we want, as engineers, based on our code.

In short: Terraform is comparing your code (the .tf files) to your state (terraform.tfstate from the GitLab storage), then comparing the state to what you have remotely (in AWS) and calculating what has to happen. This is what a terraform plan is doing for you.This is also true of terraform apply when you don't provide it with a plan file.

When we eventually execute terraform apply latest.plan we get this (simplified) flow:

graph LR
    a[Read Plan] --> b[AWS API]
    b --> c[Update State]
    c --> d[Push State to Remote Storage]

So the apply subcommand is actually implementing the plan, which results in changes to the remote AWS infrastructure, which are then saved to the state file that is then, finally, uploaded to GitLab and the Terraform remote state storage mechanism.

We're going to talk more about Terraform state files next. It's important you understand how critical this file is, how it's used, stored and how it should be managed.


Now we're going to initialise our local Terraform configuration based on our code.