본문 바로가기

Cloud/AZURE

Terraform on Azure [모듈화] - (4) VM & NSG 모듈

배포 계획

구조: Hub-Spoke 네트워크 모델
- Hub: 공통 인프라 구성 (VPN Gateway, Firewall 등)
- Spoke: 업무별 구분된 네트워크 (Web, WAS, DB 등 리소스 배치)

보안 구성
- NSG (Network Security Group): 각 Spoke VNet 및 서브넷에 할당
- VPN Gateway: Hub VNet에 배치
- Firewall: Hub VNet에 배치 및 UDR과 연동

리소스 그룹 구조
- RG-NETWORK – 가상 네트워크 및 서브넷 등 네트워크 리소스
- RG-SECURITY – NSG, Firewall, VPN 등 보안 리소스
- RG-COMPUTE – 가상 머신 등 컴퓨트 리소스
- RG-STORAGE – Storage Account 등 저장소 리소스

Tag 구성
- Key : Value 예시
- ResourceName : vm-web-prd-01 등
- ServiceType : WEB, WAS, DB 등
- Environment : PRD, QA, DEV
- DeploymentDate : 2025-05-07 등


1. VM 모듈

- main.tf

module "vm" {
  source   = "./modules/vm"
  location = var.location

  vm_map = {
    prd-web-01 = {
      name                = "prd-web-01"
      vm_size             = "Standard_B1s"
      admin_username      = "azureuser"
      admin_password      = "Azure123456!"
      resource_group_name = module.resource_groups.resource_group_names["compute"]
      subnet_id          = module.subnet.subnet_ids["prd_web"]
      location = var.location
      private_ip_address = "10.1.1.10"
      public_ip_name     = "prd-web-01-pip"
    }
  }
}

- variables.tf

variable "vm_map" {
  type    = map(any)
  default = {}
}

- 모듈 main.tf

variable "vm_map" {
  type    = map(any)
  default = {}
}


resource "azurerm_public_ip" "vm_pip" {
  for_each            = var.vm_map

  name                = each.value.public_ip_name
  location            = each.value.location
  resource_group_name = each.value.resource_group_name
  allocation_method   = "Static"
  sku                 = "Basic"

  tags = {
    ResourceName    = each.value.public_ip_name
    ServiceType     = "WEB"
    Environment     = "PRD"
    DeploymentDate  = "2025-05-07"
  }
}

resource "azurerm_network_interface" "vm_nic" {
  for_each                  = var.vm_map

  name                      = "${each.key}-nic"
  location                  = each.value.location
  resource_group_name       = each.value.resource_group_name

  ip_configuration {
    name                          = "internal"
    subnet_id                     = each.value.subnet_id
    private_ip_address_allocation = "Static"
    private_ip_address            = each.value.private_ip_address
    public_ip_address_id          = azurerm_public_ip.vm_pip[each.key].id
  }

  tags = {
    ResourceName    = "${each.key}-nic"
    ServiceType     = "WEB"
    Environment     = "PRD"
    DeploymentDate  = "2025-05-07"
  }
}

resource "azurerm_linux_virtual_machine" "vm" {
  for_each            = var.vm_map

  name                = each.value.name
  resource_group_name = each.value.resource_group_name
  location            = each.value.location
  size                = each.value.vm_size
  admin_username      = each.value.admin_username
  admin_password      = each.value.admin_password
  disable_password_authentication = false

  network_interface_ids = [
    azurerm_network_interface.vm_nic[each.key].id
  ]

  os_disk {
    name                 = "disk-${each.key}"
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "18.04-LTS"
    version   = "latest"
  }

  tags = {
    ResourceName    = each.value.name
    ServiceType     = "WEB"
    Environment     = "PRD"
    DeploymentDate  = "2025-05-07"
  }
}

variable "location" {
  description = "Location of the resources"
  type        = string
}

 

terraform validate를 통해 설정 유효성 검사

terraform plan을 통해 리소스 생성 계획 확인

terraform apply -auto-approve (yes 자동 입력 )

 

콘솔에서 리소스 배포 확인

 

2. NSG 모듈

- main.tf

module "nsg" {
  source = "./modules/nsg"

  nsgs = {
    prd_web_nsg = {
      name                = "nsg-prd-web-01"
      location            = var.location
      resource_group_name = module.resource_groups.resource_group_names["compute"]
      nic_id              = module.vm.nic_ids["prd-web-01"]
      tags = {
        ResourceName   = "nsg-prd-web-01"
        ServiceType    = "WEB"
        Environment    = "PRD"
        DeploymentDate = "2025-05-07"
      }
    }
  }
}

- 모듈 main.tf

resource "azurerm_network_security_group" "this" {
  for_each            = var.nsgs
  name                = each.value.name
  location            = each.value.location
  resource_group_name = each.value.resource_group_name

  security_rule {
    name                       = "Allow-HTTP"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "80"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }

  security_rule {
    name                       = "Allow-HTTPS"
    priority                   = 110
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "443"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }

  tags = each.value.tags
}

resource "azurerm_network_interface_security_group_association" "this" {
  for_each = var.nsgs

  network_interface_id      = each.value.nic_id
  network_security_group_id = azurerm_network_security_group.this[each.key].id
}

variable "nsgs" {
  description = "Map of NSG configs"
  type = map(object({
    name                = string
    location            = string
    resource_group_name = string
    nic_id              = string
    tags                = map(string)
  }))
  default = {}
}

- vm 모듈 main.tf

** nic 인터페이스용 nic id 필요 (output)

** vm nic를 다른 모듈(vm 모듈)에서 생성하고, nsg 모듈에서 nic의 ID를 참조해야하므로 nic output이 필요함. (같은 모듈내에서 생성하는 경우에는 output 불필요)

output "nic_ids" {
  value = { for k, nic in azurerm_network_interface.this : k => nic.id }
}

 

 

terraform validate를 통해 설정 유효성 검사

terraform plan을 통해 리소스 생성 계획 확인

terraform apply -auto-approve (yes 자동 입력 )