Compartir a través de


Inicio rápido: Creación de una instancia de Azure Firewall con varias IP públicas: Terraform

En este inicio rápido, usará Terraform para implementar una instancia de Azure Firewall con varias IP públicas a partir de un prefijo de IP pública. El firewall implementado tiene reglas de recopilación de reglas NAT que permiten conexiones RDP a dos máquinas virtuales Windows Server 2019.

Terraform habilita la definición, vista previa e implementación de la infraestructura en la nube. Con Terraform, se crean archivos de configuración mediante la sintaxis de HCL. La sintaxis de HCL permite especificar el proveedor de la nube, como Azure, y los elementos que componen la infraestructura de la nube. Después de crear los archivos de configuración, se crea un plan de ejecución que permite obtener una vista previa de los cambios de infraestructura antes de implementarlos. Una vez que compruebe los cambios, aplique el plan de ejecución para implementar la infraestructura.

Para más información acerca de Azure Firewall con varias direcciones IP públicas, consulte Implementación de una instancia de Azure Firewall con varias direcciones IP públicas mediante Azure PowerShell.

En este artículo aprenderá a:

Requisitos previos

Implementación del código de Terraform

  1. Cree un directorio en el que probar el código de ejemplo de Terraform y conviértalo en el directorio actual.

  2. Cree un archivo denominado providers.tf e inserte el siguiente código:

    terraform {
      required_providers {
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "~>3.0"
        }
        random = {
          source  = "hashicorp/random"
          version = "~>3.0"
        }
      }
    }
    
    provider "azurerm" {
      features {
        virtual_machine {
          delete_os_disk_on_deletion     = true
          skip_shutdown_and_force_delete = true
        }
      }
    }
    
  3. Cree un archivo denominado main.tf e inserte el siguiente código:

    resource "random_pet" "rg_name" {
      prefix = var.resource_group_name_prefix
    }
    
    resource "random_password" "password" {
      count       = 2
      length      = 20
      min_lower   = 1
      min_upper   = 1
      min_numeric = 1
      min_special = 1
      special     = true
    }
    
    resource "azurerm_resource_group" "rg" {
      name     = random_pet.rg_name.id
      location = var.resource_group_location
    }
    
    resource "azurerm_public_ip_prefix" "pip_prefix" {
      name                = "pip-prefix"
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
      sku                 = "Standard"
      prefix_length       = 31
    }
    
    resource "azurerm_public_ip" "pip_azfw" {
      name                = "pip-azfw"
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
      sku                 = "Standard"
      allocation_method   = "Static"
      public_ip_prefix_id = azurerm_public_ip_prefix.pip_prefix.id
    }
    
    resource "azurerm_public_ip" "pip_azfw_2" {
      name                = "pip-azfw-1"
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
      sku                 = "Standard"
      allocation_method   = "Static"
      public_ip_prefix_id = azurerm_public_ip_prefix.pip_prefix.id
    }
    
    resource "azurerm_virtual_network" "azfw_vnet" {
      name                = "azfw-vnet"
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
      address_space       = ["10.10.0.0/16"]
    }
    
    resource "azurerm_subnet" "azfw_subnet" {
      name                 = "AzureFirewallSubnet"
      resource_group_name  = azurerm_resource_group.rg.name
      virtual_network_name = azurerm_virtual_network.azfw_vnet.name
      address_prefixes     = ["10.10.0.0/26"]
    }
    
    resource "azurerm_subnet" "backend_subnet" {
      name                 = "subnet-backend"
      resource_group_name  = azurerm_resource_group.rg.name
      virtual_network_name = azurerm_virtual_network.azfw_vnet.name
      address_prefixes     = ["10.10.1.0/24"]
    }
    
    resource "azurerm_network_interface" "backend_nic" {
      count               = 2
      name                = "nic-backend-${count.index + 1}"
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
    
      ip_configuration {
        name                          = "ipconfig-backend-${count.index + 1}"
        subnet_id                     = azurerm_subnet.backend_subnet.id
        private_ip_address_allocation = "Dynamic"
      }
    }
    
    resource "azurerm_network_security_group" "backend_nsg" {
      name                = "nsg-backend"
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
      security_rule {
        name                       = "RDP"
        priority                   = 300
        direction                  = "Inbound"
        access                     = "Allow"
        protocol                   = "Tcp"
        source_port_range          = "*"
        destination_port_range     = "3389"
        source_address_prefix      = "*"
        destination_address_prefix = "*"
      }
    }
    
    resource "azurerm_network_interface_security_group_association" "vm_backend_nsg_association" {
      count                     = 2
      network_interface_id      = azurerm_network_interface.backend_nic[count.index].id
      network_security_group_id = azurerm_network_security_group.backend_nsg.id
    }
    
    resource "azurerm_windows_virtual_machine" "vm_backend" {
      count                 = 2
      name                  = "vm-backend-${count.index + 1}"
      resource_group_name   = azurerm_resource_group.rg.name
      location              = azurerm_resource_group.rg.location
      size                  = var.virtual_machine_size
      admin_username        = var.admin_username
      admin_password        = random_password.password[count.index].result
      network_interface_ids = [azurerm_network_interface.backend_nic[count.index].id]
      os_disk {
        caching              = "ReadWrite"
        storage_account_type = "Standard_LRS"
      }
      source_image_reference {
        publisher = "MicrosoftWindowsServer"
        offer     = "WindowsServer"
        sku       = "2019-Datacenter"
        version   = "latest"
      }
    }
    
    resource "azurerm_firewall_policy" "azfw_policy" {
      name                     = "azfw-policy"
      resource_group_name      = azurerm_resource_group.rg.name
      location                 = azurerm_resource_group.rg.location
      sku                      = var.firewall_sku_tier
      threat_intelligence_mode = "Alert"
    }
    
    resource "azurerm_firewall_policy_rule_collection_group" "policy_rule_collection_group" {
      name               = "RuleCollectionGroup"
      firewall_policy_id = azurerm_firewall_policy.azfw_policy.id
      priority           = 300
      application_rule_collection {
        name     = "web"
        priority = 100
        action   = "Allow"
        rule {
          name = "wan-address"
          protocols {
            type = "Http"
            port = 80
          }
          protocols {
            type = "Https"
            port = 443
          }
          destination_fqdns = ["getmywanip.com"]
          source_addresses  = ["*"]
        }
        rule {
          name = "google"
          protocols {
            type = "Http"
            port = 80
          }
          protocols {
            type = "Https"
            port = 443
          }
          destination_fqdns = ["www.google.com"]
          source_addresses  = ["10.10.1.0/24"]
        }
        rule {
          name = "wupdate"
          protocols {
            type = "Http"
            port = 80
          }
          protocols {
            type = "Https"
            port = 443
          }
          destination_fqdn_tags = ["WindowsUpdate"]
          source_addresses      = ["*"]
        }
      }
      nat_rule_collection {
        name     = "Coll-01"
        action   = "Dnat"
        priority = 200
        rule {
          name                = "rdp-01"
          protocols           = ["TCP"]
          translated_address  = "10.10.1.4"
          translated_port     = "3389"
          source_addresses    = ["*"]
          destination_address = azurerm_public_ip.pip_azfw.ip_address
          destination_ports   = ["3389"]
        }
        rule {
          name                = "rdp-02"
          protocols           = ["TCP"]
          translated_address  = "10.10.1.5"
          translated_port     = "3389"
          source_addresses    = ["*"]
          destination_address = azurerm_public_ip.pip_azfw.ip_address
          destination_ports   = ["3389"]
        }
      }
    }
    
    resource "azurerm_firewall" "fw" {
      name                = "azfw"
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
      sku_name            = "AZFW_VNet"
      sku_tier            = var.firewall_sku_tier
      ip_configuration {
        name                 = "azfw-ipconfig"
        subnet_id            = azurerm_subnet.azfw_subnet.id
        public_ip_address_id = azurerm_public_ip.pip_azfw.id
      }
      ip_configuration {
        name                 = "azfw-ipconfig-2"
        public_ip_address_id = azurerm_public_ip.pip_azfw_2.id
      }
      firewall_policy_id = azurerm_firewall_policy.azfw_policy.id
    }
    
    resource "azurerm_route_table" "rt" {
      name                          = "rt-azfw-eus"
      location                      = azurerm_resource_group.rg.location
      resource_group_name           = azurerm_resource_group.rg.name
      disable_bgp_route_propagation = false
      route {
        name                   = "azfw"
        address_prefix         = "0.0.0.0/0"
        next_hop_type          = "VirtualAppliance"
        next_hop_in_ip_address = "10.10.0.4"
      }
    }
    
    resource "azurerm_subnet_route_table_association" "jump_subnet_rt_association" {
      subnet_id      = azurerm_subnet.backend_subnet.id
      route_table_id = azurerm_route_table.rt.id
    }
    
  4. Cree un archivo denominado variables.tf e inserte el siguiente código:

    variable "resource_group_location" {
      type        = string
      description = "Location for all resources."
      default     = "eastus"
    }
    
    variable "resource_group_name_prefix" {
      type        = string
      description = "Prefix for the Resource Group Name that's combined with a random id so name is unique in your Azure subcription."
      default     = "rg"
    }
    
    variable "firewall_sku_tier" {
      type        = string
      description = "Firewall SKU."
      default     = "Premium" # Valid values are Standard and Premium
      validation {
        condition     = contains(["Standard", "Premium"], var.firewall_sku_tier)
        error_message = "The SKU must be one of the following: Standard, Premium"
      }
    }
    
    variable "virtual_machine_size" {
      type        = string
      description = "Size of the virtual machine."
      default     = "Standard_D2_v3"
    }
    
    variable "admin_username" {
      type        = string
      description = "Value of the admin username."
      default     = "azureuser"
    }
    
  5. Cree un archivo denominado outputs.tf e inserte el siguiente código:

    output "resource_group_name" {
      value = azurerm_resource_group.rg.name
    }
    output "backend_admin_password" {
      sensitive = true
      value     = azurerm_windows_virtual_machine.vm_backend[*].admin_password
    }
    

