Dans mon précédent article sur la mise en place de dnssec, je vous avais renvoyé pour la partie supervision de l'expiration des enregistrements dnssec sur un article de Stéphane Bortzmeyer expliquant comment le mettre en place sous icinga.

Comme tout le monde n'a pas icinga sous la main, voici un petit script de ma composition qui vous enverra un mail lorsqu'un enregistrement RRSIG arrive à expiration (et donc que quelque chose s'est mal passé dans la resignature automatique par bind)

#!/bin/bash

### CONFIGURATION DEFAULTS ###

# Warn if an RRSIG expires in less than this time period
WARN_TIME="4 weeks"

# print warnings to STDOUT (true or false)
WARN_STDOUT=false

# Send warnings by mail (true or false)
WARN_MAIL=true

# Where to send mail alerts (if WARN_MAIL set to true)
SEND_WARNING_MAIL_TO="hostmaster@example.tld"
SEND_WARNING_MAIL_FROM="hostmaster@example.tld"

# Command to get zone list. Adapt to your settings.
ZONE_LIST_COMMAND="ls /etc/bind/keys"

# Signed zone file path for zone ${zone}
# Use single quotes to avoid variable expansion
ZONE_FILE_PATH='/etc/bind/zones/db.${zone}.signed'



### DO NOT MODIFY ANYTHING BELOW UNLESS YOU EXACTLY KNOW WHAT YOU ARE DOING ###


# Usage function
function usage {
  echo "USAGE: $(basename $0) [-h] [-d] [-e <warning_time>] [-m] [-f <sender>] [-t <destination>] [-s] [-q]"
  echo ""
  echo "Options:"
  echo "  -h, --help    print usage message and exit"
  echo "  -d, --debug   debug mode, show expiration date of older RRSIG record for each domain even if not in"
  echo "                warning time period (only on STDOUT)"
  echo "  -e <time>,    warn if RRSIG expires in the given time period"
  echo "  --expirein <time>"
  echo "  -m, --mail    send warning by mail"
  echo "  -f <sender>,  set warning mail sender address"
  echo "  --from <sender>"
  echo "  -t <dest>,    set warning mail destination address"
  echo "  --to <dest>"
  echo "  --nomail      do NOT send warning by mail even if enabled by default"
  echo "  -s, --stdout  show warnings on stdout"
  echo "  -q, --quiet   do NOT show warnings on stdout, even if enabled by default"
  echo ""
}

DEBUG=false

# Options parsing

PARSED_OPTIONS=$(getopt -n "$0"  -o hde:msqf:t: --long "help,debug,expirein:,mail,stdout,quiet,from:,to:,nomail,nostdout"  -- "$@")

if [ $? -ne 0 ];
then
  echo "" >&2
  usage >&2
  exit 1
fi

eval set -- "$PARSED_OPTIONS"

while true; do
  case "$1" in
    -h|--help)
      usage >&2
      exit 1
      ;;
    -d|--debug)
      DEBUG=true
      shift
      ;;
    -e|--expirein)
      case "$2" in
        "") shift 2 ;;
        *) WARN_TIME=$2 ; shift 2;;
      esac
      ;;
    -m|--mail)
      WARN_MAIL=true
      shift
      ;;
    -f|--from)
      case "$2" in
        "") shift 2 ;;
        *) SEND_WARNING_MAIL_FROM=$2 ; shift 2;;
      esac
      ;;
    -t|--to)
       case "$2" in
        "") shift 2 ;;
        *) SEND_WARNING_MAIL_TO=$2 ; shift 2;;
      esac
      ;;
    --nomail)
      WARN_MAIL=false
      shift
      ;;
    -s|--stdout)
      WARN_STDOUT=true
      shift
      ;;
    -q|--quiet|--nostdout)
      WARN_STDOUT=false
      shift
      ;;
    --)
      shift
      break
      ;;
  esac
done

# Warn time limit since epoch
WARN_EPOCH=$(date --date "+${WARN_TIME}" +"%s")

# For each zone
for zone in $( $ZONE_LIST_COMMAND ); do

  # Get expiration time of next expiring RRSIG
  N=$(named-compilezone -q -D -f raw -o - ${zone} $(eval echo ${ZONE_FILE_PATH}) | grep "IN RRSIG" |awk '{ print $9 }' |sort -n |head -1)

  # Transform to epoch (usefull for date comparison)
  EXP_EPOCH=$(date --date "${N:4:2}/${N:6:2}/${N:0:4} ${N:8:2}:${N:10:2}:${N:12:2}" +"%s")
  EXP_HUMANREADABLE=$(LANG=C date --date "${N:4:2}/${N:6:2}/${N:0:4} ${N:8:2}:${N:10:2}:${N:12:2}")

  # Warn if in expiration warning time
  if [ ${EXP_EPOCH} -le ${WARN_EPOCH} ]; then
    WARN_MSG="\

