#!/bin/sh # dnssec-keys: DNSSEC key management tool # # @home: https://github.com/northox/dnssec-reverb # @license: Simplified BSD # Copyright (c) 2019 Tobias Strobel . # Based on work by: # Copyright (c) 2017 Danny Fullerton . # Copyright (c) 2009-2013 Kazunori Fujiwara . PROG=`basename $0` DIR=`dirname $0` KEYDIR="/var/cache/bind/keys" keygen="/usr/sbin/dnssec-keygen" settime="/usr/sbin/dnssec-settime" key2ds="/usr/sbin/dnssec-dsfromkey" control="/usr/sbin/rndc" RELOAD_COMMAND="$control loadkeys \$ZONE" KSK_PARAM="-n zone -a ECDSAP384SHA384 -f ksk" ZSK_PARAM="-n zone -a ECDSAP384SHA384" DNSRECORD_PARAM="-2" NOW=`date +%Y%m%d%H%M%S` DEFAULT_EXPIRE=33 LOCKF="" Fatal() { [ "$LOCKF" != "" ] && rm $LOCKF echo $PROG: $1 >&2 exit 1 } # defaults [ "$KEYDIR" = "" ] && Fatal "\$KEYDIR not set" [ -d "$KEYDIR" ] || Fatal "\$KEYDIR not a directory ($KEYDIR)" [ "$KEYBACKUPDIR" = "" ] && KEYBACKUPDIR="$KEYDIR/backup" [ "$DNSRECORDDIR" = "" ] && DNSRECORDDIR="$KEYDIR/dnsrecord" HEAD_ZSKNAME="zsk-" HEAD_KSKNAME="ksk-" HEAD_ZSSNAME="zss-" HEAD_ZSRNAME="zsr-" # Removed ZSK HEAD_KSSNAME="kss-" # setup [ ! -d $KEYBACKUPDIR ] && mkdir -p $KEYBACKUPDIR [ ! -d $DNSRECORDDIR ] && mkdir -p $DNSRECORDDIR cd $KEYDIR _check_file() { while [ "$1" != "" ]; do [ ! -s "$1" ] && Fatal "$1 does not exist." shift done } _check_nofile() { while [ "$1" != "" ]; do [ -f "$1" ] && Fatal "$1 exist." shift done } _usage() { [ "$LOCKF" != "" ] && rm $LOCKF cat < $PROG rmkeys $PROG [-s] ksk-add $PROG [-s] ksk-roll $PROG [-s] zsk-add $PROG [-s] zsk-roll $PROG [-s] zsk-rmold $PROG sign $PROG status EOF exit 1 } sign() { chmod g+r *.* eval $RELOAD_COMMAND } status() { DNSRECORD_FILE_TMP="$DNSRECORD_FILE.tmp" if [ -f $KSK_FILE ]; then echo -n "$ZONE's KSK = " cat $KSK_FILE; tail -n1 `cat $KSK_FILE`.key | tee $DNSRECORD_FILE_TMP $key2ds $_DNSRECORD_PARAM `cat $KSK_FILE`.key | tee -a $DNSRECORD_FILE_TMP fi if [ -f $KSK_S_FILE ]; then echo -n "$ZONE's next KSK = " cat $KSK_S_FILE; tail -n1 `cat $KSK_S_FILE`.key | tee $DNSRECORD_FILE_TMP $key2ds $_DNSRECORD_PARAM `cat $KSK_S_FILE`.key | tee -a $DNSRECORD_FILE_TMP fi if [ -f $ZSK_FILE ]; then echo -n "$ZONE's ZSK = " cat $ZSK_FILE; fi if [ -f $ZSK_S_FILE ]; then echo -n "$ZONE's next ZSK = " cat $ZSK_S_FILE; fi if [ -f $ZSK_R_FILE ]; then echo -n "$ZONE's previous ZSK = " cat $ZSK_R_FILE; fi mv -f $DNSRECORD_FILE_TMP $DNSRECORD_FILE } keygensub() { echo "$keygen $1 $2" newfile="$3" tmpfile="$3.tmp" _KEY=`$keygen $1 $2` [ -f $_KEY.ds ] && rm $_KEY.ds if [ ! -s $_KEY.key ]; then rm $_KEY.key Fatal "cannot write new key: $1 $2 $3" fi echo $_KEY > $tmpfile read _KEY2 < $tmpfile if [ "$_KEY" != "$_KEY2" ]; then rm $tmpfile rm $_KEY.key Fatal "cannot write $tmpfile" fi mv $tmpfile $newfile } removekeys_sub() { if [ -f $1 ]; then KEY=`head -1 $1` if [ -f $KEY.key ]; then mv $KEY.key $KEY.private $KEYBACKUPDIR/ fi fi } remove_previouskey() { if [ -f $ZSK_R_FILE ]; then removekeys_sub $ZSK_R_FILE mv $ZSK_R_FILE "$KEYBACKUPDIR/removed-ZSK-$NOW-$ZONE" fi } if [ "$1" = "" -o "$1" = "-h" -o "$1" = "-?" -o "$1" = "--help" ]; then _usage exit 0 elif [ "$1" = "-s" -o "$1" = "--sign" ];then SIGN_OPT=1 shift fi CMD="$1" shift if [ "$1" = "" ]; then Fatal "A zone must be provided." else ZONELIST="$*" fi for ZONE in $ZONELIST do LOCKF="$ZONE.lock" TMPF="$ZONE.$$" KSK_FILE="$HEAD_KSKNAME$ZONE" ZSK_FILE="$HEAD_ZSKNAME$ZONE" KSK_S_FILE="$HEAD_KSSNAME$ZONE" ZSK_S_FILE="$HEAD_ZSSNAME$ZONE" ZSK_R_FILE="$HEAD_ZSRNAME$ZONE" DNSRECORD_FILE="$DNSRECORDDIR/$ZONE" ZONE_=`echo $ZONE | tr .- __` eval _KSK_PARAM=\${KSK_PARAM_$ZONE_:-$KSK_PARAM} eval _ZSK_PARAM=\${ZSK_PARAM_$ZONE_:-$ZSK_PARAM} eval _DNSRECORD_PARAM=\${DNSRECORD_PARAM_$ZONE_:-$DNSRECORD_PARAM} echo "LOCK$$" > $TMPF LOCKSTR=`cat $TMPF` if [ ! -f $TMPF -o "LOCK$$" != "$LOCKSTR" ]; then Fatal "cannot write lock file $TMPF" fi if ln $TMPF $LOCKF; then : else rm $TMPF echo "zone $ZONE locked" continue fi rm $TMPF case $CMD in keygen) _check_nofile $KSK_FILE $ZSK_FILE keygensub "$_KSK_PARAM" $ZONE $KSK_FILE keygensub "$_ZSK_PARAM" $ZONE $ZSK_FILE status ;; rmkeys) removekeys_sub $KSK_FILE removekeys_sub $ZSK_FILE removekeys_sub $KSK_S_FILE removekeys_sub $ZSK_S_FILE rm $KSK_FILE $ZSK_FILE $KSK_S_FILE $ZSK_S_FILE status ;; ksk-add) _check_nofile $KSK_S_FILE keygensub "$_KSK_PARAM" $ZONE $KSK_S_FILE status ;; ksk-roll) _check_file $KSK_FILE $KSK_S_FILE KSK=`head -1 $KSK_FILE` KSS=`head -1 $KSK_S_FILE` _check_file $KSK.key $KSS.key $KSK.private $KSS.private mv $KSK.key $KSK.private $KEYBACKUPDIR/ mv $KSK_S_FILE $KSK_FILE OLDKSK="$KSK" KSK="$KSS" KSS="" echo "$ZONE 's KSK: valid -> removed: $OLDKSK" echo "$ZONE 's KSK: next -> current: $KSK" status ;; zsk-add) _check_nofile $ZSK_S_FILE keygensub "$_ZSK_PARAM" $ZONE $ZSK_S_FILE status ;; zsk-roll) _check_file $ZSK_FILE $ZSK_S_FILE ZSK=`head -1 $ZSK_FILE` ZSS=`head -1 $ZSK_S_FILE` _check_file $ZSK.key $ZSS.key $ZSK.private $ZSS.private remove_previouskey mv $ZSK_FILE $ZSK_R_FILE mv $ZSK_S_FILE $ZSK_FILE OLDZSK="$ZSK" ZSK="$ZSS" ZSS="" echo "$ZONE 's ZSK: valid -> previous: $OLDZSK" echo "$ZONE 's ZSK: next -> current: $ZSK" status ;; zsk-rmold) _check_file $ZSK_R_FILE remove_previouskey status ;; sign) sign ;; status) status ;; *) echo "unknown command: $CMD" _usage ;; esac rm $LOCKF done [ "$SIGN_OPT" = 1 ] && sign exit 0