I’m working on a custom check using SNMP to determine certificate expiration on an F5. When I perform an SNMP walk on .1.3.6.1.4.1.3375.2.1.15.1.2.1, I get the cert name, expiration date in a string and expiration date in epoch. I would like to be able to filter out the default certificates that come with the device as part of my custom check. Below are examples of the walk, with full OIDs:
I would like to be able to exclude default, f5-irule, etc and the OID strings all appear to end with 101.46.99.114.116 for these.
#inventory all certificates installed on the F5
def inventory_f5_bigip_certs(info):
for certname, fulldate, epochdate in info:
yield certname, “cert_thresholds”
# inventory all certificates installed on the F5
def inventory_f5_bigip_certs(info):
ignore_list = set(['/Common/default.crt',
'/Common/f5-irule.crt',
'/Common/ca-bundle.crt',
'/Common/f5-ca-bundle.crt'])
for certname, fulldate, epochdate in info:
if certname not in ignore_list:
yield certname, "cert_thresholds"
Or, if you have a parse function, filter them out there (in the same way). Then the inventory and check functions won’t even see them. I don’t think you can filter them out by OID.
Adding my full check for anyone that might find it useful.
#!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-
# +------------------------------------------------------------------+
# | ____ _ _ __ __ _ __ |
# | / ___| |__ ___ ___| | __ | \/ | |/ / |
# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
# | | |___| | | | __/ (__| < | | | | . \ |
# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
# | |
# | Copyright Mathias Kettner 2017 mk@mathias-kettner.de |
# +------------------------------------------------------------------+
#
# This file is part of Check_MK.
# The official homepage is at http://mathias-kettner.de/check_mk.
#
# check_mk is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation in version 2. check_mk is distributed
# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU General Public License for more de-
# tails. You should have received a copy of the GNU General Public
# License along with GNU Make; see the file COPYING. If not, write
# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
# Boston, MA 02110-1301 USA.
## Custom check for F5 certificate expiration
## Author: Shaun Pillé
## Contact: shaun.pille@gmail.com
## Version 0.2
#define current date in epoch time
currdate = int(time.time())
cert_thresholds = []
#define warning and critical thresholds in days
custom_warn=30
custom_crit=10
#convert custom warning thresholds to epoch time
cert_thresholds = [(custom_warn*86400),(custom_crit*86400)]
#inventory all certificates installed on the F5
def inventory_f5_bigip_certs(info):
ignore_list = set (['/Common/default.crt','/Common/f5-irule.crt','/Common/ca-
bundle.crt','/Common/f5-ca-bundle.crt'])
for certname, fulldate, epochdate in info:
if certname not in ignore_list:
yield certname, "cert_thresholds"
#check the expiration dates and return crit, warn, ok based on defined thresholds
def check_f5_bigip_certs(item, params, info):
cert_warn, cert_crit = params
state=0
for certname, fulldate, epochdate in info:
if certname == item:
expires=(int(epochdate) - currdate)/86400
if int(epochdate) - currdate < cert_crit:
state=2
elif int(epochdate) - currdate >= cert_crit and int(epochdate) - currdate <= cert_warn:
state=1
else:
state=0
infotext = "Valid for %d days" % expires
if certname:
infotext = ": ".join([infotext])
if state > 0:
infotext += " (warn/crit below %s/%s)" % (custom_warn, custom_crit)
yield state, infotext, [("daysleft", expires, cert_warn, cert_crit)]
#checkdata to pull matching SNMP strings
check_info["f5_bigip_certs"] = {
"check_function" : check_f5_bigip_certs,
"inventory_function" : inventory_f5_bigip_certs,
"service_description" : "Certificate Expiration %s",
"snmp_info" : ( ".1.3.6.1.4.1.3375.2.1.15.1.2.1", [ 1,4,5 ] )
}
Only one small hint.
The variable definitions at the start should/must be inside the functions. If you have another plugin with also the variable “custom_warn” defined the same way then only one will win
All definitions outside of functions are global in the CMK environment.
In addition to @andreas-doehler’s tip I suggest adding a snmp_scan_function. I’m not sure why it works without one. I can only guess that checkmk then tries to request the data defined by snmp_infofrom every device it encounters, which probably slows things down.
In pseudo code the snmp_scan_function translates to:
device_specific_oid = snmpget(".1.3.6.1.2.1.1.2.0")
if device_specific_oid contains ".1.3.6.1.4.1.3375.2":
some_identifier = snmpget(".1.3.6.1.4.1.3375.2.1.4.1.0")
if some_identifier contains "big-ip":
return True
return False
checkmk queries all “things” enclosed in oid(…) with snmpget-requests. sysObjectID is the OID that contains the OID of device specific data. Then it checks whether the F5 specific OID (…3375…) is contained in the returned OID. If so, a second (device specific) OID is queried to check if that value contains “big-ip”. Only then we know this is an F5 device and can go ahead and query whatever is defined by “snmp_info”. Else it is not worth querying “your” table.
I made some more modifications to make it more 1.6 / 1.7 check style like.
It is possible that there are 1-2 errors inside as i had no chance to test it.
With the release of 1.7 you can also remove a little bit of code. As there is then a “f5_bigip.include” file with common functions for this devices like a scan function.
Great! Very close to the check I wrote (but didn’t publish). I often use get_relative_date_human_readable(epochdate) which is like get_age_human_readable but automatically returns something like “10 y ago” or “in 5 d”.
Btw, I’m very grateful to @ShaunNeutron for letting me know that F5s have a MIB tree for certificates . I wasn’t aware of that but can make use of it. Until now I thought F5s can only send traps when a certificate expires. The docs don’t mention the MIB tree.
I wrote a simple nagios style plugin that, given an SSLPROFILE, will find the cert assigned to that profile and then return the expiration of that cert. Based on Shaun’s work.
#!/bin/bash
F5HOSTNAME=$1
SITE=$2
SERVERSSLPROFILE=$3
CRIT=$4
WARN=$5
TMPFILE=/tmp/f5cert.tmp_$SERVERSSLPROFILE
# set AUTH and PRIV variables
case $SITE in
XYZ)
. /omd/sites/XYZ/local/lib/nagios/plugins/f5info.xyz
;;
*)
echo invalid site, exiting
exit 3
;;
esac
snmpwalk -On -v3 -l authPriv -u checkmk -a SHA -A $AUTH -x AES -X $PRIV $F5HOSTNAME .1.3.6.1.4.1.3375.2.1 > $TMPFILE
snmpwalk -On -v3 -l authPriv -u checkmk -a SHA -A $AUTH -x AES -X $PRIV $F5HOSTNAME .1.3.6.1.4.1.3375.2.2 >> $TMPFILE
if [[ $? -ne 0 ]] ; then
echo snmpwalk error, exiting
exit 3
fi
#echo ServerProfilename is $SERVERSSLPROFILE
SERVERSSLPROFILEOID=`cat $TMPFILE | grep .1.3.6.1.4.1.3375.2.2.6.3.1.2.1..*$SERVERSSLPROFILE | awk '{print $1}'`
#echo $SERVERSSLPROFILEOID
SERVERSSLCERTOID=`echo $SERVERSSLPROFILEOID | awk -F\. {OFS=FS}'$16="5"'`
#echo $SERVERSSLCERTOID
SERVERSSLCERTNAME=`cat $TMPFILE | grep $SERVERSSLCERTOID | awk '{print $NF}'`
#echo Certname is $SERVERSSLCERTNAME
SERVERSSLCERTNAMEexpOID=`cat $TMPFILE | grep .1.3.6.1.4.1.3375.2.1.15.1.2.1.*$SERVERSSLCERTNAME | awk '{print $1}'`
#echo $SERVERSSLCERTNAMEexpOID
SERVERSSLCERTNAMEexpireationepochOID=`echo $SERVERSSLCERTNAMEexpOID | awk -F\. {OFS=FS}'$15="5"'`
#echo $SERVERSSLCERTNAMEexpireationepochOID
SERVERSSLCERTexpireepoch=`cat $TMPFILE | grep $SERVERSSLCERTNAMEexpireationepochOID | awk '{print $NF}'`
#echo $SERVERSSLCERTexpireepoch
#echo -n "Expires on "
#date -d @$SERVERSSLCERTexpireepoch
CURRENTDATEepoch=`date +%s`
#echo $CURRENTDATEepoch
DAYSTILLEXPIRE=$((($SERVERSSLCERTexpireepoch - $CURRENTDATEepoch) / 86400))
#echo $DAYSTILLEXPIRE
#rm -f $TMPFILE
if [[ $DAYSTILLEXPIRE -lt $CRIT ]] ; then
echo CRITICAL: Cert $SERVERSSLCERTNAME expires $DAYSTILLEXPIRE days less than $CRIT days
exit 2
elif [[ $DAYSTILLEXPIRE -lt WARN ]] ; then
echo WARNING: Cert $SERVERSSLCERTNAME expires $DAYSTILLEXPIRE days less than $WARN days
exit 1
else
echo OK: Cert $SERVERSSLCERTNAME expires $DAYSTILLEXPIRE days, greater or equal to $WARN days
exit 0
fi