Azure - Infrastructure as Code using Terraform

Azure - Infrastructure as Code using Terraform

My trip through MTC's course.

I have been meaning to post about this project for a while - and want to immediately give props to Derek at More Than Certified. He has done an excellent job at creating content for personal projects, resume-builders, and walk-throughs on cloud platforms for folks interested in DevOps.

I found MTC and completed the AWS - Terraform implementation a couple of months ago, then he rolled his Azure course last month! As an Azure-saturated learner, this was an exciting drop for me so this is my personal reflection on that, with a slight adjustment here and there.

To check out Derek's course head to: morethancertified.com

Note: If you're in devops and working with multiple resources, tags are great. I support them - but in my steps here, I do not use tags. You'll see some of my stuff shows up with {} curly braces, as that's where tags should end up.

For this project, you will need:

An Azure account with an active subscription

a familiarity with Visual Studio Code

Terraform v 1.1.5

Azure connected to your VS Code (How-to video below)

docs to get started:

learn.hashicorp.com/tutorials/terraform/azu..

So without further adieu, allons-y!

We are going to start out with an install of the Azure CLI for our local environment which you can find here: docs.microsoft.com/en-us/cli/azure/install-.. or in PS:

$ Invoke-WebRequest -Uri https://aka.ms/installazurecliwindows -OutFile .\AzureCLI.msi; Start-Process msiexec.exe -Wait -ArgumentList '/I AzureCLI.msi /quiet'; rm .\AzureCLI.msi

ST1_INSTALL.png

Make sure you have your subscription linked to VS Code as mentioned in the pre-reqs. If you don't, there's a nice tutorial here.

Now let's open a new terminal from the menu, and choose PowerShell (should be default if you're a Windows user). Here we are going to enter

az login

to connect our account.

You should get a popup window in your favorite browser, confirming you're in (as I was already) or a code that you can enter in terminal to validate the session for VS Code.

ST3_azlogin.png

You can verify you're in by running

az confirm show

-if you just want to double check. You might also see you Azure email at the bottom left of the screen.

Once it's set up we're going to connect to Azure and set up the new Resource Group for our project. I named mine a misspelled version of Terraform. Goodtimes. ST2_CustomProjectRG.png

Now we are going to navigate to the extensions menu on VS Code, and grab a Terraform extension. I chose this preview version: ST3_TerraformAZPreviewfromMSFT.png

You can make sure you have Terraform installed by following instructions here. I already had installed Terraform for a previous project, and used Chocolately. The command for those chocolately users is

choco install terraform

Great, let's start the folder and file area up. To get the project ready, we should build a file structure:

ST4_NewFolder.png

and when you're back at your workspace in VS Code, you see our new project is ready for us to start adding Terraform files and making magic happen.

ST5_readyforproject.png

Terraform automatically creates certain items in this directory as you update and interface so don't be surprised when .hcl shows up, or other items pop-up in the menu. And, if you're new like me, don't alter any of it either. They can be neat to explore as you build -to see how those files change, however. Derek does a great job of walking through some of that in the course.

Now that we have Terraform, the CLI, and Azure integrated into our VS Code, we can start the Terraform builds. To start our project we add a "main" file under the project menu: ST6_mainfile_build.png

We can specify the version, source, and other options while identifying the required arguments here. You'll also need the new (or old Resource Group name and region you set) you created here at a later time.

Next we will run

terraform init

and you'll get some nice green letters when it works correctly: ST7_terraform_init_screen.png

you can run

terraform fmt

to format (prettify) your code (clean it up) or

terraform validate

to confirm your code will be successful upon execution if ever you want to QC your main.tf updates

You should take of your documents area by now, note we have stored everything locally, as you see the new terraform.lock.hcl (which maintains your version) in your project folder. This is a compiled file and the windows file that communicates with Azure's API.

Next, we run

terraform plan

which shows what will be built if you run this script... I then run

terraform apply -auto-approve

since you just saw the plan, in preview.

ST8_terraform_apply.png The screen should look a lot like this. Even more if you have dark mode enabled.

You can check your work in the Azure portal or run

terraform show

in the terminal to see information for your project.

Next, we add the virtual network. Something like,

