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=
[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
Falseto bypass certificate checks. - state: Set to
presentto 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.