dnssec-signer 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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. note_msg "${ZONE}" "Validating unsigned zone file"
  96. ${CHECKZONE} "${ZONE}" "${F}"
  97. if [ $? -ne 0 ]; then
  98. error_msg "${ZONE}" "Error(s) in zone file"
  99. if [ -r "${ZONEF}" ]; then
  100. note_msg "${ZONE}" "Existing signed zone, allowing restart"
  101. return 1
  102. else
  103. note_msg "${ZONE}" "No existing signed zone, disallowing restart"
  104. return 2
  105. fi
  106. fi
  107. KEYS=()
  108. for KEY in $(ls "./"); do
  109. if [[ "${KEY}" == "K${ZONE}"* ]] && [[ "${KEY}" == *key ]]; then
  110. KEYS[${#KEYS[@]}]="${KEY}"
  111. fi
  112. done
  113. if [ "${#KEYS[@]}" -ne 2 ]; then
  114. if [ "${#KEYS[@]}" -ne 0 ]; then
  115. rm "${KEYS[@]}"
  116. fi
  117. genkeys "${ZONE}"
  118. if [ $? -ne 0 ]; then
  119. return 1
  120. fi
  121. sign "${ZONE}"
  122. return $?
  123. fi
  124. cat "${F}" > "${ZONEINCF}"
  125. for KEY in "${KEYS[@]}"; do
  126. echo "\$INCLUDE ${KEY}" >> "${ZONEINCF}"
  127. done
  128. SALT=$(head -c 1000 /dev/random | sha1sum | cut -b 1-16)
  129. ${SIGNZONE} -A -3 "${SALT}" -N increment -f "${ZONEF}" -o "${ZONE}" -t "${ZONEINCF}"
  130. if [ $? -ne 0 ]; then
  131. error_msg "${ZONE}" "Error signing zone"
  132. return 2
  133. fi
  134. note_msg "${ZONE}" "Checking zone-file"
  135. ${CHECKZONE} "${ZONE}" "${ZONEF}"
  136. if [ $? -ne 0 ]; then
  137. error_msg "${ZONE}" "Error zone-file'${SONEF}'"
  138. return 2
  139. fi
  140. note_msg "${ZONE}" "Signing successul!"
  141. return 0
  142. }
  143. # Sign zone;
  144. # Checks that dir exists first...
  145. # and ensures we're entering and leaving correctly
  146. function signzone {
  147. SIGN="${1}"
  148. CWDIR=$(pwd)
  149. sign "${1}" "${ZONESDIR}/${SIGN}"
  150. RET=$?
  151. cd "${CWDIR}"
  152. return ${RET}
  153. }
  154. note_msg "date" "$(date)"
  155. if [[ ${EUID} -ne 0 ]]; then
  156. error_msg "${USER}" "Must execute file as root."
  157. exit 1
  158. fi
  159. # Collect arguments (zones)
  160. ZONES="${*}"
  161. IFS=' ', read -r -a ZONES <<< "${ZONES}"
  162. if [ ${#ZONES[@]} -ne 0 ]; then
  163. ERR=0
  164. for ZONE in "${ZONES[@]}"; do
  165. signzone "${ZONE}"
  166. if [ $? -eq 2 ]; then
  167. # To prevent restarting dns if failure
  168. ERR=1
  169. fi
  170. done;
  171. if [ ${ERR} -eq 0 ]; then
  172. ${CHECKCONF}
  173. if [ $? -ne 0 ]; then
  174. error_msg "${CHECKCONF}" "Error in configruation, not reloading"
  175. else
  176. note_msg "${SYSCTL}" "Restarting ${DNSSERVICE}"
  177. ${SYSCTL} restart "${DNSSERVICE}"
  178. fi
  179. else
  180. error_msg "${DNSSERVICE}" "Errors in configuration(s) for zone(s), not restarting."
  181. fi
  182. else
  183. note_msg "${ZONESDIR}" "Finding zones to sign corresponding to ${NAMEDZONES}"
  184. CWD=$(pwd)
  185. cd "${ZONESDIR}"
  186. NAMED=$(cat $NAMEDZONES)
  187. for ZONE in $(ls -d */); do
  188. ACTIVE=$(cat $NAMEDZONES | grep "\"$(basename ${ZONE})\"" | tr -d '[:space:]')
  189. if [[ "${ACTIVE}" == zone* ]]; then
  190. ZONES[${#ZONES[@]}]=$(basename ${ZONE})
  191. fi
  192. done
  193. cd ${CWD}
  194. note_msg "" "Found ${#ZONES[@]} zone(s) active"
  195. if [ "${#ZONES[@]}" -ne 0 ]; then
  196. ${SELF} "${ZONES[@]}"
  197. fi
  198. fi