Implement Azure Bastion Host through Terraform

BRK0018
7 min readJun 17, 2022

Let’s implement ‘Azure Bastion’ through Terraform as part of our Terraform hands-on scenarios/series

Do you already know what is ‘Azure Bastion’ ? if not, please refer here for details

Let’s first look at our Architecture diagram shown below to understand what all is needed for the successful implementation

In order to achieve the above, we need to first break down in to small steps— Let’s do that now as shown below

Build the basic Terraform Folder Structure

  • Create a folder named Az_Bastion_Laband ensure to follow and implement ‘Pre-requisites’ , 2nd and 3rd sections of my previous blog before proceeding to the next steps
  • Configure the backend.tf accordingly in that folder which is used to store the Terraform State remotely in the respective Azure Storage Account/Container
backend.tf
  • Create provider.tf in the same folder and have the below code which helps to configure infrastructure in Microsoft Azure platform. If you are wondering what are those under key_vault section, feel free to refer my previous blog which covers the explanation
provider.tf
  • Create variables.auto.tfvars having the default declared values like below. We defined address spaces for VNet, Subnet and also for AzureFirewallSubnet as per the needs shown in the architecture above. firewall_allocation_method and firewall_sku will be consumed for building virtual_networks in the later section and definedscale_units as 2 for AzureBastionHost for later use as well
variables.auto.tfvars
  • Create variables.tf like below
variables.tf
  1. Create a Resource Group
  • Files rg_main.tf, rg_variables.tf, rg_outputs.tf look like below. We’ve already covered the explanation of how to create Resource Groups using Terraform in our previous blogs. Hence, avoiding the duplication of explanation here but showing the code necessary for implementing this scenario [Similarly, I’ll not repeat explaining the VNets, KV and all other modules which we’ve covered in our previous blog/s. Feel free to refer them if required here and here as appropriate]
main.tf Snippet_1
rg_variables.tf
rg_main.tf
rg_outputs.tf

2. Create a VNet and a Subnet in that Resource Group

vnet_main.tf
  • Apart from the VNet and Subnet, we are creating a Network Interface for our LinuxVM so that Private IP can be assigned to it
vnet_variables.tf
vnet_outputs.tf
  • Now, our main.tf looks like below
main.tf Snippet_2
  • Now perform terraform init, terraform plan and terraform apply --auto-approve one after the other successful command execution. Feel free to make use ofterraform validate and terraform fmt commands in between
  • You should be able to see the VNet, and Subnet in the respective RG in the portal

3. Create Azure Bastion Host and necessary components required

  • For a successful, Bastion Host deployment, we should create a subnet with name AzureBastionSubnet and assign a public ip to it as well. Let’s do it now
  • Create a folder az_bastion under modules and have the azb_main.tf, azb_variables.tf and azb_outputs.tf files as shown below
azb_main.tf
  • You can notice that with azb_main.tf, we are creating the AzureBastionSubnet subnet, azure publicIp and Azure Bastion Host which uses the subnet and the public-ip we created. You may notice some warning/error messages in your code as some variables like location, rg-test-name are not yet declared under az_bastion module. We’ll fix those issues in our next step with azb_variables.tf
azb_variables.tf
  • We need resources such as public-Ip and AzureFirewallSubnet-id for our other module consumption hence they are mentioned in azb_outpputs.tf as below
azb_outputs.tf
  • Now, time to call this az_bastionmodule from main.tf
main.tf Snippet_3
  • Now perform terraform init, terraform plan and terraform apply --auto-approve one after the other successful command execution.
  • You should be able to see the intended resources in the Azure Portal successfully

4. Use Azure Key Vault and create Secret for the LinuxVM

kv_main.tf Snippet_1
kv_main.tf Snippet_2
kv_variables.tf
kv_outputs.tf
  • Let’s call the az_key_vault module from the main.tf
main.tf Snippet_4
  • Now perform terraform init, terraform plan and terraform apply --auto-approve one after the other successful command execution.
  • You should be able to see the intended resources including the KV in the Azure Portal successfully

5. Create the LinuxVM

  • We’ll create the LinuxVM and assign the NIC we created before during virtual_networks module to this VM
vm_main.tf
vm_variables.tf
vm_outputs.tf
  • Let’s call the vm module from the main.tf
main.tf Snippet_5
  • Now perform terraform init, terraform plan and terraform apply --auto-approve one after the other successful command execution.
  • You should be able to see the intended resources including the VM in the Azure Portal successfully

6. Define the NSG Rules for AzureBastionHost and also for LinuxVM

  • Before proceeding further, I strongly recommend you to read through this excellent documentation from Microsoft explaining the NSG needs for the Bastion
  • We should define NSG rules for both Ingress and Egress traffic from/to the Bastion and also Ingress traffic rules for the Linux VM
  • Recommended Ingress and Egress rules are like below for Bastion
Ingress [INBOUND] for Bastion
Egress [OUTBOUND] for Bastion
  • In order to implement the above NSG rules, let’s define traffic_rules module and implement the rules accordingly
rules_main.tf Snippet_1
rules_main.tf Snippet_2
rules_main.tf Snippet_3
  • Now, associate the NSG defined to the subnet AzureBastionSubnet like below
rules_main.tf Snippet_4
  • Define NSG rule for LinuxVM and associate it to the NIC [You can also associate it with the subnet in which this VM is present like vnet1-subnet1 in case if you want to try that option. I suggest you to understand what difference it makes associating it with the NIC vs Subnet]
rules_main.tf Snippet_5

[When the file contains many lines, it is not feasible to show in one shot and explain at the same time, hence I’ve divided them in to multiple snippets such as rules_main.tf Snippet_*, where * represents numbering like 1,2,3 and so on.... I believe that allows you to follow the sequence of code accordingly. Same is true for files such as main.tf. You can notice that as main.tf Snippet_*]

rules_variables.tf
  • We don’t really have anything from the traffic_rules module to output. Hence, rules_outputs.tf is blank and it just sits there idle for the terraform schema/structure purpose
  • Finally, your Terraform folder structure looks like below for your visibility [Please ignore images folderand .md file ]
Az_Bastion_Lab folder structure

7. Deploy and Validate the Infrastructure

  • Now perform terraform init, terraform plan and terraform apply --auto-approve one after the other successful command execution. I encourage you to also use terraform validate and terraform fmt commands and fix any errors by following the blog carefully
  • With this, the deployment of resources is complete can be observed in your Azure Portal
All the Resources under the RG
  • Connect to the LinuxVM using Bastion with username and the secret like below
Connect to LinuxVM using Bastion
  • After successful login, you can access the LinuxVM as shown below
LinuxVM after successful login

Finally perform terraform destroy --auto-approve to destroy all the resources in the Azure Portal to free up consuming the $

Hope you find this information helpful.

Thanks for taking time to read!

--

--

BRK0018

Human being First, followed by A Husband and A Father of Two Smiles — Rest is the Magic!