-
Notifications
You must be signed in to change notification settings - Fork 0
Home
The Terraform Azure VM Automation project demonstrates how to automate the deployment of a virtual machine (VM) in Azure using Terraform. This project aims to showcase Infrastructure as Code (IaC) principles and how to manage cloud resources efficiently. The project includes automated deployment scripts, Terraform configuration files, and examples of outputs for easy management and scalability of Azure resources.
Before you begin, ensure you have the following installed:
- Terraform: Install Terraform
- Azure CLI: Install Azure CLI
- Git: Install Git
- PowerShell: Available by default on Windows; for other operating systems, download from Microsoft.
terraform-azure-vm-automation/
│
├── main.tf
├── variables.tf
├── outputs.tf
├── terraform.tfvars
├── git-init-push.ps1
├── tf-init-apply.ps1
├── tf-destroy.ps1
├── LICENSE
├── .gitignore
├── photos
│ ├── social_preview.jpg
│ ├── graph.png
│ ├── NetworkWatcherRG.png
└── README.md
This file contains the core configuration for provisioning resources in Azure. It includes the setup for the resource group, virtual network, subnet, network interface, and virtual machine.
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 3.105.0" # The operator >= programmatically states “greater than or equal to” in code.
}
}
}
provider "azurerm" {
features {
resource_group {
prevent_deletion_if_contains_resources = false # This if required
}
}
}
resource "azurerm_resource_group" "autoazvm-dev-rg" {
name = var.resource_group_name
location = var.location
tags = var.tags
}
# Below starts critical resources for this Project
resource "azurerm_virtual_network" "autoazvm-dev-vnet" {
name = var.azurerm_virtual_network
resource_group_name = var.resource_group_name # azure_resource_group.autoazvm-test-rg.name is an alternate. Ref: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_machine
location = var.location # azurerm_resource_group.autoazvm-test-rg.location is an alternate. Ref: ""
address_space = ["10.0.0.0/16"]
depends_on = [azurerm_resource_group.autoazvm-dev-rg]
}
# Location selection via portal is mandatory, not in here!
resource "azurerm_subnet" "autoazvm-dev-subnet" {
name = var.azurerm_subnet
resource_group_name = var.resource_group_name
virtual_network_name = var.azurerm_virtual_network
address_prefixes = ["10.0.1.0/24"]
}
resource "azurerm_network_interface" "autoazvm-dev-ni" {
name = var.network_interface_name
resource_group_name = var.resource_group_name
location = var.location
ip_configuration { # Mandatory
name = var.ip_configuration # verify name after deployment
subnet_id = azurerm_subnet.autoazvm-dev-subnet.id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_virtual_machine" "autoazvm-dev-vm" {
name = var.azurerm_virtual_machine
location = var.location
resource_group_name = var.resource_group_name
network_interface_ids = [azurerm_network_interface.autoazvm-dev-ni.id] # alternate to add all the NIC --> azurevm_network_interface.autoazvm-dev-ni.*.id
vm_size = var.vm_size
storage_os_disk {
name = var.storage_os_disk
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
# Handy command: az vm image list --output table
# Handy ref: https://learn.microsoft.com/en-us/azure/virtual-machines/linux/cli-ps-findimage#code-try-3
storage_image_reference {
publisher = "Canonical"
offer = "0001-com-ubuntu-server-jammy"
sku = "22_04-lts-gen2"
version = "latest"
}
os_profile {
computer_name = var.computer_name
admin_username = var.admin_username
admin_password = var.admin_password
}
os_profile_linux_config {
disable_password_authentication = false # being a test and short-lived environment with password verified, this is set to false.
}
tags = var.tags
}
This file defines the variables used in the Terraform configuration and uses terraform.tfvars
to specify values, making it easy to customize the deployment environment by changing variable values.
variable "resource_group_name" {
description = "The name of the resource group"
}
# Location variable is referenced in multiple resources. ADD New if I want resources to be provisioned in different regions.
# az account list-locations -o table to Get Azure Regions
variable "location" {
description = "The Azure region in which resources will be provisioned"
}
variable "azurerm_virtual_network" {
description = "The name of the Virtual Network"
}
variable "azurerm_subnet" {
description = "The name of the Subnet"
}
variable "network_interface_name" {
description = "The name of the network interface"
}
variable "ip_configuration" {
description = "The name of the IP Configuration resource"
}
variable "azurerm_virtual_machine" {
description = "The name of the Virtual Machine"
}
variable "vm_size" {
description = "The size of the Virtual Machine"
}
variable "storage_os_disk" {
description = "The name of the Storage OS disk"
}
variable "computer_name" {
description = "The HOSTNAME"
}
variable "admin_username" {
description = "The admin username"
}
variable "admin_password" {
description = "The admin password"
}
variable "tags" {
type = map(string)
}
This file defines the outputs of the Terraform configuration, providing useful information about the deployed resources.
# I personally prefer using below syntax:
output "resource_group_name" {
value = azurerm_resource_group.autoazvm-test-rg.name
}
output "virtual_network_name" {
value = azurerm_virtual_network.autoazvm-test-rg-vnet.name
}
output "subnet_id" {
value = azurerm_subnet.autoazvm-test-rg-subnet.id
}
output "network_interface_ids" {
value = azurerm_network_interface.autoazvm-test-rg-ni.id
}
output "virtual_machine_name" {
value = azurerm_virtual_machine.autoazvm-test-rg-vm.name
}
This script initializes a Git repository, adds a remote origin, commits changes, and pushes to the remote repository. The script works uninterrupted if the GitHub repository is already created and the script is updated accordingly.
# Check if .git directory exists
$gitInitialized = Test-Path -Path ".git" -PathType Container
if (-not $gitInitialized) {
# Git is not initialized, perform git init
git init
}
# Check if remote 'origin' already exists
$remoteExists = git remote get-url origin 2>$null
if (-not $remoteExists) {
# Remote 'origin' does not exist, add it
git remote add origin https://github.com/yourusername/terraform-azure-vm-automation
}
# Add files and commit changes
git add .
$commitMessage = Read-Host -Prompt 'Enter commit message'
git commit -m "$commitMessage"
# Push changes to remote 'origin'
git push
This script initializes Terraform, validates the configuration, plans the deployment, and applies the changes. In addition, it takes a backup of the .tfstate and tfplan with an opportunity to creat the Graph.
terraform fmt
az login
<# Set the desired subscription
az account set --subscription "YOUR_SUBSCRIPTION_ID_OR_NAME" #>
terraform init
terraform validate
terraform plan -out='tfplan.out'
terraform apply -auto-approve tfplan.out
terraform state list
terraform show
terraform graph > graph.dot
This script destroys the Terraform-managed infrastructure. Except NetworkWatcherRG, please refer my Key Learnings here
terraform plan -destroy -out="planout"
terraform apply "planout"
- network_interface_name: I encountered issues when trying to reference a map {} directly. I resolved this by creating a separate variable.
- network_interface_ids: This parameter expects a list of strings. I addressed this by inserting as array[].
-
azurerm_virtual_network: The virtual network resource was being prioritized before the resource group creation, causing failures. I fixed this by adding a
depends_on
clause to ensure it waits for the resource group. - NetworkWatcherRG: Upon successful deployment, a new resource group named NetworkWatcherRG is automatically created as part of Azure's network monitoring service as shown in below image, which is currently free. This occurs because the configuration includes networking components such as VNET, SUBNET, and NI. This new resource group can be manually deleted or disabled for the deployed resource's region. Reference.
-
Disable Password Authentication: Update the
os_profile_linux_config
todisable_password_authentication = true
for better security and configure SSH keys for VM access. - Secret Management: Move sensitive information such as admin passwords to a secure secret management system like Azure Key Vault.
- Scalability: Enhance the configuration to support deployment of multiple VMs and additional Azure resources such as databases and load balancers.
Feel free to fork this repository and submit pull requests. For major changes, please open an issue first to discuss what you would like to change. I have started a discussion, and everyone can bring ideas there.
Thanks to the Terraform and Azure documentation teams for their extensive resources and examples. This project was inspired by the need to automate and efficiently manage cloud infrastructure.