#!/usr/bin/perl -w # SSL Certificate check for Nagios # Written by Tim Gibbon (nagios@reversemidastouch.com) # Last Modified: 14-Oct-2008 # # Description: # # This plugin will check the expiry date of a remote SSL # certificate and will warn if the cert is due to expire. # $main::VERSION=0.02; ## LICENCE ########################################################### ## This program 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; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## END LICENCE ####################################################### ############################################################################### ###Add the following to your nagios config where is the ###fully qualified domain name of the certificate to inspect #define service{ # use generic-service # host_name # service_description Server Certs # is_volatile 0 # check_period 24x7 # max_check_attempts 4 # normal_check_interval 1440 # retry_check_interval 5 # contact_groups linux-admins # notification_interval 1440 # notification_period 24x7 # notification_options c,r ########check_command check-ssl-cert!warningdays!criticaldays # check_command check-ssl-cert!703!10 #define host{ # use generic-host # host_name # address # max_check_attempts 4 # notification_interval 480 # notification_period workhours # check_command check-ssl-cert # contact_groups linux-admins # } ############################################################################### ############################################################################### #checkcommands.cfg addition #define command{ # command_name check-ssl-cert # command_line $USER1$/check_ssl_cert_alternative.pl -H $HOSTADDRESS$ -w $ARG1$ -c #$ARG2$ # } my $exit_status; use strict; use Getopt::Std; use File::Basename; use Time::Local; # Location of the openssl command (if not in path) my $openssl_path="/usr/bin/openssl"; my $default_warning=30; #Time before we get ORANGE alert in days my $default_critical=14; #Time before we get RED alert in days # Don't change anything below here # Nagios return codes my $STATE_OK=0; my $STATE_WARNING=1; my $STATE_CRITICAL=2; my $STATE_UNKNOWN=3; my $STATE_DEPENDENT=4; my $progname=basename $0; my %months= ( 'Jan'=> 0, 'Feb' => 1, 'Mar' => 2, 'Apr' =>3, 'May' =>4, 'Jun' =>5, 'Jul' =>6, 'Aug' =>7, 'Sep' =>8, 'Oct' =>9, 'Nov' =>10, 'Dec' =>11); unless (-x $openssl_path ){ print "UNKNOWN: $openssl_path not found or is not executable by the nagios user\n"; my $exitstatus=$STATE_UNKNOWN; exit $exitstatus; } my ($hoststring,$warning,$critical)=check_usage ($default_warning,$default_critical,$main::VERSION); #open (DEBUG, ">/tmp/bobbins.log"); #print (DEBUG "Running $progname against host $hoststring using $warning/$critical \n"); #close (DEBUG); my ($certtimeleft,$certenddate)=run_openssl_compare_times(); ############################################# #print "$hoststring $certtimeleft Days left\n"; print "$hoststring expires on $certenddate\n"; ############################################# #Make the comparisons with our incoming/default params# if ($certtimeleft <= $critical){ # print ("Exiting critical\n"); exit $STATE_CRITICAL; } elsif ($certtimeleft <= $warning ){ # print ("Exiting warning\n"); exit $STATE_WARNING; } else { # print ("Exiting ok\n"); exit $STATE_OK; } ####################################################### # End of program ####################################################### ######Should never get here exit $STATE_UNKNOWN; ########################### ################################################################################ sub check_usage { my $alert_warning=$_[0]; my $alert_critical=$_[1]; my $version=$main::VERSION; my %cmd_options; getopt ("vhwcH",\%cmd_options); if ($cmd_options{h}){ print_usage($version); } unless ($cmd_options{H}){ print_usage($version); } my $hostname_port_number; if ($cmd_options{H} =~ /([\w+\.*]+\:\d+)/){ $hostname_port_number=$1; # print ("Hostname = $hostname_port_number\n"); } elsif ($cmd_options{H} !~ /\:\d+/){ $hostname_port_number=$cmd_options{H}.":443"; # print ("Hostname = $hostname_port_number\n"); } else { print("You must provide a hostname in the format hostname:portnumber\n"); print_usage(); } if (($cmd_options{w})&&($cmd_options{w} =~ /\d+/)){ $alert_warning=$cmd_options{w}; # print ("Warning limit defined, using $alert_warning\n"); } if (($cmd_options{c})&&($cmd_options{c} =~ /\d+/)){ $alert_critical=$cmd_options{c}; # print ("Critical limit defined, using $alert_critical\n"); } # print ("Ending check_usage - warning = $alert_warning, critical = $alert_critical\n"); return($hostname_port_number,$alert_warning,$alert_critical); }#End sub ################################################################################ sub print_usage { my $progname =basename($0); my $version=$_[0]; print ("$0 $version\n"); print ("Syntax:\n"); print ("$progname -H [:port] [-w ] [-c ]\n"); my $exitstatus=$STATE_UNKNOWN; exit $exitstatus; } ############################################################################## sub run_openssl_compare_times { my @openssl_output; open (CMD,"echo | $openssl_path s_client -connect $hoststring 2>/dev/null| $openssl_path x509 -noout -enddate |") or print_usage() ; while (){ chomp; push (@openssl_output,"$_"); } close (CMD); ################################################################################ ############################################################################### my ($junk,$enddate); foreach (@openssl_output){ next unless /notAfter/; ($junk,$enddate) = split (/\=/); } ############################################################################### #At this stage we have the data stored in enddate, we just need to break #it up and compare to today ####Split into component parts and place into epoch time my ($month,$day,$time,$year,$tz)=split(/\s+/,$enddate); my ($hour,$min,$sec)=split(/\:/,$time); my $expiration_time=timegm($sec, $min, $hour, $day, $months{$month}, $year-1900); ######################################################## ################Make the comparison#################################### my $today=time; my $timeleft=int(($expiration_time-$today)/(86400)); #86400 secs in day return ($timeleft,$enddate); ####################################################################### }#End sub