CZ 
15.04.2026 Anastázie VÍTEJTE V MÉM SVĚTĚ

An English translation is available for this article. Pro tento článek je dostupný anglický překlad.
Terraform and FortiGate with FortiOS - DNS Server Records

Terraform a FortiGate s FortiOS - záznamy na DNS Serveru

| Petr Bouška - Samuraj |
Pokračování popisu použití Terraformu (nástroje typu Infrastructure as Code) s Fortinet FortiOS Provider pro automatizovanou konfiguraci FortiGate. V tomto článku si vyzkoušíme vytvoření záznamů na DNS serveru běžícím na FortiGate. Popíšeme si komplikovanější situaci, kdy nejprve importujeme aktuální konfiguraci a následně přidáváme nové záznamy. Navíc je tu problém s pořadím načítaných záznamů, které jsou vnořené objekty DNS databáze. Budeme řešit seřazení záznamů, takže využijeme alternativní možnost vygenerování existující konfigurace.
zobrazeno: 655x (427 CZ, 228 EN) | Komentáře [0]

Pozn.: Popis v článku vychází z Terraform verze 1.14.6, FortiOS Provider verze 1.24.1 a FortiGate s FortiOS 7.4.11.

Přidání záznamů na DNS server

Navazujeme na informace v předchozích článcích, které popisovaly použití Terraformu a připojení na FortiGate. V dnešním příkladu budeme řešit situaci, kdy na FortiGate provozujeme DNS server a chceme přidat nové DNS záznamy pomocí Terraform. Samozřejmě bychom jednoduše mohli provést celou konfiguraci DNS Database a vytvoření DNS Zone.

Problém je, že pro DNS záznamy neexistuje samostatný resource, ale konfigurují se jako vnořené bloky uvnitř nastavení celé zóny (DNS Database). Proto nemůžeme jednoduše přidávat nové objekty, ale musíme nejprve importovat existující konfiguraci.

Další problém je, že vnořené bloky jsou reprezentovány jako neuspořádaná skupina položek. Načítají se v náhodném pořadí. Když se porovnají s konfigurací, tak se navrhují změny (přepis položek). Řešíme to na konci článku seřazením. Ale pořád to není ideální, když třeba chceme odstranit jednu položku, tak dojde ke kompletní změně všech následujících.

Import existující konfigurace

Vytvoříme soubor import.tf. Pomocí bloku import budeme importovat prostředek typu fortios_system_dnsdatabase, jméno v konfiguraci použijeme dns. Načítáme existující zónu se jménem domain.tld.

import {
  to = fortios_system_dnsdatabase.dns
  id = "domain.tld"
}

Generování konfigurace

Pomocí Terraform CLI necháme nejprve vygenerovat konfigurační soubor.

PS D:\Terraform\FortiGate> terraform plan --generate-config-out=generated.tf
fortios_system_dnsdatabase.dns: Preparing import... [id=domain.tld]
fortios_system_dnsdatabase.dns: Refreshing state... [id=domain.tld]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
 following symbols:
~ update in-place

