Orchestrating Network Security: The Comprehensive Guide to Fortinet Automation with Ansible

The integration of Ansible into the Fortinet ecosystem represents a paradigm shift from traditional manual Command Line Interface (CLI) configurations to a modern Infrastructure as Code (IaC) methodology. By leveraging the Ansible Galaxy for Fortinet collections, network engineers can transition from individual device management to systemic orchestration. This process involves the deployment of specialized modules designed to interact with FortiOS and FortiManager, allowing for the programmatic definition of firewall policies, system global settings, and address objects. The fundamental objective of this automation is to eliminate human error, ensure configuration consistency across multiple security appliances, and accelerate the provisioning of complex network environments. This technical deep dive explores the installation, configuration, and practical application of Ansible for FortiGate and FortiManager, detailing the precise mechanisms required to achieve a fully automated security posture.

The Architectural Foundation of Ansible Galaxy for Fortinet

Ansible Galaxy serves as the central nervous system for community-contributed content, functioning as a public repository where users can download collections. In the context of Fortinet, these collections are not merely scripts but are comprehensive packages composed of multiple components, including content roles, specialized modules, plugins, and detailed documentation.

The technical requirement for utilizing these tools on a Linux environment, specifically Debian or Ubuntu, begins with the preparation of the package manager and the installation of the core Ansible engine. The process is initiated by updating the local package index to ensure the latest versions of dependencies are retrieved.

The installation of the core Ansible engine is performed using the following commands:

bash apt-get update apt-get -y install ansible

For these commands to execute successfully, the operator must possess root privileges or be added to the sudoers list. The technical implication of using the -y flag is the automatic assumption of "yes" to all prompts, ensuring a non-interactive installation process which is critical for automation scripts.

Once the core engine is present, the specific Fortinet collections must be pulled from the Galaxy repository. There are two primary collections depending on the management target: the FortiOS collection for direct firewall interaction and the FortiManager collection for centralized management.

The installation commands are as follows:

bash ansible-galaxy collection install fortinet.fortios ansible-galaxy collection install fortinet.fortimanager

The impact of this installation is the placement of the Fortinet-specific modules into the Ansible collection path, typically located under /root/.ansible/collections/ansible_collections. This allows the Ansible engine to recognize the specific API calls and data structures required to communicate with FortiGate devices. To verify that the installation was successful and the modules are available for use, the following command is utilized:

bash ansible-galaxy collection list

Establishing Connectivity and Authentication Protocols

Before any configuration can be pushed to a FortiGate device, a secure communication channel must be established. FortiOS supports two primary methods of authentication: the traditional username and password combination, and the more secure, API-driven access token.

The technical layer of this connectivity relies heavily on the httpapi connection plugin. Unlike standard SSH connections, the httpapi allows Ansible to communicate directly with the FortiOS REST API. This is more efficient for large-scale changes and provides more granular control over the configuration state.

Connection Parameter Specifications

To facilitate this connection, specific variables must be defined. These variables tell Ansible how to handle the SSL handshake and which port to use for communication.

Parameter Value/Setting Technical Purpose
ansible_connection httpapi Defines the use of the REST API instead of SSH
ansiblehttpapiuse_ssl yes Ensures the connection is encrypted via HTTPS
ansiblehttpapivalidate_certs no Disables SSL certificate validation (common in lab/internal environments)
ansiblehttpapiport 443 Specifies the standard HTTPS port for API communication
ansiblenetworkos fortinet.fortios.fortios Identifies the target platform as FortiOS

The impact of setting ansible_httpapi_validate_certs to no is that the automation will not fail if the FortiGate is using a self-signed certificate. However, in a production environment, this should be transitioned to yes with a valid certificate chain to prevent man-in-the-middle attacks.

Inventory Management and Variable Configuration

The inventory file is the cornerstone of Ansible, mapping the logical groups of devices to their physical network addresses and credentials. This is typically handled via a text file created with editors such as nano or vim.

Creating the Inventory File

To create the file in a Linux environment, the following commands are used:

bash nano <file name> or bash vim <file name>

Within this file, the structure is divided into host groups and variable groups. The host group identifies the devices, while the vars section defines the global settings for those devices.

Example inventory structure:

```ini [fortigates] fgt ansiblehost= ansibleuser="" ansiblepassword="" fortigate ansiblehost= fortiosaccesstoken=

[fortigates:vars] ansiblenetworkos=fortinet.fortios.fortios

[all:vars] ansibleconnection=httpapi ansiblehttpapivalidatecerts=no ansiblehttpapiuse_ssl=yes ```

The contextual relationship here is that the [fortigates] group defines the targets, while the [all:vars] section applies the httpapi settings to every device in the inventory, eliminating the need to repeat these parameters for every single host.

For those using nano, the file is saved by pressing Ctrl + X, followed by Enter. For vim users, the sequence is Esc, typing :w, and hitting Enter.

Playbook Development and YAML Implementation

The actual configuration of the FortiGate device is performed through Playbooks, written in YAML format. YAML is chosen for its human-readability and its ability to represent complex nested data structures, which is essential for firewall policies.

The Structure of a FortiOS Playbook

A standard playbook consists of a target host, a set of variables, and a sequence of tasks. Each task calls a specific module from the fortinet.fortios collection.

The basic syntax for a task is:

yaml hosts: <object created in inventory> tasks: - name: <tasks name> <Ansible Module> <Configuration on FortiGate> <Objects in the Configuration>

Technical Implementation of Basic Configurations