resource "azurerm_virtual_network" "vnet" {
      + address_space         = [
          + "10.123.0.0/16",

ST9_terraform_vnet_addition.png then run

terraform plan

&

terraform apply

[[I should mention here that if you run into issues anytime with "no changes" when you run "plan", then you probably just need to go back and save your file. I definitely forget this when going in increments but a best-practice is "Save", "terraform plan", then apply]]

Additionally, anytime you want to know what's in your resource group in terraform; try

terraform state list

or

terraform state show resource_group_name

(shows that rg) or you can still run

terraform show

to see it all.

Now, let's add our subnet:

ST11_add_subnet.png

Again, always save your file, then run

terraform fmt

to format your file, and notice if there are any errors. Here, I was missing an "=" after group name so I went back and cleaned that up.

Run

terraform plan

again to see how it works, and if like me - you misnamed virtual network name, update it, save and, run

terraform apply --auto approve

(& this may take a minute or so)

ST12_fixed_subnet.png

Once complete run

terraform state list

to view your resources:

ST13_terraform_statelist_result.png

Now comes the big money - we are going to add in the network security group. Here are some resources: registry.terraform.io/providers/hashicorp/a.. registry.terraform.io/providers/hashicorp/a..

We set up the nsg and rules to allow inbound traffic to connect to it, and will use an asterisk to denote "any". In the source IP address add your public ip address (shh, it's private). If you don't know your IP, https://www.whatsmyip.org/ will give it to you. ST14_nsg_setup.png

You can also add your security group association here to protect our subnet, just a couple of lines: ST15_nsg_sga.png

Then do the save, fmt, plan, apply shuffle. And let's run

terraform state list

to see our resources. Here's what I had so far: ST16_state_list_checkpt.png

Now we are going to sort-of imply a public IP, but adding a dynamic IP address won't actually occur until the NICis attached to a resource (a VM, later).
ST18_public_nic-tf.png

Going to dump some photos of the next steps here:

ST17_pub-ip.png

ST19_public_ip_creation.png

ST20_state_list_checkpt.png

Okay, so we've got the network ready. Now we can get something to connect to. We add a VM:

This will include the VM resource, an SSH key, an OS Disk and then an actual OS. My favorite part. And let's stick with Linux.

I used i used TF's GH repo for an Ubuntu Server OS and made some minor changes.

You'll definitely want to change "caching" to "ReadOnly" because the ephemeral OS disk doesn't permit readwrite, as is in the GH. You can read more about that here, if you're curious.

ST21_planning_the_VM_inTerminal.png

Save, fmt, plan, apply! Again!! Then maybe wait a few minutes for it to deploy and

clear

your terminal cause that's a lot to handle.

Next, create your SSH key

ssh-keygen -t rsa

and save it in the same directory, just rename it to something nice and fancy.

"C:\Users\you/.ssh/bacon"

then add your passphrase (or don't), I'm sure it's fine.

Verify your key was made by checking the list of files in .ssh:

ST22_verifyKey_withls.png

Your key now needs to get called into the VM somewhere so: Add the key pair you just made somewhere in your VM's code: (we get to use TF's file function here)

admin_ssh_key {
    username   = "adminuser"
    public_key = file("~/.ssh/yourkeyname.pub")
  }

ST23_adding_they_key.png

Here we can get your IP address! run

terraform state list

again then copy that new resource, and try running

terraform state show new_linux_vm_name

ST24_list_then_show_IP.png

ssh -i ~/ssh/keyname adminuser@the.public.ip.address

Once you ssh using the above code (and the public ip address now in your file), you can confirm the addition of the certificate, and see yourself logged in as the username you made during the addition of the vm.

You're in like Flynn!

ST26_userloggedin.png

You can also try adding docker using the customdata template terraform.io/language/functions/file

#!/bin/bash
sudo apt-get update -y &&
sudo apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common &&
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - &&
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" &&
sudo apt-get update -y &&
sudo sudo apt-get install docker-ce docker-ce-cli containerd.io -y &&
sudo usermod -aG docker adminuser

ST27_added_docker_customdata.png

ST28_newSSH.png

ST29_run_dockerver.png

You'll also get to reinstall your VM and practice finding your IP, and SSHing again in this tutorial once you update that Docker installation.

Then you need to fmt, plan (yes, 1 will be destroyed as the VM will be redployed), and apply! It will take a min, grab a cookie.

After you eat your Oreos and your VM has redeployed, we are going to have a new IP address so let's run

terraform state list

and grab the Linux vm name again then

terraform state show vm-name

So we are then gonna get back in via our new IP address with the ssh from above, and we can recheck the Docker version with

docker --version

I went off-script & added some threat intelligence from Terraform's library.

And then I returned to add data sources, with the following:

data "azurerm_public_ip" "pip-data" {
    name = azurerm_public_ip.pip.name
}

You know the drill: we then fmt, save, plan and try

terraform apply -refresh-only
``` if you didn't fall asleep.

enter yes
and run another

state list ``` & we have data!

ST32_terraform-refresh-data.png

This deployed threat watcher on my resource group, which was cool, and a step off of Derek's tutorial.

defender_analytics_Azure_Screen.png

I did add the remote and config tools from the tutorial:

ST30_ssh_extension.png

but I also opted for the other implementations for practice.

Another great run through from More Than Certified!

Alternate journeys: Outputs

Add other applications, libraries, whatever you need to make the development environment yours!

Derek suggests setting up a repository and configuring it to work with your remote instance if you completed that portion, which sounds very DevCool.