Terraform Quickstart

Posted: 06 September, 2021 Category: recipes Tagged: terraform

Note: to install terraform, the steps are almost identical to the steps in my Upgrading Terraform post, so look there.

Terraform "life cycle"

# can run this many times; no harm unless you change version of tf or providers in a major way
terraform init

# think of this a prettier for your tf files lol
terraform fmt

# validate the syntax etc of your files and check them against the valid schema
terraform validate

# describe what would happen if we were to run 'apply'
terraform plan

# build that infra!
terraform apply

# nuke that infra!
terraform destroy

It's good practice to keep your infra definitions alongside your application code, because... well, it's code. That's part of the point of IAC (Infrastructure as code).

In doing so, you might tuck it all away in a dedicated folder. A tutorial I was looking at did so with a deploy folder, and I followed suit. What that means though, is that all your terraform invocations can't take place at the root of your project tree anymore. You would need to cd into the target folder holding all your terraform goodies, and then (don't forget) cd back out again. Ugh. I prefer the programmatic equivalent, by way of terraform's -chdir switch. i.e.:

# let's pretend we're in the 'deploy' folder, shall we?
terraform -chdir=deploy init

...etc. All terraform commands (init, plan, apply etc) can be prefixed with this little directory change switch. Much neater and makes it explicit where everything is running. Also perfect for CI/CD pipelines: type once and forget about it.


The lowdown is here. I am honestly not trying to maintain dev, staging AND prod environments (or more). But large projects do, so I'm trying to get into the habit of at least pegging the final deployable thing as prod. To that end, workspaces come in handy:

# list all workspaces
terraform workspace list

# create a separate workspace
terraform workspace new <workspace-name>

# select a pre-existing workspace
terraform workspace select <workspace-name>

Handy snippet for maneuvering workspaces inside ci/cd pipelines. Example:

terraform workspace select staging || terraform workspace new staging

Riight? Nifty.

emoji-boom if using workspace name xyz, remember that tf will store the corresponding statefile at env/xyz/<statefile> and this might muff up your carefully laid plans around what paths exist and what access permissions target what paths/resources. After invoking workspaces I had to:

  • prefix the bucket key in my S3 backend accordingly (in main.tf)
  • change my IAM policy for the terraform user so that the new path is accessible


The point about bothering with these in the first place is that:

  • with local backends (the default), everything happens from your machine: state is stored locally, and although you're provisioning remote infra, the commands are comming from your machine.
  • with remote backends, your state is stored remotely, and you additionally have the choice to perform operations remotely too, if you want to. I.e. computer B reads the state from computer C in the cloud, and builds computer D in yet another cloud, according to your terraform instructions... and your local machine is completely uninvolved.

I was going to use terraform cloud. I TOTALLY was. But when it came time to shake oauth hands with my github, it seemingly wanted access right down to orgs I didn't even own. So I was like, yeah naw. (tbf I didn't poke around too much with proffered grant/revoke switches on each org - I was too disgusted and had already reflexively clicked cancel. Another day mayhaps. With a different account, I shouldn't wonder. Lol!).

I've gone with the S3 backend + dynamodb for locking. Will hunt for alternatives in future.

This backend requires an AWS::IAM user with the necessary creds to poke around in S3 and dynamodb, but the S3 backend docs pretty much give you everything needed to set up the resources as well as the access policy.