Inicialización de Terraform

Para inicializar la implementación de Terraform, ejecute terraform init. Este comando descarga el proveedor de Azure necesario para administrar los recursos de Azure.

terraform init -upgrade

Puntos clave:

  • El parámetro -upgrade actualiza los complementos de proveedor necesarios a la versión más reciente que cumpla con las restricciones de versión de la configuración.

Creación de un plan de ejecución de Terraform

Ejecute terraform plan para crear un plan de ejecución.

terraform plan -out main.tfplan

Puntos clave:

  • El comando terraform plan crea un plan de ejecución, pero no lo ejecuta. En su lugar, determina qué acciones son necesarias para crear la configuración especificada en los archivos de configuración. Este patrón le permite comprobar si el plan de ejecución coincide con sus expectativas antes de realizar cambios en los recursos reales.
  • El parámetro -out opcional permite especificar un archivo de salida para el plan. El uso del parámetro -out garantiza que el plan que ha revisado es exactamente lo que se aplica.

Aplicación de un plan de ejecución de Terraform

Ejecute terraform apply para aplicar el plan de ejecución a su infraestructura en la nube.

terraform apply main.tfplan

Puntos clave:

  • El comando terraform apply de ejemplo asume que ejecutó terraform plan -out main.tfplan previamente.
  • Si especificó un nombre de archivo diferente para el parámetro -out, use ese mismo nombre de archivo en la llamada a terraform apply.
  • Si no ha utilizado el parámetro -out, llame a terraform apply sin ningún parámetro.

Verificación de los resultados

  1. Obtenga el nombre del grupo de recursos de Azure.

    resource_group_name=$(terraform output -raw resource_group_name)
    
  2. Ejecute az network ip-group list para mostrar los dos nuevos grupos de IP.

    az network ip-group list --resource-group $resource_group_name
    

Limpieza de recursos

Cuando ya no necesite los recursos creados a través de Terraform, realice los pasos siguientes:

  1. Ejecute el comando terraform plan y especifique la marca destroy.

    terraform plan -destroy -out main.destroy.tfplan
    

    Puntos clave:

    • El comando terraform plan crea un plan de ejecución, pero no lo ejecuta. En su lugar, determina qué acciones son necesarias para crear la configuración especificada en los archivos de configuración. Este patrón le permite comprobar si el plan de ejecución coincide con sus expectativas antes de realizar cambios en los recursos reales.
    • El parámetro -out opcional permite especificar un archivo de salida para el plan. El uso del parámetro -out garantiza que el plan que ha revisado es exactamente lo que se aplica.
  2. Ejecute terraform apply para aplicar el plan de ejecución.

    terraform apply main.destroy.tfplan
    

Solución de problemas de Terraform en Azure

Solución de problemas comunes al usar Terraform en Azure

Pasos siguientes