Here in my company we regularly need to check for expired certificates or just to have a proactive management checking which certificates are close to their expiry dates and issue new ones to avoid service disruption.
For that reason I’ve created a simple bash script which can be used in conjunction with nagios to check for expiring certicates.
#!/bin/sh ######################################################## # # Check certificates inside a java keystore # ######################################################## TIMEOUT="timeout -k 10s 5s " KEYTOOL="$TIMEOUT keytool" THRESHOLD_IN_DAYS="30" KEYSTORE="" PASSWORD="" RET=0 ARGS=`getopt -o "p:k:t:" -l "password:,keystore:,threshold:" -n "$0" -- "$@"` function usage { echo "Usage: $0 --keystore <keystore> [--password <password>] [--threshold <number of days until expiry>]" exit } function start { CURRENT=`date +%s` THRESHOLD=$(($CURRENT + ($THRESHOLD_IN_DAYS*24*60*60))) if [ $THRESHOLD -le $CURRENT ]; then echo "[ERROR] Invalid date." exit 1 fi echo "Looking for certificates inside the keystore $(basename $KEYSTORE) expiring in $THRESHOLD_IN_DAYS day(s)..." $KEYTOOL -list -v -keystore "$KEYSTORE" $PASSWORD 2>&1 > /dev/null if [ $? -gt 0 ]; then echo "Error opening the keystore."; exit 1; fi $KEYTOOL -list -v -keystore "$KEYSTORE" $PASSWORD | grep Alias | awk '{print $3}' | while read ALIAS do #Iterate through all the certificate alias EXPIRACY=`$KEYTOOL -list -v -keystore "$KEYSTORE" $PASSWORD -alias $ALIAS | grep Valid` UNTIL=`$KEYTOOL -list -v -keystore "$KEYSTORE" $PASSWORD -alias $ALIAS | grep Valid | perl -ne 'if(/until: (.*?)\n/) { print "$1\n"; }'` UNTIL_SECONDS=`date -d "$UNTIL" +%s` REMAINING_DAYS=$(( ($UNTIL_SECONDS - $(date +%s)) / 60 / 60 / 24 )) if [ $THRESHOLD -le $UNTIL_SECONDS ]; then echo "[OK] Certificate $ALIAS expires in '$UNTIL' ($REMAINING_DAYS day(s) remaining)." else echo "[WARNING] Certificate $ALIAS expires in '$UNTIL' ($REMAINING_DAYS day(s) remaining)." RET=1 fi done echo "Finished..." exit $RET } eval set -- "$ARGS" while true do case "$1" in -p|--password) if [ -n "$2" ]; then PASSWORD=" -storepass $2"; else echo "Invalid password"; exit 1; fi shift 2;; -k|--keystore) if [ ! -f "$2" ]; then echo "Keystore not found: $1"; exit 1; else KEYSTORE=$2; fi shift 2;; -t|--threshold) if [ -n "$2" ] && [[ $2 =~ ^[0-9]+$ ]]; then THRESHOLD_IN_DAYS=$2; else echo "Invalid threshold"; exit 1; fi shift 2;; --) shift break;; esac done if [ -n "$KEYSTORE" ] then start else usage fi
All you have to do is call it like this:
./checkCertificate --keystore [YOUR_KEYSTORE_FILE] --password [YOUR_PASSWORD] --threshold [THRESHOLD_IN_DAYS]
The threshold indicates how many days are left until the expiry date is reached. I’m sure that there are several other ways of doing it but this is my own 🙂
The root_ca.cert expiration date of my company is in 30 years (2043) and this far long date seems to cause an issue when checking the validity of keystores that contain that root_ca.cert…
Do you have an idea on how to get it working in my case ?
But are you talking about an error being raised by my script? Can you please share the output of the script you you run it against the keystore that holds that certificate?
Thank you for this nice script!
I just had to exchange the awk expression
‘{print $3}’
in line 37 with
‘{print $NF}’
because the position of the alias name is language dependent (“Aliasname: xyz” => $2 in German). But it should always be the last token in the line ( => $NF ).
Indeed! 😀
Found this via Google, very useful thanks!
As you say, there are several ways of doing it, but the one thing that stood out was the unnecessary calling up of PERL just to cut out a column, in this bit here:
UNTIL=`$KEYTOOL -list -v -keystore “$KEYSTORE” $PASSWORD -alias $ALIAS | grep Valid | perl -ne ‘if(/until: (.*?)\n/) { print “$1\n”; }’`
UNTIL_SECONDS=`date -d “$UNTIL” +%s`
This could be done with awk of course, but seeing as we are writing shell code then (assuming bash or Korn available) more efficient code could be something like:
VALIDITY=$($KEYTOOL -list -v -keystore “$KEYSTORE” $PASSWORD -alias $ALIAS | grep Valid)
UNTIL_SECONDS=$(date -d “${VALIDITY##*until: }” +%s)
Saves forking for external processes. 🙂
Great tip! Thanks! 🙂
i am running the script in ksh i am getting an error in this line please help me
-t|–threshold)
if [ -n “$2” ] && [[ $2 =~ ^[0-9]+$ ]]; then THRESHOLD_IN_DAYS=$2; else echo “Invalid threshold”; exit 1; fi
shift 2;;
Thanks for this!
I had to do a few changes to get it to work:
Rename function names:
“function usage {” -> “usage () {”
“function start {” -> “start () {”
On my system keytool requires adding -storepass before the password so:
$KEYTOOL -list -v -keystore “$KEYSTORE” $PASSWORD 2>&1 > /dev/null
would become
$KEYTOOL -list -v -keystore “$KEYSTORE” -storepass $PASSWORD 2>&1 > /dev/null
I had one system with an intermediate cert in the same keystore also found with alias. Due to this it would fail on the following call:
UNTIL=`$KEYTOOL -list -v -keystore “$KEYSTORE” -storepass $PASSWORD -alias $ALIAS | grep Valid | perl -ne ‘if(/until: (.*?)\n/) { print “$1\n”; }’`
I added head -1 to only include the first validity date:
UNTIL=`$KEYTOOL -list -v -keystore “$KEYSTORE” -storepass $PASSWORD -alias $ALIAS | grep Valid | head -1 | perl -ne ‘if(/until: (.*?)\n/) { print “$1\n”; }’`
Also it does not handle special characters in the storepass, would probably be better to also wrap that up
Nice, but at least one moment – there can be cases, when one Alias have several certificates (there is message like “Certificate chain length: 3
Certificate[1]:
…
Certificate[2]:
…
Certificate[3]:
..
Thanks a lot for the script. Some minor modifications:
1.
$KEYTOOL -list -v -keystore “$KEYSTORE” $PASSWORD | grep Alias | awk ‘{print $NF}’ | while read ALIAS
replaced with :
$KEYTOOL -list -v -keystore “$KEYSTORE” $PASSWORD | sed -n -e ‘/Alias/ s/.*\: *//p’ | while read ALIAS
to grab everything after the colon (:) because some people create aliases using spaces.
2. loop over all the certificates belonging to the same alias by replacing:
VALIDITY=$($KEYTOOL -list -v -keystore “$KEYSTORE” $PASSWORD -alias “$ALIAS” | grep Valid)
with
$KEYTOOL -list -v -keystore “$KEYSTORE” $PASSWORD -alias “$ALIAS” | grep Valid | while read VALIDITY
do …. done (the done just before the previous done)
Thanks for the script. A minor modification since the keytool command is not always in the user PATH.
KEYTOOL=”`readlink -f /usr/bin/java| sed ‘s/java/keytool/’`”
A fixed version is available as a gist at https://gist.github.com/banterCZ/9bd6aa1ab49995fdf018