Icinga check command for OPNsense firewall monitoring
This check command depends on the following python modules:
- enum
- requests
- argparse
Installation on Debian / Ubuntu
apt install python3 python3-requests
Installation on Rocky / Alma Linux 9
yum install python3 python3-requests
Installation on FreeBSD
pkg install python3 py39-requests
Add a check command definition and a service to Icinga2.
Use ./check_opnsense.py -h to get instructions:
usage: check_opnsense.py [-h] [-V] -H HOSTNAME [-p PORT] [--api-key API_KEY] [--api-secret API_SECRET] [-t TIMEOUT] [-k] -m {updates,ipsec,interfaces,services,wireguard,disk,memory,swap,cpu,load}
[-w THRESHOLD_WARNING] [-c THRESHOLD_CRITICAL] [-v] [-f FILTER] [--filter-regex FILTER_REGEX] [-i INCLUDE]
Check command OPNsense firewall monitoring
options:
-h, --help show this help message and exit
-V, --version show program's version number and exit
API Options:
-H, --hostname HOSTNAME
OPNsense hostname or ip address
-p, --port PORT OPNsense https-api port
--api-key API_KEY API key (See OPNsense user manager), defaults to $OPNSENSE_API_KEY
--api-secret API_SECRET
API secret (See OPNsense user manager), defaults to $OPNSENSE_API_SECRET
-t, --timeout TIMEOUT
API request timeout in seconds (default: 30)
-k, --insecure Don't verify HTTPS certificate
Check Options:
-m, --mode {updates,ipsec,interfaces,services,wireguard,disk,memory,swap,cpu,load}
Mode to use.
-w, --warning THRESHOLD_WARNING
Warning threshold for check value
-c, --critical THRESHOLD_CRITICAL
Critical threshold for check value
-v, --verbose Show additional details, e.g. the items excluded by --filter
-f, --filter FILTER Comma separated list of items to exclude from the output and the exit code calculation. Example: 'Disk 1, Disk 2'.
--filter-regex FILTER_REGEX
Exclude every item matching this regular expression. Example: 'lo[0-9]+'.
-i, --include INCLUDE
Comma separated list of the only items to check. Everything else is excluded. Example: 'igb0, igb1'.Go to the user manager and select the user you want to use for API access. Click the + icon in the API keys section to add a new API key, which triggers a download of a tex file containing the key and secret.
This file should look similar to this one:
key=w86XNZob/8Oq8aC5r0kbNarNtdpoQU781fyoeaOBQsBwkXUt
secret=XeD26XVrJ5ilAc/EmglCRC+0j2e57tRsjHwFepOseySWLM53pJASeTA3
For further information have a look at the opnsense documentation.
Whatever you pass on the command line shows up in the process list of the monitoring host. Put the credentials in the environment to keep them out of it:
export OPNSENSE_API_KEY=w86XNZob/8Oq8aC5r0kbNarNtdpoQU781fyoeaOBQsBwkXUt
export OPNSENSE_API_SECRET=XeD26XVrJ5ilAc/EmglCRC+0j2e57tRsjHwFepOseySWLM53pJASeTA3
./check_opnsense.py -H <OPNSENSE_HOSTNAME> -m updatesFor a permanent setup, keep the two variables in a file that only the monitoring user can read:
cat > /etc/check_opnsense.env <<'EOF'
OPNSENSE_API_KEY=w86XNZob/8Oq8aC5r0kbNarNtdpoQU781fyoeaOBQsBwkXUt
OPNSENSE_API_SECRET=XeD26XVrJ5ilAc/EmglCRC+0j2e57tRsjHwFepOseySWLM53pJASeTA3
EOF
chmod 600 /etc/check_opnsense.envThe lines have no export, because that is the format systemd reads. Make the file belong to the
user icinga2 runs as, which is not the same on every distribution.
The check plugin itself does not read the file. Something has to put the variables into the environment it runs in. Under systemd a drop-in does that for icinga2 and everything it starts:
# /etc/systemd/system/icinga2.service.d/opnsense.conf
[Service]
EnvironmentFile=/etc/check_opnsense.envRun systemctl daemon-reload and restart icinga2 afterwards. In a shell, read the same file with
set -a; . /etc/check_opnsense.env; set +a.
Most modes let you skip items you are not interested in. Skipped items count neither for the output nor for the exit code.
-f/--filter takes a comma separated list of names, for example -f "/, /var". If the names share
a pattern, --filter-regex 'lo[0-9]+' saves you from listing them all.
-i/--include works the other way round. It checks the listed items and skips everything else.
-f and --filter-regex still apply on top of it.
Add -v to see what was left out:
[OK] Disk space is ok | /var=4%;80.0;90.0;0;100
[OK] /var has 190G of 200G (96.0%) free disk space
--- FILTERED ---
[FILTER] / is excluded by --filter
Check for updates
./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m updates
[CRITICAL] There are 43 updates available, total download size is 199.1MiB. This update requires a reboot.|upgrade_packages=42 reinstall_packages=1 remove_packages=0 available_updates=43
./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m updates
[WARNING] There are 14 updates available, total download size is 64.8MiB.|upgrade_packages=14 reinstall_packages=0 remove_packages=0 available_updates=14
./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m updates
[OK] - System up to date|upgrade_packages=0 reinstall_packages=0 remove_packages=0 available_updates=0Check for services
./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m services
[CRITICAL] 1 service(s) stopped: ddclient (ddclient)
--- RUNNING SERVICES ---
[RUNNING] Configd (configd)
[RUNNING] Cron (cron)
[RUNNING] Dnsmasq DNS/DHCP (dnsmasq)
[RUNNING] Gateway Watcher (dpinger/:watcher:)
[RUNNING] Gateway WAN (dpinger/WAN)
[RUNNING] Hostwatch (hostwatch)
[RUNNING] Users and Groups (login)
[RUNNING] Ntpd (ntpd)
[RUNNING] OpenVPN server company-vpn (openvpn/4711)
[RUNNING] Packet Filter (pf)
[RUNNING] System routing (routing)
[RUNNING] IPsec VPN (strongswan)
[RUNNING] System tunables (sysctl)
[RUNNING] Syslog-ng (syslog-ng)
[RUNNING] Unbound (unbound)
[RUNNING] Web GUI (webgui)
| services_running=16 services_stopped=1Check interface status
Options:
-f <device>will not check<device>i.e.-f igb0will not check the igb0 interface.
One interface being down is enough to make the check critical. The check ignores interfaces that are disabled in OPNsense.
./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m interfaces
[OK] 2 interface(s) are up | interfaces_up=2 interfaces_down=0
[OK] interface igb0 is up
[OK] interface igb1 is up./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m interfaces
[CRITICAL] 1 interface(s) are down | interfaces_up=1 interfaces_down=1
[OK] interface igb0 is up
[CRITICAL] interface igb1 is downCheck ipsec tunnel status
./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m ipsec
[WARNING] IPsec tunnels not connected: headquarter
./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m ipsec
[OK] IPsec tunnels connected: remote-office, headquarterCheck wireguard tunnel status
./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m wireguard
[OK] 2/2 Wireguard peers are online
[OK] Peer host1 is online (8.8.8.4:35376)
[OK] Peer host2 is online (8.8.8.5:34376)Check available disk space
Options:
-wand-cdefine maximum disk usage i.e.-w 80will warn if disk usage exceeds 80%-f <mountpoint>will not check<mountpoint>i.e.-f /will not check the root filesystem.
./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m disk
[OK] Disk space is ok | /=2%;80.0;90.0;0;100
[OK] / has 201G of 222G (98.0%) free disk space./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m disk - w 1 -c 2.5
[WARNING] Disk space is low on 1 disk(s) | /=2%;1.0;2.5;0;100
[WARNING] / has only 201G of 222G (98.0%) free disk space./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m disk - w 1 -c 2
[CRITICAL] Disk space is critically low on 1 disk(s) | /=2%;1.0;2.0;0;100
[CRITICAL] / has only 201G of 222G (98.0%) free disk space./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m disk - w 1 -c 2 -f '/'
[UNKNOWN] No disks foundCheck memory
Options:
-wand-cdefine maximum memory usage i.e.-w 80will warn if memory usage exceeds 80%
Opnsense systems without ZFS, not using ARC:
./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m memory
[OK] Memory usage is 34% | memory=34%;80.0;90.0;0;100;
Opnsense systems with ZFS, using ARC:
./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m memory -w 35 -c 50
[WARNING] Memory usage is 39% | memory=39%;35.0;50.0;0;100; arc_size=199MB;
Additional memory used for ARC: 199MBCheck swap
Options:
-wand-cdefine maximum memory usage i.e.-w 80will warn if memory usage exceeds 80%
./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m swap
[OK] Total swap usage is 2% | /dev/md0=9%;80.0;90.0;0;100 /dev/gpt/swapfs=1%;80.0;90.0;0;100
Swap usage on /dev/md0 is 9%
Swap usage on /dev/gpt/swapfs is 1%./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m swap -f /dev/gpt/swapfs -c 8
[CRITICAL] Total swap usage is 9% | /dev/md0=9%;80.0;8.0;0;100
Swap usage on /dev/md0 is 9%Check CPU
Options:
-wand-cdefine maximum cpu usage i.e.-w 80will warn if cpu usage exceeds 80%
./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m cpu
[OK] CPU usage is 1.9% | cpu_usage=1.9%;80.0;90.0;0;100./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m cpu -w 30 -c 40
[CRITICAL] CPU usage is 42.7% | cpu_usage=42.7%;1.0;1.2;0;100Check load
Options:
-wand-cdefine maximum load i.e.-w 2will warn if any load time range exceeds 2.
./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m load
[OK] Load is ok. | load1=0.88;3.0;4.0;0; load5=0.72;3.0;4.0;0; load15=0.61;3.0;4.0;0;
[OK] load1 is 0.88
[OK] load5 is 0.72
[OK] load15 is 0.61./check_opnsense.py -H <OPNSENSE_HOSTNAME> --api-key <API_KEY> --api-secret <API_SECRET> -m load -w 0.5 -c 0.8
[CRITICAL] Load is critical. | load1=1.34;0.5;0.8;0; load5=0.82;0.5;0.8;0; load15=0.65;0.5;0.8;0;
[CRITICAL] load1 is 1.34
[CRITICAL] load5 is 0.82
[WARNING] load15 is 0.65