Journey through IaC: Terraform basics
06 Jan 2021With infrastructure as code being a big thing these days, I decided to broaden my horizons a bit and look into Terraform. Terraform is a tool by Hashicorp used for describing and provisioning infrastructure, primarily in the cloud. It’s very popular these days, so it seems like a good starting point for my journey through IaC.
The objective of this exercise is getting to know a little about Terraform by creating a VM. I decided to start by deploying a VM on GCP. I will be focusing on using Terraform, but the scope for now will be reduced to managing a single project in GCP.
The setup
First of all, installation of Terraform CLI. In my case, it was possible to just use pacman -S terraform
. It’s one patch version behind at the time of writing, but that’s not a big issue for me. Full installation instructions can be found here. The tutorial also contains a handy test that everything works by provisioning an NGINX Docker container. Just copy and pase a file, run a couple commands and boom, you’ve got an NGINX server running in Docker. The part that surprised me was that destroying the environment also deleted the Docker image, leaving the environment clean. Neat!
The second part is setting up Google Cloud. First, creating a Google Cloud account. Not much to say about that, just follow the instructions on their webpage. They offer some free services and some free credits, which is nice. Now, creating a project to keep everything nice and tidy. It can be done here. I called mine terraform-tutorial
. While I’m there, I should also enable Google Compute Engine API and create a service account. The service account should have a project editor role.
And now, we can finally start writing our Terraform configuration.
The configuration
Before starting this, I recommend creating a folder locally to keep files organized. This is not a big or lasting project, so I don’t see a point in creating a git repository for this purpose. In any case, we can start writing a file called main.tf
. The documentation for GCP provider is available here and there’s also an example file in the Terraform tutorial. Also, make sure to copy the service account credentials in json format to this folder.
The default main.tf
looks like this:
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "3.5.0"
}
}
}
provider "google" {
credentials = file("terraform-tutorial.json")
project = "terraform-tutorial-300814"
region = "us-central1"
zone = "us-central1-c"
}
resource "google_compute_network" "vpc_network" {
name = "terraform-network"
}
resource "google_compute_instance" "vm_instance" {
name = "terraform-instance"
machine_type = "f1-micro"
boot_disk {
initialize_params {
image = "debian-cloud/debian-9"
}
}
network_interface {
network = google_compute_network.vpc_network.name
access_config {
}
}
}
The file consists of three sections. The first one is Terraform metadata, in this case only describing the required providers. The second one configures that one provider, giving it credentials to use, as well as some variables that apply to all of the resources in this file. The third one has a bunch of resource blocks, describing what we want to create in the cloud.
Alright, one terraform init
and terraform apply
later, we have a VM up. Woohoo! Alright, let’s try accessing the VM via SSH. Google Cloud console offers a nice feature of generating a command that can be used to SSH into the machine directly using the gcloud
command from Google Cloud SDK. Install the SDK, login, paste the command, wait a little until it generates a key file… And it doesn’t work.
The SSH access
It mentions some firewall, could that be it? Let’s use Terraform to create that! Documentation for the Terraform resource can be found here and the GCP firewall documentation is here. First, we should add a firewall rule to main.tf
:
resource "google_compute_firewall" "default" {
name = "terraform-tutorial-firewall"
network = google_compute_network.vpc_network.name
allow {
protocol = "icmp"
}
allow {
protocol = "tcp"
ports = ["22"]
}
}
Basically, what it says is allow ICMP traffic and TCP traffic over port 22 on VMs in the VPC network we created earlier. Try the SSH command again after applying the rule and, well, it works! However, are we happy with that? We’re using an SSH key that gcloud
generated for us, can we use Terraform to configure access by providing a public key? Also, it might be a good idea to create another account with passwordless sudo capabilities to allow for easier automatic configuration.
The method might sound a bit unconventional, but in GCP custom keys are added through metadata. More info can be found here All we need to do to try this out is generate a new SSH key and add a metadata entry to the compute instance, like this:
resource "google_compute_instance" "vm_instance" {
name = "terraform-instance"
machine_type = "f1-micro"
boot_disk {
initialize_params {
image = "debian-cloud/debian-9"
}
}
network_interface {
network = google_compute_network.vpc_network.name
access_config {
}
}
metadata = {
ssh-keys = "$USERNAME:$PASTE_PUBLIC_KEY_HERE"
}
}
Yes, it’s ugly. In case you’re wondering, if you want to do that for multiple users, the keys are in the same string, just in a new line. And regarding the passwordless sudo access, looks like it’s there by default, fun!
To finish up, run terraform destroy
to clean up whatever you created using it. No fuss, no forgotten VMs and similar, you run it and whatever is described in main.tf is gone!
Wrapping up
Today I learned the bare basics of Terraform. It seems pretty simple, the file format is easy to read and it’s not all that hard to set up. Provisioning a single VM wasn’t difficult at all and it seems like a very elegant way of keeping cloud infrastructure stored in code. I’m sure once it’s mastered, it also allows spinning up new environments very easily. I’m definitely looking forward to diving deeper into it.