Fortigate Config Change Notification

Whenever changes are made in configuration, Fortigate posts notification at Slack channel.

Fortigate automation is composed of three elements:

  1. automation trigger … available trigger -HA Failover, Config change, Log, IOC, High CPU, Conserve mode
  2. automation action … available action -Email, IP Ban, AWS lambda, Webhook
  3. automation stitch … Combination of trigger and action

I create GoogleCloudFunction which will do:

  1. Receive webhook from Fortigate
  2. Post message at Slack channel

1. Create a program for Google Cloud Function

In order to create Google Cloud Function, I need to create three files locally.

  • requirements.txt … Additional libraries to be added for runtime.
  • slack.py … Utility python code which act as an interface for Slack
  • main.py … Receive the request, and post the message to Slack using slack.py
# requirements.txt
requests
# slack.py
import os

import requests


token = os.environ['SLACK_TOKEN']

def post(msg, channel, hostname):

    headers = {
        "Content-type": "application/json"
    }

    params = {
        "token": token,
        "text": msg,
        "channel": channel,
        "as_user": False,
        "username": hostname,
    }

    url = "https://slack.com/api/chat.postMessage"

    resp = requests.post(url, params=params, headers=headers)

    return resp.status_code
# main.py
import os
import sys

import requests

import slack


SLACK_CHANNEL = os.environ["SLACK_CHANNEL"]
AUTH_KEY = "supersecretkey"

def main(request):

    if not request.headers.get("Auth-key") == AUTH_KEY:
        print(f"Wrong auth_key provided from {request.headers.get('X-Forwarded-For')}")
        sys.exit(1)
    category = request.headers.get("Notif-type")
    if category == "ConfigChange":
        content = f"Config has been modified\n"
        content += f"WAN IP Address: {request.headers.get('X-Forwarded-For')}\n"
        content += f"Modified by: {request.headers.get('User')} at {request.headers.get('Client')}\n"
        try:
            slack.post(content, SLACK_CHANNEL, "GCP_FortigateNotify")
            print(f"Message posted to {SLACK_CHANNEL}")
        except requests.exceptions.RequestException as e:
            print(f"Request failed: {e}")
    else:
        print(f"Not implemented - requested: {category}")

Once created, compress them into one zip file. I name it “archive.zip” here.

2. Deploy Google Cloud Function

From Console, navigate to Cloud Function and deploy a new function. Note I set an environmental variables for “SLACK_TOKEN”, which you have to get your own token to post the message in Slack. The other environmental variables can be any value you want.

Check if there is no error log is recorded, and confirm the deployment is ready.

3. Configure Fortigate for notification

Again please note this function is only available for FortiOS6.0 or later, and as usual these new features change a lot from version to the version. Please check the appropriate manual before configuration.

config system automation-trigger
    edit "config-change"
        set event-type config-change
    next
end
config system automation-action
    edit "GCP-Notify"
        set action-type webhook
        set protocol https
        set uri "<your_googlefunction_project>/Fortigate_Notify"
        set port 443
        set headers "Auth-Key:supersecretkey" "Client:%%log.ui%%" "Notif-type:ConfigChange" "User:%%user%%"
    next
end
config system automation-stitch
    edit "config-notify-GCP"
        set trigger "config-change"
        set action "GCP-Notify"
    next
end

Test

It’s time to test. You can log in to Fortigate either via ssh or via web. Once you made changes, you need to log out (or you can wait for timeout). This is because Fortigate only logs configuration changes after the current session termination.

Fortigateでコンフィグ変更があったら自動的にSlackに通知してくれます。この機能はFortiOS6.0以降で実装されたautomationを使用しています。