############################################################
# 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"
}