dnssec-signer 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. JOURCTL=/bin/journalctl
  41. DNSSERVICE="bind9.service"
  42. LOGGER=/usr/bin/logger
  43. LOGGERFLAGN="-t $(whoami) -p daemon.info"
  44. LOGGERFLAGE="-t $(whoami) -p daemon.err"
  45. ######################################################
  46. # END OF CONFIG #
  47. ######################################################
  48. function error_msg {
  49. FOR=${1}
  50. ERRMSG="${2}"
  51. echo -e "\e[31m[${SELF}:\e[1m${FOR}\e[21m]:\e[0m ${ERRMSG}"
  52. ${LOGGER} ${LOGGERFLAGE} "[${SELF}:${FOR}]: ${ERRMSG}"
  53. }
  54. function note_msg {
  55. FOR=${1}
  56. NOTEMSG="${2}"
  57. echo -e "\e[32m[${SELF}:\e[1m${FOR}\e[21m]:\e[0m ${NOTEMSG}"
  58. ${LOGGER} ${LOGGERFLAGN} "[${SELF}:${FOR}]: ${NOTEMSG}"
  59. }
  60. # Generating keys for zone
  61. # Note, this doesnt check if they exists!
  62. function genkeys {
  63. ZONE=${1}
  64. note_msg "${ZONE}" "Generating missing ZSK and KSK"
  65. ${KEYGEN} -a NSEC3RSASHA1 -b 2048 -n ZONE "${ZONE}"
  66. if [ $? -ne 0 ]; then
  67. error_msg "${ZONE}" "Failed to generate Zone Signing Key (ZSK)"
  68. return 1
  69. fi
  70. ${KEYGEN} -f KSK -a NSEC3RSASHA1 -b 4096 -n ZONE "${ZONE}"
  71. if [ $? -ne 0 ]; then
  72. error_msg "${ZONE}" "Failed to generate Key Signing Key (KSK)"
  73. return 1
  74. fi
  75. note_msg "${ZONE}" "ZSK and KSK generated"
  76. return 0
  77. }
  78. # Sign zone
  79. # The actual signing process.
  80. function sign {
  81. ZONE="${1}"
  82. note_msg "${ZONE}" "Signing ZONE"
  83. if ! [ -d "${2}" ]; then
  84. error_msg "${ZONE}" "Path ${2} doesnt exist"
  85. return 1
  86. fi
  87. cd "${2}"
  88. echo `pwd`
  89. F="db"
  90. if ! [ -w "${F}" ]; then
  91. error_msg "${ZONE}" "Missing $(pwd)/${F}"
  92. return 1
  93. fi
  94. ZONEF="db.zone"
  95. ZONEINCF="${ZONEF}.include"
  96. note_msg "${ZONE}" "Validating unsigned zone file"
  97. ${CHECKZONE} "${ZONE}" "${F}"
  98. if [ $? -ne 0 ]; then
  99. error_msg "${ZONE}" "Error(s) in zone file"
  100. if [ -r "${ZONEF}" ]; then
  101. note_msg "${ZONE}" "Existing signed zone, allowing restart"
  102. return 1
  103. else
  104. note_msg "${ZONE}" "No existing signed zone, disallowing restart"
  105. return 2
  106. fi
  107. fi
  108. KEYS=()
  109. for KEY in $(ls "./"); do
  110. if [[ "${KEY}" == "K${ZONE}"* ]] && [[ "${KEY}" == *key ]]; then
  111. KEYS[${#KEYS[@]}]="${KEY}"
  112. fi
  113. done
  114. if [ "${#KEYS[@]}" -ne 2 ]; then
  115. if [ "${#KEYS[@]}" -ne 0 ]; then
  116. rm "${KEYS[@]}"
  117. fi
  118. genkeys "${ZONE}"
  119. if [ $? -ne 0 ]; then
  120. return 1
  121. fi
  122. sign "${ZONE}" "${2}"
  123. return $?
  124. fi
  125. cat "${F}" > "${ZONEINCF}"
  126. for KEY in "${KEYS[@]}"; do
  127. echo "\$INCLUDE ${KEY}" >> "${ZONEINCF}"
  128. done
  129. SALT=$(head -c 1000 /dev/random | sha1sum | cut -b 1-16)
  130. ${SIGNZONE} -A -3 "${SALT}" -N increment -f "${ZONEF}" -o "${ZONE}" -t "${ZONEINCF}"
  131. if [ $? -ne 0 ]; then
  132. error_msg "${ZONE}" "Error signing zone"
  133. return 2
  134. fi
  135. note_msg "${ZONE}" "Checking zone-file"
  136. ${CHECKZONE} "${ZONE}" "${ZONEF}"
  137. if [ $? -ne 0 ]; then
  138. error_msg "${ZONE}" "Error zone-file'${SONEF}'"
  139. return 2
  140. fi
  141. note_msg "${ZONE}" "Signing successul!"
  142. return 0
  143. }
  144. # Sign zone;
  145. # Checks that dir exists first...
  146. # and ensures we're entering and leaving correctly
  147. function signzone {
  148. SIGN="${1}"
  149. CWDIR=$(pwd)
  150. sign "${1}" "${ZONESDIR}/${SIGN}"
  151. RET=$?
  152. cd "${CWDIR}"
  153. return ${RET}
  154. }
  155. note_msg "date" "$(date)"
  156. if [[ ${EUID} -ne 0 ]]; then
  157. error_msg "${USER}" "Must execute file as root."
  158. exit 1
  159. fi
  160. # Collect arguments (zones)
  161. ZONES="${*}"
  162. IFS=' ', read -r -a ZONES <<< "${ZONES}"
  163. if [ ${#ZONES[@]} -ne 0 ]; then
  164. note_msg "${#ZONES[@]}" "Start signing zones"
  165. ERR=0
  166. for ZONE in "${ZONES[@]}"; do
  167. signzone "${ZONE}"
  168. if [ $? -eq 2 ]; then
  169. # To prevent restarting dns if failure
  170. ERR=1
  171. fi
  172. done;
  173. if [ ${ERR} -eq 0 ]; then
  174. ${CHECKCONF}
  175. if [ $? -ne 0 ]; then
  176. error_msg "${CHECKCONF}" "Error in configruation, not reloading"
  177. else
  178. note_msg "$(basename ${SYSCTL})" "Restarting ${DNSSERVICE}"
  179. ${SYSCTL} restart "${DNSSERVICE}"
  180. if [ $? -ne 0 ]; then
  181. ${JOURCTL} -n 10 --unit "${DNSSERVICE}" | xargs -0
  182. fi
  183. fi
  184. else
  185. error_msg "${DNSSERVICE}" "Errors in configuration(s) for zone(s), not restarting."
  186. fi
  187. else
  188. note_msg "${ZONESDIR}" "Finding zones to sign corresponding to ${NAMEDZONES}"
  189. CWD=$(pwd)
  190. cd "${ZONESDIR}"
  191. NAMED=$(cat $NAMEDZONES)
  192. for ZONE in $(ls -d */); do
  193. ACTIVE=$(cat $NAMEDZONES | grep "\"$(basename ${ZONE})\"" | tr -d '[:space:]')
  194. if [[ "${ACTIVE}" == zone* ]]; then
  195. ZONES[${#ZONES[@]}]=$(basename ${ZONE})
  196. fi
  197. done
  198. cd ${CWD}
  199. note_msg "" "Found ${#ZONES[@]} zone(s) active"
  200. if [ "${#ZONES[@]}" -ne 0 ]; then
  201. ${SELF} "${ZONES[@]}"
  202. fi
  203. fi