One of the most common tasks is modifying the global system settings, such as the hostname. This is achieved using the fortinet.fortios.fortios_system_global module.

Example for hostname change:

yaml hosts: fortigates tasks: - name: Change hostname fortinet.fortios.fortios_system_global: system_global: hostname: "FortiGate_Lab"

Another critical component is the creation of firewall address objects. This is a prerequisite for creating any firewall policy. The fortinet.fortios.fortios_firewall_address module is used, ensuring the state is set to present to avoid accidental deletion.

Example for address creation:

yaml - name: Create Address fortinet.fortios.fortios_firewall_address: state: "present" firewall_address: name: test_123 subnet: 10.1.1.1 255.255.255.0

Advanced Playbook Configuration with Tokens

In scenarios where the variables are not present in the inventory file, they can be defined directly within the playbook. This is particularly useful for using access tokens for authentication.

yaml - hosts: fortigates connection: httpapi collections: - fortinet.fortios vars: vdom: "root" ansible_httpapi_use_ssl: true ansible_httpapi_validate_certs: false ansible_httpapi_port: 443 tasks: - name: Configure global attribute fortios_system_global: vdom: "{{ vdom }}" access_token: "{{ fortios_access_token }}" system_global: hostname: 'FortiGateHostName'

The use of the vdom variable is critical because FortiGate devices can be partitioned into Virtual Domains. If the device is in a single-domain mode, the root VDOM is used by default.

Comprehensive Firewall Policy Automation

The most complex part of Fortinet automation is the creation of IPv4 policies. This requires a deep understanding of the parameters involved in the fortios_firewall_policy module.

Essential Parameters for Policy Creation

When defining a policy in YAML, several key variables must be accurately mapped:

  • host: The IP address of the FortiGate.
  • username/password: Credentials for the session.
  • ssl_verify: Set to False to bypass certificate checks.
  • state: Set to present to ensure the policy is created.
  • pid: The Policy ID. When set to 0, the FortiGate appliance automatically selects the next available ID from its internal database.
  • vlan_addr: The name of the address object for the source traffic.
  • int_vlan: The interface where the incoming VLAN traffic resides.

Practical Scenario: Multi-Rule Implementation

In a real-world scenario, such as creating rules for a Development environment and a Zabbix monitoring server, the playbook must be structured to handle multiple tasks.

Scenario Requirements: - Rule 1: Permit DEV (192.168.10.0/24) access to HTTP/HTTPS on host 192.168.20.20. - Rule 2: Permit Zabbix server (192.168.20.100) access to DEV (192.168.10.0/24) via TCP/10051.

The technical implementation of these rules requires the fortios_firewall_policy module.

Example Playbook Segment:

yaml - name: Create 2 rules on fortigate hosts: localhost: connection: local gather_facts: no vars: host: "192.168.0.1:443" ansible_httpapi_use_ssl: yes ansible_httpapi_validate_certs: no ansible_httpapi_port: 443 ansible_network_os: fortios username: "admin" password: "password123" tasks: - name: Create first policy fortios_firewall_policy: host: "{{ host }}" username: "{{ username }}" password: "{{ password }}" ssl_verify: "False" state: present firewall_policy: policyid: "{{ pid }}" name: "PERMIT {{ vlan_addr }} > DST-HOST" action: "accept" srcintf: - name: "{{ int_vlan }}" dstintf: - name: "Port2" srcaddr: - name: "{{ vlan_addr }}" dstaddr: - name: "DST-HOST" service: - name: "HTTP" - name: "HTTPS" comments: "Permit comunication between {{ vlan_addr }} and DST-HOST" schedule: "always" logtraffic: "utm" logtraffic_start: "disable"

The impact of this approach is that the network engineer can deploy hundreds of policies across dozens of firewalls by simply modifying a YAML variable list rather than manually entering commands in the CLI for each device.

Dependency Management and Python Environment

A critical technical requirement often overlooked is the Python dependency layer. While the Ansible collection provides the modules, the underlying communication often relies on specific Python libraries.

For those implementing the fortios modules, it is essential to install the fortiosapi library via the Python package manager. Depending on the system configuration, this is done using:

bash pip install fortiosapi or bash pip3 install fortiosapi

The scientific reason for this is that the Ansible module acts as a wrapper around the Python API. Without the fortiosapi library, the module cannot translate YAML instructions into the JSON payloads required by the FortiOS REST API.

Conclusion: Analysis of Automated Security Management

The transition from manual configuration to Ansible-driven orchestration for Fortinet devices provides a scalable framework for security management. The technical shift toward using the httpapi connection and the fortinet.fortios collection allows for a declarative approach to networking. Instead of specifying "how" to change a setting (imperative), the engineer specifies "what" the final state should be (declarative).

The use of the pid: 0 setting is a particularly powerful feature, as it offloads the management of policy indexing to the FortiGate appliance, preventing conflicts that occur when multiple engineers manually assign policy IDs. Furthermore, the ability to utilize access tokens instead of passwords enhances security by limiting the exposure of administrative credentials within the automation scripts.

Ultimately, the synergy between Ansible's idempotent nature and Fortinet's robust API creates an environment where network changes are predictable, version-controlled, and easily reversible. This methodology reduces the operational risk associated with human error and ensures that the security posture of the organization is consistent across all deployed appliances.

Sources

  1. Technical Tip: How to install the Ansible Galaxy for Fortinet
  2. Technical Tip: Application of Ansible on FortiGate
  3. First Network Automation Ansible Fortigate

Related Posts