About this article

Backup is one of the critical points of a solid cyber security strategy, and it is a vast topic. It can cover file backup, disk backup, virtual disk backup, database and configuration backup. In addition, backups are crucial for our DRP(Disaster Recovery Plan); actually, there is not a DRP if there is not a backup in place.

This article will cover how to backup your Fortigate configuration automatically using Gitlab CI/CD and Ansible.

There are many ways to run our Ansible playbooks, and we could ask: Why use Gitlab CI/CD for it? The answer is quite simple, some customers do not need to run an Ansible Tower, AWX or Semaphore, and Gitlab CI/CD has excellent potential to automate and schedule tasks.

What do I need to follow in this article?

  • Gitlab account.
  • Gitlab Runner to run our CI/CD Jobs.
  • Create an SSH Key to push config files to a repository.

In Gitlab, we will need to set our CI/CD environment variable. These variables will be used by the CI/CD pipeline and help us to keep our configuration and playbooks clear of sensitive data.

Variables:

  • FTG_PASSWD # We recommend creating a user for the backup job
  • KNOWN_HOSTS # Here, we need to get the public keys for Gitlab so that, later, we can push the config files to the repository.
  • SSH_KEY # Your SSH Key to push to the Gitlab repository.

About the KNOWN_HOSTS, you can get that information from your terminal using the command.

ssh-keyscan gitlab-host

Now let us have a look at the files we need. In my case, I created a git repository called fortigate-backup. The repository contains:

  • gitlab-ci.yml
  • backup.yml
  • inventory.yml

.gitlab-ci.yml

---
stages:
- linting
- backup

yamllint:
  stage: linting
  image: registry.gitlab.com/pipeline-components/yamllint:latest
  script:
  - yamllint .

ansible-lint:
  stage: linting
  image: registry.gitlab.com/pipeline-components/ansible-lint:latest
  script:
  - ansible-lint --show-relpath .

ftg-backup:
  stage: backup
  image: willhallonline/ansible:2.9.27-bullseye-slim
  variables:
    DOCKER_DRIVER: overlay
    FTG_PASSWD: "${FTG_PASSWD}"
  services:
  - docker:dind
  before_script:
  - mkdir ~/.ssh/
  - echo "${KNOWN_HOSTS}" > ~/.ssh/known_hosts
  - echo "${SSH_KEY}" > ~/.ssh/id_rsa
  - chmod 600 ~/.ssh/id_rsa
  - git config --global user.email "john@example.com"
  - git config --global user.name "Gitlab CI"
  - export COMMIT_TIME=$(date)
  script:
  - apt update && apt install -y git
  - ansible-galaxy collection install fortinet.fortios:1.1.9
  - ansible-playbook -i fortinet/inventory.yml fortinet/backup.yml
  - mkdir /fortigate-backups
  - git clone git@gitlab.com:myusername/fortigate-configs-backup.git /fortigate-backups
  - cd /fortigate-backups
  - rm -f backup_global backup_vdom
  - cp /tmp/backup_* .
  - git add -A
  - git commit -m "${COMMIT_TIME}"
  - |
    if [ -n "$(git status --porcelain)" ]; then
      echo "there are changes";
      git push
    else
      echo "no changes";
    fi    
  environment:
    name: main
  rules:
  - if: $CI_COMMIT_BRANCH == "main"

Lets explain the .gitlab-ci.yml which is a very important part for our backup task.

First we have two jobs to run the yamllint and ansible-lint, it is important to write good Infrastructure as a Code.

Then we have the ftg-backup job, as you can see, we use the ansible docker image. In variables we set the FTG_PASSWD env variable, it will be use when running the playbook and authenticate with the firewalls. For before_script we configure the SSH options and git configuration to use afterwards with our Gitlab repository.

In the main section script we do very interesting things:

  • Update and install git package.
  • Install fortinet ansible collection which is used by our playbook.
  • Run the playbook to backup the configs
  • Clone the fortigate-configs-backup repository, this is the repo where we will store our backups.
  • At last we check if the files contain new changes or not to commit to the repository.

inventory.yml

---
fortigates:
  hosts:
    fw01.example.com:
      ansible_host: 172.16.1.254
      ansible_user: backup
      ansible_password: '{{ lookup("env", "FTG_PASSWD") }}'
    fw02.example.com:
      ansible_host: 172.16.2.254
      ansible_user: backup
      ansible_password: '{{ lookup("env", "FTG_PASSWD") }}'
    fw03.example.com:
      ansible_host: 172.16.3.254
      ansible_user: backup
      ansible_password: '{{ lookup("env", "FTG_PASSWD") }}'
  vars:
    ansible_network_os: fortinet.fortios.fortios

In the inventory, it is essential to replace the information accordingly with your existing firewall infrastructure, hostname, IP address and credentials.

backup.yml

---
- hosts: fortigates
  connection: httpapi
  collections:
    - fortinet.fortios
  vars:
    vdom: "root"
    ansible_httpapi_use_ssl: "yes"
    ansible_httpapi_validate_certs: "no"
    ansible_httpapi_port: 443
  tasks:
    - name: backup a_specific_vdom settings
      fortios_system_config_backup_restore:
        config: "system config backup"
        vdom: "{{ vdom }}"
        backup: "yes"
        scope: "vdom"
        filename: '/tmp/backup_vdom_{{ inventory_hostname }}'

    - name: backup global settings
      fortios_system_config_backup_restore:
        config: "system config backup"
        vdom: "{{ vdom }}"
        backup: "yes"
        scope: "global"
        filename: '/tmp/backup_global_{{ inventory_hostname }}'

In this playbook what we do is to take backup of the global configuration and the root vdom. On the specific vdom backup, you can configure different vdoms if it is necessary or create multiple tasks for multiple vdoms. for more information, I recommend checking the ansible documentation.

After we push our .gitlab-ci.yml and Ansible playbook, it will run automatically once. If we would like to schedule this pipeline job everyday or once a week we just need to go to CI/CD -> Schedules and create a new schedule.

In some cases, it may be important to encrypt files before pushing them to the repository, in this case we can use tools like:

  • GPG
  • ccrypt
  • 7-zip

If you need to support with Fortinet or DevSecOps in your company, you can always contact us at Gonkar IT Security