20091214 a simple ssl site monitor - plembo/onemoretech GitHub Wiki

title: A simple SSL site monitor link: https://onemoretech.wordpress.com/2009/12/14/a-simple-ssl-site-monitor/ author: lembobro description: post_id: 209 created: 2009/12/14 14:53:35 created_gmt: 2009/12/14 14:53:35 comment_status: open post_name: a-simple-ssl-site-monitor status: publish post_type: post

A simple SSL site monitor

In some places the same guy who is responsible for the day to day functioning of a company’s web servers also controls the account with whatever 3rd party SSL certificate authority they get their certificates from. Since most commercial issuers (and even some non-commercial ones, like CACert) will send a friendly reminder (or two) when a certificate they issued is about to expire, this reduces the risk that a cert may expire and create havoc in the environment (what kind of havoc is a subject for another post).

But some of us aren’t so lucky as to have access to our 3rd party issuer account, however, and need some independent means of avoiding being blindsided by an expired certificate.

Following is a simple perl script that will read a list of FDQNs (in the format “WWW.EXAMPLE.COM”) and check to see if the SSL certificates for the target web sites have expired or are about to expire. The script first tries to connect to the target at port 443 (or whatever other port you might be using for SSL) with Net::Ping to first determine if the site can be reached, and then uses Net::SSL::ExpireDate to see if the certificate has expired or is about to expire (the variable “$months” tells it the amount of notice you’d like). In the example below the report is dumped in HTML format to a web directory that can be consulted by sysadmins. Another variation could use MIME::Lite to build an e-mail message for distribution to the admins.

#!/usr/bin/perl
# sslcert_checker.pl Take a list of web servers (FDQN's) and check to see:
# (a) if they're listening on SSL port; and (b) if their certs are expired or about to expire.
	
use strict;
use Net::Ping;
use IO::Socket::SSL;
use Net::SSL::ExpireDate;
use Custom::Text::ParseWords;
	
my $HOME = $ENV{'HOME'};
my $WWW = "/var/www/html/webreports";
	
my $cssfile = "$WWW/css/reports.css";
my $infile = "$WWW/etc/sslsitelist.txt";
my $filename = "sslsitestatus.html";
my $outfile = "$WWW/latest/$filename";
my $timestamp = localtime();
	
my $months = '1';
	
make_report();
	
sub make_report {
	
 open FH, ">$outfile" or die $!;
	
 print FH "<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">n";
 print FH "<html>n";
 print FH "<head>n";
 print FH "<meta http-equiv="Content-Type" content="text/html; charset=utf-8">n";
 print FH "<meta name="Author" content="Phil Lembo">n";
 print FH "<meta http-equiv="Content-Style-Type" content="text/css">n";
 print FH "<style>";
 open FH1, "<$cssfile" or die $!;
 while(<FH1>) {
	my $line = $_;
	print FH $line;
 }
 close FH1;
 print FH "</style>n";
 print FH "<title>SSL Website Status Report $timestamp</title>n";
 print FH "</head>n";
 print FH "<body>n";
 print FH "<center><h1>SSL Website Status</h1>n";
 print FH "<h2>Report for $timestamp</h2></center>n";
 print FH "<p>n";
	
 print FH "<p>List of all SSL websites showing status if SSL certificate has or is about to expire</p>n";
	
 print FH "<center><table>n";
 print FH "<tr><th>Server URL</th><th>Status</th>n";
 close FH;
	
 check_hosts();
	
 open FH, ">>$outfile" or die $!;
 print FH "</table></center>n";
 print FH "</body></html>n";
 close FH;
}
	
sub check_hosts {
	
 open FH1, "<$infile" or die $!;
 while (<FH1>) {
	chomp;
	my( $sslhost
	)  = ( &parse_line(',',0,$_));
	$sslhost = lc($sslhost);
	check_ssl($sslhost);
 }
close FH1;
}
	
sub check_ssl {
	
  my $sslhost = @_[0];
  my $url = "https://".$sslhost;
  my $ping = Net::Ping->new('tcp',2) ;
  $ping->{port_num} = getservbyname("https", "tcp");
  $ping->service_check({1});
	
  my $avail = $ping->ping($sslhost, 2);
	
  open FH, ">>$outfile" or die $!;
	
  print FH "&lttr><td>$url</td>n";
	
  if ($avail == 1) {
	
  	my $ed = Net::SSL::ExpireDate->new( https => $sslhost) or warn $!;
 	my $expire_date = $ed->expire_date;
 	my $client = IO::Socket::SSL->new( "$sslhost:https");
	my $expired = $ed->is_expired;
 	my $expires = $ed->is_expired("$months months");
	
 	if($expired) {
		print $url, " cert expired ", $expire_date, "n";
		print FH "<td>cert expired $expire_date</td&gt</tr>n";
 	}
 	elsif($expires) {
		print $url, " cert expires ", $expire_date, "n";
		print FH "<td>cert expires $expire_date</td></tr>n";
 	}
 	else {
	        print $url, " OKn";
		print FH "<td>OK</td></tr>n";
 	}
 }
 else {
		print $url, " failed to connectn";
		print FH "<td>failed to connect</td></tr>n";
		next;
 }
}

Note for Solaris: Building Net::SSL::ExpireDate on Solaris 10 for Sparc turned out to be a real joy.

Although the boxes had the standard Sun Freeware package for OpenSSL 0.9.8k installed and everything was mapped properly in $LD_LIBRARY_PATH, CPPFLAGS and CFLAGS, the install kept failing on Crypto::OpenSSL::X509, with that package’s Makefile.PL complaining that “* libcrypto is not installed or not in the default path. Aborting”.

After Googling around a bit and not coming up with anything meaningful, I decided to poke around Makefile.PL and wound up commenting out the “exit;” on line 29, right under the warning. The Crypto module installed without error after that. I still got a couple of errors on test for Net::SSL::ExpireDate, but my test script worked fine after the install so I’m not going to sweat it.

Did I mention that things installed without error on RHEL 5.4?

Update:

Corrected a bunch of typos that were either already there or introduced by the Wordpress to Flatpress conversion process. Also fixed a problem with the service availability code (it wasn’t really working). My apologies to all.

Copyright 2004-2019 Phil Lembo

⚠️ **GitHub.com Fallback** ⚠️