DNSSEC EXPIRATION WARNING
-------------------------

Domain ${zone} has an RRSIG expiring in less than ${WARN_TIME}
Next expiration date on (${EXP_EPOCH}) ${EXP_HUMANREADABLE}
"
    $WARN_STDOUT && echo -e "${WARN_MSG}"
    if $WARN_MAIL; then
      WARN_MAIL_HEADERS="\
From: ${SEND_WARNING_MAIL_FROM}
To: <${SEND_WARNING_MAIL_TO}>
Subject: ***DNSSEC RRSIG EXPIRATION WARNING ***
Date: $(date -R)
"
      echo -e "${WARN_MAIL_HEADERS}\n${WARN_MSG}" | sendmail -t -oi -f "${SEND_WARNING_MAIL_FROM}"
    fi
  else
    $DEBUG && echo "Next Expiration of zone ${zone} (no warning) on (${EXP_EPOCH}) ${EXP_HUMANREADABLE}"
  fi
done
exit 0

Tout ce que vous avez à faire, c'est de déposer ce scripts dans /etc/cron.daily (n'oubliez pas de le rendre exécutable) et adapter les valeurs par défaut en début de script et hop, vous recevrez un mail 3 jours avant l'expiration des enregistrements RRSIG.

La variable WARN_TIME contient la période de temps dans laquelle la présence de l'expiration d'un enregistrement RRSIG provoque une alarme. C'est une "date string" compréhensible par la commande date. Par exemple, 3 days provoquera une alarme si un enregistrement RRSIG arrive a expiration dans les 3 prochains jours. On peut également utiliser "Next thursday" pour les domaines dont un enregistrement RRSIG arrive a expiration avant jeudi prochain, ou bien "next month".

Les variables WARN_STDOUT et WARN_MAIL servent respectivement à afficher les warning sur la sortie standard ou à les envoyer par mail.

Les variables SEND_WARNING_MAIL_TOet SEND_WARNING_MAIL_FROM servent à définir respectivement le(s) destinataire(s) et l'expéditeur (d'en-tête et d'enveloppe) du mail d'alarme.

La variable ZONE_LIST_COMMANDindique au script comment obtenir la liste des domaines à checker. Pour mon cas, chaque domaine a ses clés dans un sous-répertoire spécifique de /etc/bind/keys dont le nom est le nom du domaine. Ainsi, je me contente de lister le contenu de /etc/bind/keys. Toute autre commande qui fournit la liste des domaines à vérifier fera l'affaire. Au pire, le cat d'un fichier texte.

Enfin, la variable ZONE_FILE_PATH indique le chemin du fichier de zone signé pour la zone ${zone}. Pensez à utiliser des simples quotes pour éviter l'expansion de la variable ${zone}.

J'ai préféré baser ce script sur le contenu des fichiers de zone signés plutôt que sur une interrogation du DNS.

Vous pouvez aussi l'appeler manuellement avec les options qui vont bien :

USAGE: dnssec-monitor [-h] [-d] [-e <warning_time>] [-m] [-f <sender>] [-t <destination>] [-s] [-q]

Options:
  -h, --help    print usage message and exit
  -d, --debug   debug mode, show expiration date of older RRSIG record for each domain even if not in
                warning time period (only on STDOUT)
  -e <time>,    warn if RRSIG expires in the given time period
  --expirein <time>
  -m, --mail    send warning by mail
  -f <sender>,  set warning mail sender address
  --from <sender>
  -t <dest>,    set warning mail destination address
  --to <dest>
  --nomail      do NOT send warning by mail even if enabled by default
  -s, --stdout  show warnings on stdout
  -q, --quiet   do NOT show warnings on stdout, even if enabled by default

Par exemple, pour afficher le résultat sur la sortie standard, ne pas envoyer de mail, alarmer s'il y a une expiration dans les 16 prochains jours, et afficher les prochaines dates d'expiration pour chaque domaine même s'il n'y a pas d'expiration dans la période indiquée :

$ ./dnssec-monitor --nomail -s -e "16 days" -d
Next Expiration of zone example.tld (no warning) on (1404131654) Mon Jun 30 14:34:14 CEST 2014
Next Expiration of zone example2.tld (no warning) on (1404130965) Mon Jun 30 14:22:45 CEST 2014
Next Expiration of zone example3.tld (no warning) on (1404133571) Mon Jun 30 15:06:11 CEST 2014

DNSSEC EXPIRATION WARNING
-------------------------

Domain example4.tld has an RRSIG expiring in less than 16 days
Next expiration date on (1403990327) Sat Jun 28 23:18:47 CEST 2014

Comments

comments powered by Disqus