scripts/aech/dnssec-keys.sh

279 lines
5.7 KiB
Bash

#!/bin/sh
# dnssec-keys: DNSSEC key management tool
#
# @home: https://github.com/northox/dnssec-reverb
# @license: Simplified BSD
# Copyright (c) 2019 Tobias Strobel <git@strobeltobias.de>.
# Based on work by:
# Copyright (c) 2017 Danny Fullerton <danny@mantor.org>.
# Copyright (c) 2009-2013 Kazunori Fujiwara <fujiwara@wide.ad.jp>.
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 <<EOF
usage: $PROG keygen <zone>
$PROG rmkeys <zone>
$PROG [-s] ksk-add <zone>
$PROG [-s] ksk-roll <zone>
$PROG [-s] zsk-add <zone>
$PROG [-s] zsk-roll <zone>
$PROG [-s] zsk-rmold <zone>
$PROG sign <zone>
$PROG status <zone>
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