Deploying FortiGate-VM Next Generation Firewall using Terraform

Last reviewed 2023-10-20 UTC

By Bartek Moczulski, Consulting System Engineer, Fortinet Inc.

This tutorial shows you how to use Terraform to deploy a FortiGate reference architecture to help protect your applications against cyberattacks. FortiGate is a next-generation firewall (NGFW) with software-defined wide area network (SD-WAN) capabilities deployed as a network virtual appliance in Compute Engine. When deployed, FortiGate can help secure applications by inspecting all inbound traffic originating from the internet and outbound and internal traffic between application tiers. You can use the same FortiGate cluster as a secure web gateway to protect outbound traffic originating from your workloads.

In this tutorial, you create several networks and deploy a high-availability (HA) FortiGate cluster. You also create a two-tier web application and configure FortiGate and Google Cloud to help enable secure inbound traffic, outbound traffic, and internal traffic.


The following diagram shows that the architecture deployed in this tutorial consists of an HA cluster of FortiGate NGFWs that uses a pair of external and internal load balancers to direct traffic to the active FortiGate VM instance. A two-tier web application is deployed behind the NGFWs. Connections from the internet to the application frontend (Tier 1) pass through the active FortiGate instance, as indicated by the red path. The NGFWs also inspect connections from Tier1 to Tier2, as indicated by the purple path.

For more information about testing NGFW connectivity and testing threat prevention, see Verify the FortiGate NGFW deployment.

An HA cluster of FortiGate NGFWs that uses a pair of external and
internal load balancers.


  • Prepare for the deployment.
  • Clone the Terraform modules.
  • Deploy an HA cluster of FortiGate VMs into new Virtual Private Cloud (VPC) networks.
  • Verify that the appliances deployed successfully.
  • Create sample workloads and help secure them using FortiGate.

This tutorial is split into two separate deployments.

In the first deployment, you use the day0 Terraform module to create a basic FortiGate deployment, form an HA cluster, and prepare load balancer resources.

In the second deployment, you use an example configuration in the day1 Terraform module to create a simple two-tier web application. You also enable secure connectivity to, from, and within the application using the FortiGate NGFW deployed earlier.


FortiGate VM for Google Cloud supports both on-demand pay-as-you-go (PAYG) licensing and bring-your-own-license (BYOL) models. This tutorial uses the BYOL model. For more information, see FortiGate support.

In this document, you use the following billable components of Google Cloud:

To generate a cost estimate based on your projected usage, use the pricing calculator. New Google Cloud users might be eligible for a free trial.

For more information about FortiGate licensing in the public cloud, see the Fortinet article on order types.

If you're a new Google Cloud user, you might be eligible for a free trial.

Before you begin

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  2. Make sure that billing is enabled for your Google Cloud project.

  3. Enable the Compute Engine API.

    Enable the API

Upload FortiGate license files (.lic) to a local directory, like lic1.lic and lic2.lic. These files are referenced when deploying instances for license provisioning. To obtain your production-ready or evaluation licenses, contact your local Fortinet reseller.

  1. Ensure both lic1.lic and lic2.lic files are uploaded to the Day0 directory before you run your Terraform plan. If you prefer to use the PAYG licensing model, consult the documentation on GitHub regarding the required code modifications.
  2. (Optional) Create a dedicated custom role and a service account for FortiGate.

    This action isn't obligatory, although it's highly recommended that you create these roles. If the fortigatesdn-ro service account isn't found, the template attempts to detect it and falls back to the Compute Engine default service account. For more information, see the Create a custom role and a service account section.

    You must have the Compute Admin privileges to the Google Cloud project to deploy this tutorial.

This tutorial consists of Terraform templates that fully automate the deployment of all resources. The necessary files are available in the Fortinet GitHub repository:

  1. In Cloud Shell, clone the GitHub repository:

    git clone

    You can follow this tutorial using Cloud Shell, which comes preinstalled with the gcloud CLI, Git, Terraform, and text editors. If you use Cloud Shell, you don't need to install anything on your workstation.

  1. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

A Cloud Shell session opens inside a new frame at the bottom of the Google Cloud console and displays a command-line prompt.

Create a custom role and a service account

FortiGate instances can query Google API Client Libraries to resolve dynamic addresses in a firewall policy. This popular functionality lets you build firewall policies based on network tags and other metadata rather than on static IP addresses. In this section, you create an IAM role and a service account with the minimum required privilege set, and a binding policy.

After you create roles, they can't be deleted and recreated.

  1. In Cloud Shell, create a Fortinet IAM role:

    GCP_PROJECT_ID=$(gcloud config get-value project)
    gcloud iam roles create FortigateSdnReader --project=$Google Cloud_PROJECT_ID \
      --title="FortiGate SDN Connector Role (read-only)" \
  2. Create a Fortinet service account:

    GCP_PROJECT_ID=$(gcloud config get-value project)
    gcloud iam roles create FortigateSdnReader --project=$GCP_PROJECT_ID \
      --title="FortiGate SDN Connector Role (read-only)" \
    gcloud iam service-accounts create fortigatesdn-ro \
      --display-name="FortiGate SDN Connector"
  3. Create a binding policy:

    gcloud projects add-iam-policy-binding $GCP_PROJECT_ID \
      --member="serviceAccount:fortigatesdn-ro@$" \

Initialize Terraform

In this section, you modify the files in the Day0 directory in the Terraform GitHub repository:

Before you begin, find the public IP address of your computer by searching for My IP address.

  1. In Cloud Shell, update the terraform.tfvars file with your Google Cloud project ID and the us-central1 region:

    GCE_REGION = us-central1
    Prefix = fgt-
  2. Add your public IP address to the admin_acl list in the file:

    module "fortigates" {
      source          = "../modules/fgcp-ha-ap-lb"
      region          = var.GCE_REGION
      service_account = != null ? : ""
      admin_acl       = ["IP-ADDRESS", "${data.http.my_ip.body}/32"]
      api_acl         = ["${data.http.my_ip.body}/32"]

    This template restricts access for the administrative interface and FortiGate API to the IP address that you run the template from.

  3. Initialize Terraform:

    terraform init
    terraform plan -out tf.plan
    ## verify the list of resources that will be created before moving to the next step.
    terraform apply tf.plan
  4. To connect to the primary FortiGate instance, use ssh with the default user ID: admin.

    The default password and primary IP address are visible in the Terraform output. When you connect for the first time, you must change the admin password.

  5. Verify the status of the provisioning by checking the output of the following command:

    get system ha status

    The output should resemble the data in the following screenshot:

    The provisioning response shows two instances: Primary and Secondary.

    At the end of the output, you should see two instances: Primary and Secondary. This output confirms that both instances were properly licensed and successfully formed an HA cluster.

This section described the minimal deployment of a FortiGate cluster. In the next section, you add additional functionality such as routes, firewall policies, and peered VPCs.

Deploy FortiGate NGFW workloads

In this section, you update the files in the Day1 directory of the GitHub repository to deploy workloads with a new public IP address. You also update the configuration files of the FortiGate NGFW.

The Day1 directory contains the following files:

  • Imports data from the day0 deployment to identify FortiGate instances and their API key. It also indicates where the Terraform state file is pulled from.
  • Creates a proxy and web servers into new Tier 1 and Tier 2 VPC networks.
  • Connects Tier 1 and Tier 2 VPC networks with internal VPC of the FortiGate cluster. It also enables inbound and outbound connectivity and adds Tier 1 to the Tier 2 east-west firewall policy.

Using the -parallelism=1 Terraform option in the code sample helps reduce or remove concurrency issues related to Google Cloud peering and routing operations for multiple VPC networks in a single Terraform deployment.

  1. In Cloud Shell, access the Day1 directory:

    cd ../day1
  2. To deploy a sample web application and configure FortiGate to forward connections to it, run the following commands:

    terraform init
    terraform plan -out day1.plan
    terraform apply day1.plan -parallelism=1

    The following screenshot shows a route operation in progress error. An error like this can occur if you don't use the -parallelism flag. Without this flag, you might run into concurrency issues.

    Error message caused by a lack of a -parallelism flag.

    To recover from this error, run the terraform apply command again. Terraform automatically verifies which steps failed and adds the missing resources.

Verify the FortiGate NGFW deployment

At this point in the tutorial, you've deployed a multi-tier architecture with inbound, outbound, and internal connectivity, all secured using FortiGate. In this section, you verify your deployment of the FortiGate NGFW. You also attempt to upload a harmless virus file to ensure that the firewall is operating. To connect to the web server over FortiGate, check the public IP address of the external load balancer in Terraform outputs. Connect to it using your web browser.

Wait a minute or two for the proxy and web server provisioning to finish before attempting the following verification steps:

  1. In Cloud Shell, copy the public IP address of the external load balancer from the public_ip output of the terraform apply command.
  2. Launch a web browser.
  3. Connect to the public IP address of the load balancer:

    http://Public IP address of the load balancer

    You should see the default Nginx welcome page.

    Successful connection confirmed by default Nginx web page.

  4. To download a harmless test virus file from the European Institute for Computer Anti-Virus Research, and to verify that FortiGate NGFW threat inspection is working, add / to the IP address you entered in the previous step.

    Test virus file blocked by east-west traffic inspection.

To see more details about the inspected network traffic:

  1. In the web browser, enter the public IP address of the first FortiGate instance (the same IP address you used earlier for SSH connections) into the address bar.
  2. Connect to the FortiGate web console using a web browser. The HTTPS console is available on the standard port of 443 by default.
  3. Skip the following optional setup steps:

    • Dashboard configuration
    • Firmware updates
    • Initial welcome video
  4. Select Log & Report > Forward Traffic from the FortiGate web console.

    A list of all the connections attempted through the FortiGate firewall appears. You should be able to identify the following:

    • Successful connection from your own IP address to the web server followed by a successful internal connection.
    • Multiple outbound connections with various applications detected.
    • Another internal connection between and that is blocked because of UTM policy. This action proves that the east-west threat inspection is working correctly.
  5. To reveal details of the detected threat, double-click on the blocked connection in the Result column. A details page appears.

    FortiGate forward traffic log.

  6. Select Security. Security appears in Log details.

Clean up

To avoid incurring charges to your Google Cloud account for the resources used in this tutorial, either delete the project that contains the resources, or keep the project and delete the individual resources.

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Delete the individual resources

To avoid incurring further charges, delete the individual resources that you use in this tutorial:

Delete the configuration added in the Day1 directory

Go to the Day1 directory from which you deployed the solution and run the following command:

   terraform destroy

Confirm you want to delete the resources.

Delete the FortiGate and the remaining resources

Go to the Day0 directory and run the following command:

   terraform destroy

Confirm you want to delete the resources.

To mitigate the FortiOS provider error, you have to update the API ACL:

  1. Check the public IP address of your Cloud Shell instance:

  2. Enable connecting to serial ports in the primary FortiGate (fgt-vm1-us-central1) VM instance settings using the Google Cloud console.

  3. To connect to the FortiGate administrative interface using the serial console, click Connect to serial console.

  4. Issue the following commands in the FortiGate CLI, replacing IP_ADDRESS with Cloud Shell public IP address:

      config system api-user
        edit terraform
          config trusthost
            edit 0
            set ipv4-trusthost IP_ADDRESS/32
  5. Go back to the Day1 directory and re-run terraform destroy.

What's next