dnssec-signer 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. #!/usr/bin/env bash
  2. #####################################################
  3. # This script require the following
  4. #
  5. # * A path structure like this:
  6. # [..path..]/<domainname.tld>/
  7. # * This path contains a zone file named `db`
  8. #
  9. # Your named.conf.local file must link to a
  10. # filed named `db.signed`, e.g
  11. #
  12. # zone "domain.tld" {
  13. # type master;
  14. # file "[..path..]/domain.tld/db.signed";
  15. # };
  16. #
  17. # USAGE:
  18. #
  19. # 1. Make `dnssec-signer` executable:
  20. # chmod +x /path/to/dnssec-signer
  21. #
  22. # 2. Run:
  23. # ./path/to/dnssec-signer <domain.tld>
  24. # 3. Or, for every domain in path
  25. # ./path/to/dnssec-signer
  26. #
  27. ######################################################
  28. SELF="$(basename ${0})"
  29. ######################################################
  30. # START OF CONFIG #
  31. ######################################################
  32. # SET YOU SYSTEM SPECIFIC DATA (which systemctl e.g) #
  33. NAMEDZONES="/etc/bind/named.conf.local"
  34. ZONESDIR="/etc/bind/zones"
  35. CHECKZONE=/usr/sbin/named-checkzone
  36. CHECKCONF=/usr/sbin/named-checkconf
  37. KEYGEN=/usr/sbin/dnssec-keygen
  38. SIGNZONE=/usr/sbin/dnssec-signzone
  39. SYSCTL=/bin/systemctl
  40. DNSSERVICE="bind9.service"
  41. LOGGER=/usr/bin/logger
  42. LOGGERFLAGN="-t $(whoami) -p daemon.info"
  43. LOGGERFLAGE="-t $(whoami) -p daemon.err"
  44. ######################################################
  45. # END OF CONFIG #
  46. ######################################################
  47. function error_msg {
  48. FOR=${1}
  49. ERRMSG="${2}"
  50. echo -e "\e[31m[${SELF}:\e[1m${FOR}\e[21m]:\e[0m ${ERRMSG}"
  51. ${LOGGER} ${LOGGERFLAGE} "[${SELF}:${FOR}]: ${ERRMSG}"
  52. }
  53. function note_msg {
  54. FOR=${1}
  55. NOTEMSG="${2}"
  56. echo -e "\e[32m[${SELF}:\e[1m${FOR}\e[21m]:\e[0m ${NOTEMSG}"
  57. ${LOGGER} ${LOGGERFLAGN} "[${SELF}:${FOR}]: ${NOTEMSG}"
  58. }
  59. # Generating keys for zone
  60. # Note, this doesnt check if they exists!
  61. function genkeys {
  62. ZONE=${1}
  63. note_msg "${ZONE}" "Generating missing ZSK and KSK"
  64. ${KEYGEN} -a NSEC3RSASHA1 -b 2048 -n ZONE "${ZONE}"
  65. if [ $? -ne 0 ]; then
  66. error_msg "${ZONE}" "Failed to generate Zone Signing Key (ZSK)"
  67. return 1
  68. fi
  69. ${KEYGEN} -f KSK -a NSEC3RSASHA1 -b 4096 -n ZONE "${ZONE}"
  70. if [ $? -ne 0 ]; then
  71. error_msg "${ZONE}" "Failed to generate Key Signing Key (KSK)"
  72. return 1
  73. fi
  74. note_msg "${ZONE}" "ZSK and KSK generated"
  75. return 0
  76. }
  77. # Sign zone
  78. # The actual signing process.
  79. function sign {
  80. ZONE="${1}"
  81. note_msg "${ZONE}" "Signing ZONE"
  82. if ! [ -d "${2}" ]; then
  83. error_msg "${ZONE}" "Path ${2} doesnt exist"
  84. return 1
  85. fi
  86. cd "${2}"
  87. echo `pwd`
  88. F="db"
  89. if ! [ -w "${F}" ]; then
  90. error_msg "${ZONE}" "Missing $(pwd)/${F}"
  91. return 1
  92. fi
  93. ZONEF="db.zone"
  94. ZONEINCF="${ZONEF}.include"
  95. KEYS=()
  96. for KEY in $(ls "./"); do
  97. if [[ "${KEY}" == "K${ZONE}"* ]] && [[ "${KEY}" == *key ]]; then
  98. KEYS[${#KEYS[@]}]="${KEY}"
  99. fi
  100. done
  101. if [ "${#KEYS[@]}" -ne 2 ]; then
  102. if [ "${#KEYS[@]}" -ne 0 ]; then
  103. rm "${KEYS[@]}"
  104. fi
  105. genkeys "${ZONE}"
  106. if [ $? -ne 0 ]; then
  107. return 1
  108. fi
  109. sign "${ZONE}"
  110. return $?
  111. fi
  112. cat "${F}" > "${ZONEINCF}"
  113. for KEY in "${KEYS[@]}"; do
  114. echo "\$INCLUDE ${KEY}" >> "${ZONEINCF}"
  115. done
  116. SALT=$(head -c 1000 /dev/random | sha1sum | cut -b 1-16)
  117. ${SIGNZONE} -A -3 "${SALT}" -N increment -f "${ZONEF}" -o "${ZONE}" -t "${ZONEINCF}"
  118. if [ $? -ne 0 ]; then
  119. error_msg "${ZONE}" "Error signing zone"
  120. return 2
  121. fi
  122. note_msg "${ZONE}" "Checking zone-file"
  123. ${CHECKZONE} "${ZONE}" "${ZONEF}"
  124. if [ $? -ne 0 ]; then
  125. error_msg "${ZONE}" "Error zone-file'${SONEF}'"
  126. return 2
  127. fi
  128. note_msg "${ZONE}" "Signing successul!"
  129. return 0
  130. }
  131. # Sign zone;
  132. # Checks that dir exists first...
  133. # and ensures we're entering and leaving correctly
  134. function signzone {
  135. SIGN="${1}"
  136. CWDIR=$(pwd)
  137. sign "${1}" "${ZONESDIR}/${SIGN}"
  138. RET=$?
  139. cd "${CWDIR}"
  140. return ${RET}
  141. }
  142. note_msg "date" "$(date)"
  143. if [[ ${EUID} -ne 0 ]]; then
  144. error_msg "${USER}" "Must execute file as root."
  145. exit 1
  146. fi
  147. # Collect arguments (zones)
  148. ZONES="${*}"
  149. IFS=' ', read -r -a ZONES <<< "${ZONES}"
  150. if [ ${#ZONES[@]} -ne 0 ]; then
  151. ERR=0
  152. for ZONE in "${ZONES[@]}"; do
  153. signzone "${ZONE}"
  154. if [ $? -eq 2 ]; then
  155. # To prevent restarting dns if failure
  156. ERR=1
  157. fi
  158. done;
  159. if [ ${ERR} -eq 0 ]; then
  160. ${CHECKCONF}
  161. if [ $? -ne 0 ]; then
  162. error_msg "${CHECKCONF}" "Error in configruation, not reloading"
  163. else
  164. note_msg "${SYSCTL}" "Restarting ${DNSSERVICE}"
  165. ${SYSCTL} restart "${DNSSERVICE}"
  166. fi
  167. else
  168. error_msg "${DNSSERVICE}" "Errors in configuration(s) for zone(s), not restarting."
  169. fi
  170. else
  171. note_msg "${ZONESDIR}" "Finding zones to sign corresponding to ${NAMEDZONES}"
  172. CWD=$(pwd)
  173. cd "${ZONESDIR}"
  174. NAMED=$(cat $NAMEDZONES)
  175. for ZONE in $(ls -d */); do
  176. ACTIVE=$(cat $NAMEDZONES | grep "\"$(basename ${ZONE})\"" | tr -d '[:space:]')
  177. if [[ "${ACTIVE}" == zone* ]]; then
  178. ZONES[${#ZONES[@]}]=$(basename ${ZONE})
  179. fi
  180. done
  181. cd ${CWD}
  182. note_msg "" "Found ${#ZONES[@]} zone(s) active"
  183. if [ "${#ZONES[@]}" -ne 0 ]; then
  184. ${SELF} "${ZONES[@]}"
  185. fi
  186. fi