Tuesday, November 11, 2025

How we use Terraform for managing multiple FW

 So in Terraform we used similar groups and rules between our WEST, and EAST firewall clusters. So each group we manage by TF has the same details.


Since it's best security practice to avoid using the same api-key between DataCenters we use tfvars and auto.tfvars to call up the API-key ( aka token ) 


e.g my provider.tf 


gn.admin@debian-s-2vcpu-4gb-120gb-intel-atl1-01:~# cat provider.tf 

terraform {

  required_providers {

    fortios = {

      source = "fortinetdev/fortios"

    }

   }

}



#   FortiOS Provider Details for the FW1 and FW2

#

provider "fortios" {

hostname = var.hostname_value 

token =  var.token

insecure = "true"

}



Now in our variables.tf definition we define the variables


gn.admin@debian-s-2vcpu-4gb-120gb-intel-atl1-01:~# cat variables.tf 

# variables.tf socpuppets



# FW1 = WEST COAST , FW2 - EAST COAST

#

#

variable "hostname_value" {

  description = "The desired hostname for the resource"

  type        = string

}



variable "token" {

  description = "The desired API-token  for the resource"

  type        = string

}


my *.auto.tfvars


gn.admin@debian-s-2vcpu-4gb-120gb-intel-atl1-01:~# ls -ltr *auto.tfvars

-rw-r--r-- 1 root root 41 Jan 11  2023 terraform1.auto.tfvars

-rw-r--r-- 1 root root 41 Jan 19  2023 terraform2.auto.tfvars

root@debian-s-2vcpu-4gb-120gb-intel-atl1-01:~# cat *.auto.tfvars

token = "yy1t5w3rbt5Qwx79dg1Gw40w4Qprh3"

token = "1cy8qb396qcjHxq0qGs3fsx4Nr7mpz"

root@debian-s-2vcpu-4gb-120gb-intel-atl1-01:~# 


So now when I run my apply,  we just call up the FW1 or FW2  for execution


e.g

main.tf




gn.admin@debian-s-2vcpu-4gb-120gb-intel-atl1-01:~# terraform apply  -var-file=terraform1.auto.tfvars

var.hostname_value

  The desired hostname for the resource


  Enter a value: FW1


fortios_firewall_address.dumbass: Refreshing state... [id=dumbass]


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_firewall_address.dumbass will be updated in-place

  ~ resource "fortios_firewall_address" "dumbass" {

      ~ comment               = " Managed by TERRAFORMS " -> " Managed by TERRAFORMS BLOGGER DEMO "

        id                    = "dumbass"

        name                  = "dumbass"

      - visibility            = "enable" -> null

        # (41 unchanged attributes 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



We found that this simplifies items when you have multiple objects that you are managing with code.


To recap


breakout your main.tf into provider.tf and main.tf, define variables.tf and auto.tfvars and call up and auto-populate the token







NSE ( network security expert) and Route/Switching Engineer
kfelix  -----a----t---- socpuppets ---dot---com
     ^      ^
=(  @  @ )=
         o

        /  \


  


Monday, November 10, 2025

Using Pulumi for managing fortios IaC

In this example, I will demo using Pulumi with fortios

https://www.pulumi.com/registry/packages/fortios/api-docs/firewall/addrgrp/


The advantage over Terraform

  •   handle multiple languages like go or yaml
  •   Secrets are encrypted by default
  •   Simpler to set up
  •   Quicker to debug and built-in diagnostics identification


So here's my Pulumi.yaml built from a yaml template


root@debian-s-1vcpu-1gb-nyc3-01:~/pul2# cat Pulumi.yaml 

name: basic


runtime: yaml


config:

  fortios:cabundlefile:

    value: /etc/ssl/certs/firewall.crt

  fortios:hostname:

    value: xxx.xxx.xxx.xxx 

  fortios:insecure:

    value: true 

  fortios:token:

    value: thsNr5qt6dgj7Nfh3Ggynq6z1NGpzn 


resources:

  # Create provider instance

  fortios-provider:

    type: pulumi:providers:fortios

    properties:

      cabundlefile: ${fortios:cabundlefile}

      hostname: ${fortios:hostname}

      insecure: ${fortios:insecure}

      token: ${fortios:token}

 # Create a Static Route Item

  route1:

    type: fortios:networking:RouteStatic

    properties:

      dst: 10.13.2.14/32

      gateway: 192.168.111.111

      device: lan5

    options:

      provider: ${fortios-provider}


# Create a Static Route Item

  route2:

    type: fortios:networking:RouteStatic

    properties:

      dst: 10.32.2.12/32

      gateway: 192.168.111.111

      device: lan5

    options:

      provider: ${fortios-provider}

      

  trname1:

    type: fortios:firewall:Address

    properties:

      name: ken01111

      allowRouting: disable

      subnet: 12.1.1.0 255.255.255.0

      type: ipmask

      visibility: enable


  trname2:   

    type: fortios:firewall:Address

    properties:

      name: ken01112

      allowRouting: disable

      subnet: 12.2.1.0 255.255.255.0

      type: ipmask

      visibility: enable


  trname3:   

    type: fortios:firewall:Address

    properties:

      name: ken01113

      allowRouting: disable

      subnet: 13.2.1.0 255.255.255.0

      type: ipmask

      visibility: enable



  trname:

    type: fortios:firewall:Addrgrp

    properties:

      allowRouting: disable

      name: BLOCKITNOW

      comment: my_block_list

      visibility: enable

      members:

        - name: ${trname1.name}

        - name: ${trname2.name}

        - name: ${trname3.name} 

To execute the task, just run "pulumi up"


For this demo, I'm using these versions










NSE ( network security expert) and Route/Switching Engineer
kfelix  -----a----t---- socpuppets ---dot---com
     ^      ^
=(  @  @ )=
         o

        /  \