Terraform will perform the following actions:

  # fortios_system_dnsdatabase.dns will be updated in-place
  # (imported from "domain.tld")
  ~ resource "fortios_system_dnsdatabase" "dns" {
        allow_transfer          = null
        authoritative           = "enable"
        contact                 = "host"
        domain                  = "domain.tld"
      + dynamic_sort_subtable   = "false"
        forwarder               = null
        forwarder6              = "::"
      + get_all_tables          = "false"
        id                      = "domain.tld"

...

        dns_entry {
            canonical_name = null
            hostname       = "server02"
            id             = 2
            ip             = "192.168.0.2"
            ipv6           = "::"
            preference     = 10
            status         = "enable"
            ttl            = 0
            type           = "A"
        }

...

Plan: 1 to import, 0 to add, 1 to change, 0 to destroy.

...

Co mi přijde zajímavé, že se mimo importu uvádí také změna. A jsou označeny argumenty dynamic_sort_subtable a get_all_tables jako přidané. Ve vygenerované konfiguraci jsou uvedeny jako

  dynamic_sort_subtable = null
  get_all_tables        = null

Import

Následně provedeme podle bloků import a resource import do stavového souboru.

PS D:\Terraform\FortiGate> terraform apply
fortios_system_dnsdatabase.dns: Preparing import... [id=domain.tld]
fortios_system_dnsdatabase.dns: Refreshing state... [id=domain.tld]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
 following symbols:
~ update in-place

...

Plan: 1 to import, 0 to add, 1 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

fortios_system_dnsdatabase.dns: Importing... [id=domain.tld]
fortios_system_dnsdatabase.dns: Import complete [id=domain.tld]
fortios_system_dnsdatabase.dns: Modifying... [id=domain.tld]
fortios_system_dnsdatabase.dns: Modifications complete after 0s [id=domain.tld]

Apply complete! Resources: 1 imported, 0 added, 1 changed, 0 destroyed.

Úprava konfigurace

Můžeme rovnou pracovat se souborem generated.tf, ale pro větší přehlednost můžeme vytvořit nový soubor main.tf a do něj zkopírovat upravenou konfiguraci. Generovaná konfigurace obsahuje všechny argumenty daného prostředku (včetně výchozích hodnot atd.). Také můžeme odebrat soubor import.tf.

resource "fortios_system_dnsdatabase" "dns" {
  name          = "domain.tld"
  domain        = "domain.tld"
  type          = "primary"
  view          = "shadow"
  ttl           = 86400
  authoritative = "enable"
  
  dns_entry {
    hostname = "server01"
    id       = 1
    ip       = "192.168.0.1"
    type     = "A"
  }
  dns_entry {
    hostname = "server02"
    id       = 2
    ip       = "192.168.0.2"
    type     = "A"
  }
  dns_entry {
    hostname = "server03"
    id       = 3
    ip       = "192.168.0.3"
    type     = "A"
  }
}

Ověříme, že naše upravená konfigurace odpovídá reálnému stavu.

PS D:\Terraform\FortiGate> terraform plan 
fortios_system_dnsdatabase.dns: Refreshing state... [id=domain.tld]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.

Vytvoření nového DNS záznamu

Da konfigurace přidáme nový blok dns_entry s údaji nového záznamu.

  dns_entry {
    hostname = "server04"
    id       = 4
    ip       = "192.168.0.4"
    type     = "A"
  }

Aplikujeme změny konfigurace a záznam se vytvoří na FortiGate.

Visual Studio Code - Terraform project - FortiGate DNS Entry
PS D:\Terraform\FortiGate> terraform apply
fortios_system_dnsdatabase.dns: Refreshing state... [id=domain.tld]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
 following symbols:
~ update in-place

Terraform will perform the following actions:

  # fortios_system_dnsdatabase.dns will be updated in-place
  ~ resource "fortios_system_dnsdatabase" "dns" {
        id                      = "domain.tld"
        name                    = "domain.tld"
        # (23 unchanged attributes hidden)

      + dns_entry {
          + hostname = "server04"
          + id       = 4
          + ip       = "192.168.0.4"
          + type     = "A"
        }

        # (3 unchanged blocks hidden)

    }

Plan: 0 to add, 1 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

fortios_system_dnsdatabase.dns: Modifying... [id=domain.tld]
fortios_system_dnsdatabase.dns: Modifications complete after 0s [id=domain.tld]

Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
FortiGate 7.4 - DNS Servers - DNS Zone entries

Konfigurace s využitím proměnných

Konfiguraci můžeme ještě více upravit, abychom jednotlivé DNS záznamy definovali pomocí proměnné v samostatném souboru.

variables.tf

Mezi definice proměnných přidáme seznam objektů pro DNS záznamy.

# DNS Entries for DNS Zone
variable "dns_entries" {
  description = "DNS resource records"
  type = list(object({
    hostname = string
    id       = number
    ip       = string
    type     = optional(string, "A")
    })
  )  
}

dns-records.auto.tfvars

Vytvoříme nový soubor kam vložíme konfiguraci DNS záznamů.

dns_entries = [
  {
    hostname = "server01"
    id       = 1
    ip       = "192.168.0.1"
  } , {
    hostname = "server02"
    id       = 2
    ip       = "192.168.0.2"
  } , {
    hostname = "server03"
    id       = 3
    ip       = "192.168.0.3"
  } , {
    hostname = "server04"
    id       = 4
    ip       = "192.168.0.4"
  }
]

main.tf

Upravíme konfiguraci prostředku a pro vnořené bloky dns_entry využijeme dynamic Blocks.

resource "fortios_system_dnsdatabase" "dns" {
  name                  = "domain.tld"
  domain                = "domain.tld"
  type                  = "primary"
  view                  = "shadow"
  ttl                   = 86400
  authoritative         = "enable"
  dynamic_sort_subtable = "true"

  dynamic "dns_entry" {
    for_each = var.dns_entries

    content {
      hostname = dns_entry.value.hostname
      id       = dns_entry.value.id
      ip       = dns_entry.value.ip
      type     = dns_entry.value.type
    }
  }
}

Problém s pořadím položek

Resource fortios_system_dnsdatabase může obsahovat mnoho vnořených bloků dns_entry pro jednotlivé DNS záznamy. Podle informací v diskusi Ignoring order of resource blocks upon modification se využívá TypeSet, což je neuspořádaná skupina položek. Nepodporuje indexování podle klíče (ID). Tyto položky se z pohledu FortiAPI označují jako sub-tables.

V praxi se položky pokaždé načítají v jiném pořadí, což může vyvolávat opakovanou potřebu změny. Pro porovnání, zda došlo ke změně, se používá hash. Při testech s pár položkami se mi problém objevil pouze občas. Ale při stovce položek to bylo pokaždé.

Generování konfigurace a import

Již když generujeme konfiguraci, tak nejsou položky seřazené podle ID a když pak chceme provést import, tak se provádí aplikace změn.

PS D:\Terraform\FortiGate> terraform apply

...

Terraform will perform the following actions:

  # fortios_system_dnsdatabase.dns will be updated in-place
  # (imported from "domain.tld")
  ~ resource "fortios_system_dnsdatabase" "dns" {
        allow_transfer          = null
        authoritative           = "enable"
        contact                 = "host"
        domain                  = "domain.tld"
      + dynamic_sort_subtable   = "false"

...

      ~ dns_entry {
            canonical_name = null
          ~ hostname       = "server01" -> "server03"
          ~ id             = 1 -> 3
          ~ ip             = "192.168.0.1" -> "192.168.0.3"
            ipv6           = "::"
            preference     = 10
            status         = "enable"
            ttl            = 0
            type           = "A"
        }
      ~ dns_entry {

...

Plan: 1 to import, 0 to add, 1 to change, 0 to destroy.

Když aplikujeme změny, tak se na FortiGate naštěstí nic nezmění. Dojde k importu vzdálených objektů do Terraform state.

dynamic_sort_subtable

Řešením by měl být argument dynamic_sort_subtable, který zařídí, že se položky načítají seřazené. Problém je, že vygenerovaná konfigurace seřazená není.

resource "fortios_system_dnsdatabase" "dns" {
  dynamic_sort_subtable = "true"

Vytvoření seřazené konfigurace

Zkusil jsem dát dohromady alternativní řešení, kdy využijeme datový zdroj a načteme fortios_system_dnsdatabase. Seřadíme položky podle ID, které musíme nejprve převést na číslo. Pomocí output zobrazíme hodnoty jednotlivých DNS záznamů přesně ve formátu, jak jsme si připravili konfiguraci proměnné v minulé kapitole.

locals {
  padded_map = {
    for entry in data.fortios_system_dnsdatabase.DNS.dns_entry :
    format("%010d", tonumber(entry.id)) => entry
  }
  dns_entries_sorted = [
    for k in sort(keys(local.padded_map)) :
    local.padded_map[k]
  ]
}

data "fortios_system_dnsdatabase" "DNS" {
  name = "domain.tld"
}

output "dns_entries" {  
  value = [
    for entry in local.dns_entries_sorted : {
      id       = entry.id
      hostname = entry.hostname
      ip       = entry.ip
      type     = entry.type
    }
  ]
}

Když aplikujeme změny, tak dojde k načtení hodnot a uložení do stavového souboru. Zároveň se zobrazí jednotlivé položky (výstup).

PS D:\Terraform\FortiGate> terraform apply
data.fortios_system_dnsdatabase.DNS: Reading...
fortios_system_dnsdatabase.dns: Refreshing state... [id=domain.tld]
data.fortios_system_dnsdatabase.DNS: Read complete after 0s [id=domain.tld]

Changes to Outputs:
  + dns_entries = [
      + {
          + hostname = "server01"
          + id       = 1
          + ip       = "192.168.0.1"
          + type     = "A"
        },
      + {
          + hostname = "server02"
          + id       = 2
          + ip       = "192.168.0.2"
          + type     = "A"
        },
      + {
          + hostname = "server03"
          + id       = 3
          + ip       = "192.168.0.3"
          + type     = "A"
        },
      + {
          + hostname = "server04"
          + id       = 4
          + ip       = "192.168.0.4"
          + type     = "A"
        },
    ]


You can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes
 
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

dns_entries = [
  {
    "hostname" = "server01"
    "id" = 1
    "ip" = "192.168.0.1"
    "type" = "A"
  },
  {
    "hostname" = "server02"
    "id" = 2
    "ip" = "192.168.0.2"
    "type" = "A"
  },
  {
    "hostname" = "server03"
    "id" = 3
    "ip" = "192.168.0.3"
    "type" = "A"
  },
  {
    "hostname" = "server04"
    "id" = 4
    "ip" = "192.168.0.4"
    "type" = "A"
  },
]

Zobrazené položky (Outputs) zkopírujeme do souboru dns-records.auto.tfvars. Následně provedeme import.

Související články:

Infrastruktura jako kód - Terraform

Nástroje typu Infrastructure as Code (IaC) umožňují definovat, nasazovat a spravovat infrastrukturu deklarativním (nebo imperativním) způsobem pomocí konfiguračních souborů. Prostředky (servery, sítě, úložiště apod.) popíšeme v textovém souboru, který definuje požadovaný stav. Nástroj zajistí, že reálné prostředí odpovídá definici. Zatím se budeme věnovat nástroji Terraform.

Fortinet FortiGate a další

Bezpečnostní řešení firmy Fortinet. Nejvíce zaměřeno na Next Generation Firewall (NGFW) FortiGate. Konfigurace FW, politik, NATu, ale také VPN a možností autentizace. Okrajově práce s logy pomocí FortiAnalyzer a s klienty pomocí FortiClient EMS.

Pokud se chcete vyjádřit k tomuto článku, využijte komentáře níže.

Komentáře

Zatím zde nejsou žádné komentáře.

Přidat komentář

Vložit tag: strong em link

Nápověda:
  • maximální délka komentáře je 2000 znaků
  • HTML tagy nejsou povoleny (budou odstraněny), použít se mohou pouze speciální tagy (jsou uvedeny nad vstupním polem)
  • nový řádek (ENTER) ukončí odstavec a začne nový
  • pokud odpovídáte na jiný komentář, vložte na začátek odstavce (řádku) číslo komentáře v hranatých závorkách