############################################################
# PROVIDER
# This tells Terraform which cloud provider we are using.
# azurerm = Azure Resource Manager API
############################################################
provider "azurerm" {
features {}
# prevents terraform from auto-registering every Azure service
resource_provider_registrations = "none"
}
############################################################
# RESOURCE GROUP
# Resource groups are containers that hold Azure resources.
# Everything we create will live inside this group.
############################################################
resource "azurerm_resource_group" "rg" {
name = var.resource_group_name
location = var.location
}
############################################################
# VIRTUAL NETWORK (VNet)
# This creates a private network in Azure.
# Think of it like your own internal datacenter network.
############################################################
resource "azurerm_virtual_network" "vnet" {
name = "terraform-vnet"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
# CIDR block for the network
address_space = ["10.0.0.0/16"]
}
############################################################
# SUBNET
# A subnet divides the VNet into smaller networks.
# VMs get private IPs from this subnet.
############################################################
resource "azurerm_subnet" "subnet" {
name = "internal"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
# 256 IP addresses (Azure reserves 5 → 251 usable)
address_prefixes = ["10.0.1.0/24"]
}
############################################################
# PUBLIC IP
# This creates a public internet address.
# It will later be attached to the network interface.
############################################################
resource "azurerm_public_ip" "pip" {
name = "terraform-pip"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
allocation_method = "Static" # IP stays the same
sku = "Standard" # recommended modern tier
}
############################################################
# NETWORK INTERFACE (NIC)
# A NIC acts like a network card for the VM.
# The VM connects to the NIC, not directly to the subnet.
############################################################
resource "azurerm_network_interface" "nic" {
name = "terraform-nic"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
ip_configuration {
name = "internal"
# connect NIC to subnet
subnet_id = azurerm_subnet.subnet.id
# Azure automatically assigns private IP
private_ip_address_allocation = "Dynamic"
# attach public internet IP
public_ip_address_id = azurerm_public_ip.pip.id
}
}
############################################################
# NETWORK SECURITY GROUP (NSG)
# This is Azure's firewall.
# It controls which traffic is allowed in/out.
############################################################
resource "azurerm_network_security_group" "nsg" {
name = "terraform-nsg"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
# Allow SSH access from the internet
security_rule {
name = "SSH"
priority = 1000
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
############################################################
# ATTACH NSG TO SUBNET
# This applies the firewall rules to the subnet.
# All resources in this subnet inherit these rules.
############################################################
resource "azurerm_subnet_network_security_group_association" "assoc" {
subnet_id = azurerm_subnet.subnet.id
network_security_group_id = azurerm_network_security_group.nsg.id
}
############################################################
# VIRTUAL MACHINE
# This creates the actual Ubuntu server.
############################################################
resource "azurerm_linux_virtual_machine" "vm" {
name = var.vm_name
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
size = "Standard_B1ls" # VM size (CPU + RAM)
zone = "2" # availability zone
admin_username = var.admin_name
# attach NIC to the VM
network_interface_ids = [
azurerm_network_interface.nic.id
]
# SSH authentication
admin_ssh_key {
username = var.admin_name
public_key = file("~/.ssh/id_ed25519_main.pub")
}
# OS disk configuration
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
# Ubuntu image to install
source_image_reference {
publisher = "Canonical"
offer = "ubuntu-24_04-lts"
sku = "server"
version = "latest"
}
}
############################################################
# OUTPUT
# After deployment Terraform prints the VM's public IP
############################################################
output "vm_public_ip" {
value = azurerm_public_ip.pip.ip_address
}variable.tf
variable "location" {
description = "Azure region"
type = string
default = "centralindia"
}
variable "resource_group_name" {
description = "Resource group name"
type = string
default = "terraform-vm-rg"
}
variable "vm_name" {
description = "Name of vm"
type = string
default = "terraform-vm"
}
variable "admin_name" {
description = "Name of admin"
type = string
default = "light"
}