]> git.immae.eu Git - perso/Immae/Config/Nix.git/commitdiff
Add dnssec
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Tue, 10 Oct 2023 08:44:24 +0000 (10:44 +0200)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Wed, 11 Oct 2023 22:24:46 +0000 (00:24 +0200)
15 files changed:
deploy/flake.lock
flake.lock
flakes/flake.lock
flakes/private/monitoring/myplugins.nix
flakes/private/monitoring/plugins/check_dnssec [new file with mode: 0755]
systems/backup-2/flake.lock
systems/dilion/flake.lock
systems/eldiron/dns.nix
systems/eldiron/ejabberd/default.nix
systems/eldiron/flake.lock
systems/eldiron/mail/postfix.nix
systems/eldiron/mail/sympa.nix
systems/eldiron/websites/tools/default.nix
systems/monitoring-1/flake.lock
systems/quatresaisons/flake.lock

index 5cdf632b06a06350397bf89926d7e63d304fb111..99a99c06b832094abbf8aaefd2e9ff4517de55da 100644 (file)
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-nTSS6oSOmi4T40fXl2o8wfw1/6o2/PP4f8rHtVTGw2s=",
+        "narHash": "sha256-s6HoAgXQrELPNK0BwuMRmJiuAmNN8VvNhhS0K9hYmh4=",
         "path": "../flakes",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-yqURiQf32DNTy5zfAIatoWwFTqvsGDQd+221BoSfsCY=",
+        "narHash": "sha256-KR4/Na/SqEfg9PNnBLk17lTn4LUU7irZGrgvw7TEUYQ=",
         "path": "../systems/backup-2",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-2Q1QywPMmeYtlrSNE869LwUJQjtbRUXbDhNFT4WBRJE=",
+        "narHash": "sha256-7B/UHUhGyJRBRjEms+zI8ZhBAN1vE365GZw2ciJVg1M=",
         "path": "../systems/dilion",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-E88xTYPerBoKGo+EB6RThKwM1AxuhPWhs583WxwD8cA=",
+        "narHash": "sha256-q1+zzXLioBDjua4Omke9ki0hUaW2rtqTMRUXZ/+uHwU=",
         "path": "../systems/eldiron",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-Ejc4fEaRV8u1yWV+u4z6F2SAGDBYEubbgRoG7tE3ctM=",
+        "narHash": "sha256-tsZO/C4md/8qRfxIsvVgeMkB0iAEl4IJC5/i8t/li2I=",
         "path": "../systems/monitoring-1",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-6hR+IuCejk0AIiwggSgrvCQXiRzbF5IiMFr3YqbBwZI=",
+        "narHash": "sha256-UrrTxZeyqV2cFsC3XKVrJoay7LdnE6OTZnBJfimPle4=",
         "path": "../systems/quatresaisons",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "./private/monitoring",
         "type": "path"
       },
index 6cc709e7553a0433fae559c2e38cd6b550a43db9..e6b10be63b37b5a6c5d5270f98bd7ee7734fc5b3 100644 (file)
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-nTSS6oSOmi4T40fXl2o8wfw1/6o2/PP4f8rHtVTGw2s=",
+        "narHash": "sha256-s6HoAgXQrELPNK0BwuMRmJiuAmNN8VvNhhS0K9hYmh4=",
         "path": "./flakes",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-yqURiQf32DNTy5zfAIatoWwFTqvsGDQd+221BoSfsCY=",
+        "narHash": "sha256-KR4/Na/SqEfg9PNnBLk17lTn4LUU7irZGrgvw7TEUYQ=",
         "path": "../systems/backup-2",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-2Q1QywPMmeYtlrSNE869LwUJQjtbRUXbDhNFT4WBRJE=",
+        "narHash": "sha256-7B/UHUhGyJRBRjEms+zI8ZhBAN1vE365GZw2ciJVg1M=",
         "path": "../systems/dilion",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-E88xTYPerBoKGo+EB6RThKwM1AxuhPWhs583WxwD8cA=",
+        "narHash": "sha256-q1+zzXLioBDjua4Omke9ki0hUaW2rtqTMRUXZ/+uHwU=",
         "path": "../systems/eldiron",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-Ejc4fEaRV8u1yWV+u4z6F2SAGDBYEubbgRoG7tE3ctM=",
+        "narHash": "sha256-tsZO/C4md/8qRfxIsvVgeMkB0iAEl4IJC5/i8t/li2I=",
         "path": "../systems/monitoring-1",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-6hR+IuCejk0AIiwggSgrvCQXiRzbF5IiMFr3YqbBwZI=",
+        "narHash": "sha256-UrrTxZeyqV2cFsC3XKVrJoay7LdnE6OTZnBJfimPle4=",
         "path": "../systems/quatresaisons",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "./private/monitoring",
         "type": "path"
       },
index 751316c21befa879c70d6e923e1e8d7ef0436fc6..090ef48dc8d7e29c313dd497ab16f6a97566cb14 100644 (file)
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-yqURiQf32DNTy5zfAIatoWwFTqvsGDQd+221BoSfsCY=",
+        "narHash": "sha256-KR4/Na/SqEfg9PNnBLk17lTn4LUU7irZGrgvw7TEUYQ=",
         "path": "../systems/backup-2",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-2Q1QywPMmeYtlrSNE869LwUJQjtbRUXbDhNFT4WBRJE=",
+        "narHash": "sha256-7B/UHUhGyJRBRjEms+zI8ZhBAN1vE365GZw2ciJVg1M=",
         "path": "../systems/dilion",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-E88xTYPerBoKGo+EB6RThKwM1AxuhPWhs583WxwD8cA=",
+        "narHash": "sha256-q1+zzXLioBDjua4Omke9ki0hUaW2rtqTMRUXZ/+uHwU=",
         "path": "../systems/eldiron",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-Ejc4fEaRV8u1yWV+u4z6F2SAGDBYEubbgRoG7tE3ctM=",
+        "narHash": "sha256-tsZO/C4md/8qRfxIsvVgeMkB0iAEl4IJC5/i8t/li2I=",
         "path": "../systems/monitoring-1",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-6hR+IuCejk0AIiwggSgrvCQXiRzbF5IiMFr3YqbBwZI=",
+        "narHash": "sha256-UrrTxZeyqV2cFsC3XKVrJoay7LdnE6OTZnBJfimPle4=",
         "path": "../systems/quatresaisons",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "./private/monitoring",
         "type": "path"
       },
index 35730bb5c88d610e64197436b1afa6e955de17aa..f76f2c1a4dfe93dbe79a5978d09d2331758a3280 100644 (file)
@@ -69,8 +69,31 @@ in
   dns = {
     commands = {
       check_dns = "$USER1$/check_dns -H $ARG1$ -s $HOSTADDRESS$ $ARG2$";
+      check_dns_soa = "$USER2$/check_dns_soa -H $ARG1$ -z $ARG2$ -M $ARG3$";
+      check_dnssec = "$USER2$/check_dnssec -z $ARG1$";
       check_external_dns = "$USER1$/check_dns -H $ARG2$ -s $ARG1$ $ARG3$";
     };
+    chunk = let
+      soa_plugin = pkgs.fetchurl {
+        name = "check_dns_soa";
+        url = "https://exchange.nagios.org/components/com_mtree/attachment.php?link_id=1429&cf_id=24";
+        sha256 = "sha256-Yy4XO19Fb7WdHZZmhUfyyAGBnxJyFWwc7U3HiWyE8wc=";
+      };
+    in ''
+      cp ${./plugins}/check_dnssec $out/
+      patchShebangs $out/check_dnssec
+      wrapProgram $out/check_dnssec --prefix PATH : ${lib.makeBinPath [
+        pkgs.bind.dnsutils pkgs.gnugrep pkgs.gawk pkgs.which pkgs.coreutils
+      ]}
+
+      cp ${soa_plugin} $out/check_dns_soa
+      chmod +xw $out/check_dns_soa
+      patchShebangs $out/check_dns_soa
+      sed -i -e 's/^use utils qw.*$/my %ERRORS = ("OK" => 0, "WARNING" => 1, "CRITICAL" => 2, "UNKNOWN" => 3);my $TIMEOUT = 10;/' -e '/^use lib /d' $out/check_dns_soa
+      wrapProgram $out/check_dns_soa --prefix PERL5LIB : ${pkgs.perlPackages.makePerlPath [
+        pkgs.perlPackages.NetDNS
+      ]}
+    '';
   };
   mdadm = {
     commands = {
diff --git a/flakes/private/monitoring/plugins/check_dnssec b/flakes/private/monitoring/plugins/check_dnssec
new file mode 100755 (executable)
index 0000000..a6e408d
--- /dev/null
@@ -0,0 +1,195 @@
+#!/usr/bin/env bash
+
+# check_dnssec_expiry.sh
+#
+# Copyright 2017 by Mario Rimann <mario@rimann.org>
+# Licensed under the permissive MIT license, see LICENSE.md
+#
+# Development of this script was partially sponsored by my
+# employer internezzo, see http://www.internezzo.ch
+#
+# If this script helps you to make your work easier, please consider
+# to give feedback or do something good, see https://rimann.org/support
+
+usage() {
+       cat - >&2 << _EOT_
+usage $0 -z <zone> [-w <warning %>] [-c <critical %>] [-r <resolver>] [-f <always failing domain>]
+
+       -z <zone>
+               specify zone to check
+       -w <critical %>
+               warning time left percentage
+       -c <critical %>
+               critical time left percentage
+       -r <resolver>
+               specify which resolver to use.
+       -f <always failing domain>
+               specify a domain that will always fail DNSSEC.
+               used to test if DNSSEC is supported in used tools.
+       -t <DNS record type to check>
+               specify a DNS record type for calculating the remaining lifetime.
+               For example SOA, A, etc.
+_EOT_
+       exit 255
+}
+
+# Parse the input options
+while getopts ":z:w:c:r:f:h:t:" opt; do
+  case $opt in
+    z)
+      zone=$OPTARG
+      ;;
+    w)
+      warning=$OPTARG
+      ;;
+    c)
+      critical=$OPTARG
+      ;;
+    r)
+      resolver=$OPTARG
+      ;;
+    f)
+      alwaysFailingDomain=$OPTARG
+      ;;
+    t)
+      recordType=$OPTARG
+      ;;
+    h)
+      usage ;;
+  esac
+done
+
+
+# Check if dig is available at all - fail hard if not
+pathToDig=$( which dig )
+if [[ ! -e $pathToDig ]]; then
+       echo "No executable of dig found, cannot proceed without dig. Sorry!"
+       exit 1
+fi
+
+# Check if we got a zone to validate - fail hard if not
+if [[ -z $zone ]]; then
+       echo "Missing zone to test - please provide a zone via the -z parameter."
+       usage
+       exit 3
+fi
+
+# Check if we got warning/critical percentage values, use defaults if not
+if [[ -z $warning ]]; then
+       warning=20
+fi
+if [[ -z $critical ]]; then
+       critical=10
+fi
+
+
+# Use Google's 8.8.8.8 resolver as fallback if none is provided
+if [[ -z $resolver ]]; then
+       resolver="8.8.8.8"
+fi
+
+if [[ -z $alwaysFailingDomain ]]; then
+       alwaysFailingDomain="dnssec-failed.org"
+fi
+
+# Use SOA record type as fallback
+if [[ -z $recordType ]]; then
+        recordType="SOA"
+fi
+
+# Check the resolver to properly validate DNSSEC at all (if he doesn't, every further test is futile and a waste of bandwith)
+checkResolverDoesDnssecValidation=$(dig +nocmd +nostats +noquestion $alwaysFailingDomain @${resolver} | grep "opcode: QUERY" | grep "status: SERVFAIL")
+if [[ -z $checkResolverDoesDnssecValidation ]]; then
+       echo "WARNING: Resolver seems to not validate DNSSEC signatures - going further seems hopeless right now."
+       exit 1
+fi
+
+# Check if the resolver delivers an answer for the domain to test
+checkDomainResolvableWithDnssecEnabledResolver=$(dig +short @${resolver} SOA $zone)
+if [[ -z $checkDomainResolvableWithDnssecEnabledResolver ]]; then
+
+       checkDomainResolvableWithDnssecValidationExplicitelyDisabled=$(dig +short @${resolver} SOA $zone +cd)
+
+       if [[ ! -z $checkDomainResolvableWithDnssecValidationExplicitelyDisabled ]]; then
+               echo "CRITICAL: The domain $zone can be validated without DNSSEC validation - but will fail on resolvers that do validate DNSSEC."
+               exit 2
+       else
+               echo "CRITICAL: The domain $zone cannot be resolved via $resolver as resolver while DNSSEC validation is active."
+               exit 2
+       fi
+fi
+
+# Check if the domain is DNSSEC signed at all
+# (and emerge a WARNING in that case, since this check is about testing DNSSEC being "present" and valid which is not the case for an unsigned zone)
+checkZoneItselfIsSignedAtAll=$( dig $zone @$resolver DS +short )
+if [[ -z $checkZoneItselfIsSignedAtAll ]]; then
+       echo "WARNING: Zone $zone seems to be unsigned itself (= resolvable, but no DNSSEC involved at all)"
+       exit 1
+fi
+
+
+# Check if there are multiple RRSIG responses and check them one after the other
+now=$(date +"%s")
+rrsigEntries=$( dig @$resolver $recordType $zone +dnssec | grep RRSIG )
+if [[ -z $rrsigEntries ]]; then
+        echo "CRITICAL: There is no RRSIG for the SOA of your zone."
+        exit 2
+else
+       while read -r rrsig; do
+               # Get the RRSIG entry and extract the date out of it
+               expiryDateOfSignature=$( echo $rrsig | awk '{print $9}')
+               checkValidityOfExpirationTimestamp=$( echo $expiryDateOfSignature | egrep '[0-9]{14}')
+               if [[ -z $checkValidityOfExpirationTimestamp ]]; then
+                       echo "UNKNOWN: Something went wrong while checking the expiration of the RRSIG entry - investigate please".
+                       exit 3
+               fi
+
+               inceptionDateOfSignature=$( echo $rrsig | awk '{print $10}')
+               checkValidityOfInceptionTimestamp=$( echo $inceptionDateOfSignature | egrep '[0-9]{14}')
+               if [[ -z $checkValidityOfInceptionTimestamp ]]; then
+                       echo "UNKNOWN: Something went wrong while checking the inception date of the RRSIG entry - investigate please".
+                       exit 3
+               fi
+
+               # Fiddle out the expiry and inceptiondate of the signature to have a base to do some calculations afterwards
+               expiryDateAsString="${expiryDateOfSignature:0:4}-${expiryDateOfSignature:4:2}-${expiryDateOfSignature:6:2} ${expiryDateOfSignature:8:2}:${expiryDateOfSignature:10:2}:00"
+               expiryDateOfSignatureAsUnixTime=$( date -u -d "$expiryDateAsString" +"%s" 2>/dev/null )
+               if [[ $? -ne 0 ]]; then
+                       # if we come to this place, something must have gone wrong converting the date-string. This can happen as e.g. MacOS X and Linux don't behave the same way in this topic...
+                       expiryDateOfSignatureAsUnixTime=$( date -j -u -f "%Y-%m-%d %T" "$expiryDateAsString" +"%s" )
+               fi
+               inceptionDateAsString="${inceptionDateOfSignature:0:4}-${inceptionDateOfSignature:4:2}-${inceptionDateOfSignature:6:2} ${inceptionDateOfSignature:8:2}:${inceptionDateOfSignature:10:2}:00"
+               inceptionDateOfSignatureAsUnixTime=$( date -u -d "$inceptionDateAsString" +"%s" 2>/dev/null )
+               if [[ $? -ne 0 ]]; then
+                       # if we come to this place, something must have gone wrong converting the date-string. This can happen as e.g. MacOS X and Linux don't behave the same way in this topic...
+                       inceptionDateOfSignatureAsUnixTime=$( date -j -u -f "%Y-%m-%d %T" "$inceptionDateAsString" +"%s" )
+               fi
+
+
+               # calculate the remaining lifetime of the signature
+               totalLifetime=$( expr $expiryDateOfSignatureAsUnixTime - $inceptionDateOfSignatureAsUnixTime)
+               remainingLifetimeOfSignature=$( expr $expiryDateOfSignatureAsUnixTime - $now)
+               remainingPercentage=$( expr "100" \* $remainingLifetimeOfSignature / $totalLifetime)
+
+               # store the result of this single RRSIG's check
+               if [[ -z $maxRemainingLifetime || $remainingLifetimeOfSignature -gt $maxRemainingLifetime ]]; then
+                       maxRemainingLifetime=$remainingLifetimeOfSignature
+                       maxRemainingPercentage=$remainingPercentage
+               fi
+       done <<< "$rrsigEntries"
+fi
+
+
+
+
+# determine if we need to alert, and if so, how loud to cry, depending on warning/critial threshholds provided
+if [[ $maxRemainingPercentage -lt $critical ]]; then
+       echo "CRITICAL: DNSSEC signature for $zone is very short before expiration! ($maxRemainingPercentage% remaining) | sig_lifetime=$maxRemainingLifetime  sig_lifetime_percentage=$remainingPercentage%;$warning;$critical"
+       exit 2
+elif [[ $remainingPercentage -lt $warning ]]; then
+       echo "WARNING: DNSSEC signature for $zone is short before expiration! ($maxRemainingPercentage% remaining) | sig_lifetime=$maxRemainingLifetime  sig_lifetime_percentage=$remainingPercentage%;$warning;$critical"
+       exit 1
+else
+       echo "OK: DNSSEC signatures for $zone seem to be valid and not expired ($maxRemainingPercentage% remaining) | sig_lifetime=$maxRemainingLifetime  sig_lifetime_percentage=$remainingPercentage%;$warning;$critical"
+       exit 0
+fi
index 919a027bb157aec707fd45848b0433f7056a6f73..3ca1baf1a70f13fc62c95655b1ce3a993c2aa6f5 100644 (file)
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
index b6aef703891046e525f73675146e04e7289ee701..bd3cdd9ef869e50d1bb41574e282e0aa1ca079b7 100644 (file)
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
index 486fcc1ad4aa49dfac69d5afc5840048c40cc0b2..7645b69494261501914de5d40f80e977234104a8 100644 (file)
@@ -1,4 +1,18 @@
 { lib, pkgs, config, dns-nix, ... }:
+let
+  zonesWithDNSSec = lib.filterAttrs (k: v: v.dnssec.enable) config.myServices.dns.zones;
+  zoneToFile = name: v: pkgs.runCommand "${name}.zone" {
+    text = v;
+    passAsFile = [ "text" ];
+    # Automatically change the increment when relevant change
+    # happened (both serial and mta-sts)
+  } ''
+    mv "$textPath" $out
+    increment=$(( 100*($(date -u +%-H) * 60 + $(date -u +%-M))/1440 ))
+    sed -i -e "s/2022121902/$(date -u +%Y%m%d)$increment/g" $out
+    sed -i -e "s/20200109150200Z/$(date -u +%Y%m%d%H%M%SZ)/g" $out
+  '';
+in
 {
   options.myServices.dns = {
     enable = lib.mkEnableOption "enable DNS resolver";
         servers = config.myEnv.servers;
         ips = i: { A = i.ip4; AAAA = i.ip6; };
         letsencrypt = [ { tag = "issue"; value = "letsencrypt.org"; issuerCritical = false; } ];
-        toKV = a: builtins.concatStringsSep ";" (builtins.attrValues (builtins.mapAttrs (n: v: "${n}=${v}") a));
+        toKV = a: let
+          removeOrder = n: lib.last (builtins.split "__" n);
+        in
+          builtins.concatStringsSep ";" (builtins.attrValues (builtins.mapAttrs (n: v: "${removeOrder n}=${v}") a));
         mailMX = {
           hasEmail = true;
           subdomains = let
           SOA = {
             # yyyymmdd?? (increment ?? at each change)
             serial = 2022121902; # Don't change this value, it is replaced automatically!
-            refresh = 10800;
-            retry = 3600;
-            expire = 604800;
-            minimum = 10800; # negative cache ttl
+            refresh = 3*60*60;
+            retry = 60*60;
+            expire = 14*24*60*60;
+            minimum = 3*60*60; # negative cache ttl
             adminEmail = "hostmaster@immae.eu"; #email-address s/@/./
             nameServer = "ns1.immae.eu.";
           };
@@ -42,7 +59,7 @@
             (toKV config.myEnv.mail.dkim.immae_eu.public)
           ];
         };
-        mailCommon = name: {
+        mailCommon = name: quarantine: {
           MX = let
             mxes = lib.filterAttrs (n: v: v ? mx && v.mx.enable) servers;
           in
             # MTA-STS
             # https://blog.delouw.ch/2018/12/16/using-mta-sts-to-enhance-email-transport-security-and-privacy/
             # https://support.google.com/a/answer/9261504
-            _mta-sts.TXT = [ (toKV { v = "STSv1"; id = "20200109150200Z"; }) ]; # Don't change this value, it is updated automatically!
-            _tls.subdomains._smtp.TXT = [ (toKV { v = "TLSRPTv1"; "rua" = "mailto:postmaster+mta-sts@immae.eu"; }) ];
+            _mta-sts.TXT = [ (toKV { _00__v = "STSv1"; id = "20200109150200Z"; }) ]; # Don't change this value, it is updated automatically!
+            _tls.subdomains._smtp.TXT = [ (toKV { _00__v = "TLSRPTv1"; rua = "mailto:postmaster+mta-sts@immae.eu"; }) ];
             mta-sts = ips servers.eldiron.ips.main;
 
             # DMARC
-            _dmarc.TXT = [ (toKV { v = "DMARC1"; p = "none"; adkim = "r"; aspf = "r"; fo = "1"; rua = "mailto:postmaster+rua@immae.eu"; ruf = "mailto:postmaster+ruf@immae.eu"; }) ];
+            # p needs to be the first tag
+            _dmarc.TXT = [ (toKV { _00__v = "DMARC1"; _01__p = if quarantine then "quarantine" else "none"; adkim = "s"; aspf = "s"; fo = "1"; rua = "mailto:postmaster+rua@immae.eu"; ruf = "mailto:postmaster+ruf@immae.eu"; }) ];
           };
 
           # SPF
-          TXT = [ (toKV { v = "spf1 mx ~all"; }) ];
+          TXT = [ (toKV { _00__v = "spf1 mx ~all"; }) ];
         };
       };
     };
         dns-nix.lib.types.zone.getSubModules ++ [
           ({ name, ... }: {
             options = {
+              dnssec = lib.mkOption {
+                default.enable = false;
+                type = lib.types.submodule {
+                  options = {
+                    enable = lib.mkEnableOption "Configure dnssec for this domain";
+                  };
+                };
+              };
               hasEmail = lib.mkEnableOption "This domain has e-mails configuration";
               emailPolicies = lib.mkOption {
                 default = {};
         zoneHeader
         (ips servers.eldiron.ips.main)
         {
-          ns = [ "immae" ];
+          dnssec.enable = true;
+          ns = [ "immae" "raito" ];
           CAA = letsencrypt;
+          extraConfig = ''
+            notify yes;
+          '';
+          slaves = [ "raito" ];
         }
       ];
       "immae.dev" = lib.mkMerge [
         {
+          dnssec.enable = true;
           extraConfig = ''
             notify yes;
           '';
       ];
       "immae.eu" = lib.mkMerge [
         {
+          dnssec.enable = true;
           extraConfig = ''
             notify yes;
           '';
         zoneHeader
         (ips servers.eldiron.ips.production)
         {
-          ns = [ "immae" "raito" ];
+          ns = [ "immae" ];
+          # Cannot put ns2.immae.eu as glue record as it takes ages to propagate.
+          # And gandi only accepts NS records with glues in their interface
+          NS = [ "kurisu.dual.lahfa.xyz." ];
           CAA = letsencrypt;
 
           # ns1 has glue records in gandi.net
         {
           # Machines local users
           emailPolicies.localhost.receive = false;
-          subdomains.localhost = lib.mkMerge [ (mailCommon "immae.eu") mailSend ];
+          subdomains.localhost = lib.mkMerge [ (mailCommon "immae.eu" true) mailSend ];
           emailPolicies.eldiron.receive = true;
-          subdomains.eldiron = lib.mkMerge [ (mailCommon "immae.eu") mailSend ];
+          subdomains.eldiron = lib.mkMerge [ (mailCommon "immae.eu" true) mailSend ];
         }
         {
           # For each server "server" and each server ip group "ipgroup",
       zones =
         builtins.mapAttrs (name: v: {
           master = true;
-          extraConfig = v.extraConfig;
+          extraConfig = v.extraConfig + lib.optionalString v.dnssec.enable ''
+            key-directory "/var/lib/named/dnssec_keys";
+            dnssec-policy default;
+            inline-signing yes;
+          '';
           masters = [];
           slaves =
             lib.flatten (map (n: builtins.attrValues config.myEnv.dns.ns.${n}) v.slaves);
-          file = pkgs.runCommand "${name}.zone" {
-            text = v;
-            passAsFile = [ "text" ];
-            # Automatically change the increment when relevant change
-            # happened (both serial and mta-sts)
-          } ''
-            mv "$textPath" $out
-            increment=$(( 100*($(date -u +%-H) * 60 + $(date -u +%-M))/1440 ))
-            sed -i -e "s/2022121902/$(date -u +%Y%m%d)$increment/g" $out
-            sed -i -e "s/20200109150200Z/$(date -u +%Y%m%d%H%M%SZ)/g" $out
-          '';
+          file = if v.dnssec.enable then "/var/run/named/dnssec-${name}.zone" else zoneToFile name v;
         }) config.myServices.dns.zones;
     };
+    systemd.services.bind.serviceConfig.StateDirectory = "named";
+    systemd.services.bind.preStart = lib.mkAfter
+      (builtins.concatStringsSep "\n" (lib.mapAttrsToList (name: v: ''
+        install -m444 ${zoneToFile name v} /var/run/named/dnssec-${name}.zone
+      '') zonesWithDNSSec) + ''
+        install -dm755 -o named /var/lib/named/dnssec_keys
+      '');
     myServices.monitoring.fromMasterActivatedPlugins = [ "dns" ];
     myServices.monitoring.fromMasterObjects.service = lib.mkMerge (lib.mapAttrsToList (name: z:
       lib.optional (builtins.elem "immae" z.ns) {
         servicegroups = "webstatus-dns";
         _webstatus_name = name;
       } ++
-      lib.optional (builtins.elem "raito" z.ns) {
-        service_description = "raito dns is active and authoritative for ${name}";
+      lib.optionals (builtins.elem "raito" z.ns) [
+        {
+          service_description = "raito dns is active and authoritative for ${name}";
+          host_name = config.hostEnv.fqdn;
+          use = "dns-service";
+          check_command = ["check_external_dns" "kurisu.dual.lahfa.xyz" name "-A"];
+
+          servicegroups = "webstatus-dns";
+          _webstatus_name = "${name} (Secondary DNS Raito)";
+        }
+        {
+          service_description = "raito dns is up to date for ${name}";
+          host_name = config.hostEnv.fqdn;
+          use = "dns-service";
+          check_command = ["check_dns_soa" "kurisu.dual.lahfa.xyz" name config.hostEnv.fqdn];
+
+          servicegroups = "webstatus-dns";
+          _webstatus_name = "${name} (Secondary DNS Raito up to date)";
+        }
+      ] ++
+      lib.optional z.dnssec.enable {
+        service_description = "DNSSEC is active and not expired for ${name}";
         host_name = config.hostEnv.fqdn;
         use = "dns-service";
-        check_command = ["check_external_dns" "kurisu.dual.lahfa.xyz" name "-A"];
+        check_command = ["check_dnssec" name];
 
         servicegroups = "webstatus-dns";
-        _webstatus_name = "${name} (Secondary DNS Raito)";
+        _webstatus_name = "${name} (DNSSEC)";
       }
     ) config.myServices.dns.zones);
   };
index 5268516104fd5dc0d2e2384abd3818de1a2a80e5..463d25511afbfc5cad177846ad0bda31f480768f 100644 (file)
@@ -25,7 +25,7 @@ in
         }
         zoneHeader
         mailMX
-        (mailCommon "immae.fr")
+        (mailCommon "immae.fr" true)
         (ips servers.eldiron.ips.main)
         {
           ns = [ "immae" "raito" ];
index c52dd619e966c01247f9ba5de980bcc40c6427ef..5a60dabc6722f76d736445cb58dc77cf14396745 100644 (file)
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
index f95ee1bb04217e6d9114fd8e04122a13433c3336..93d1e1e161f5888817367e63ce4906531e0f5519 100644 (file)
@@ -12,7 +12,7 @@ in
   config = lib.mkIf config.myServices.mail.enable {
     myServices.dns.zones."immae.eu" = with config.myServices.dns.helpers; lib.mkMerge [
       mailMX
-      (mailCommon "immae.eu")
+      (mailCommon "immae.eu" true)
       mailSend
       {
         # Virtual forwards and mailboxes for real users
@@ -22,7 +22,7 @@ in
         # system virtual mailboxes:
         #     devnull, printer, testconnect
         emailPolicies."".receive = true;
-        subdomains.mail = lib.mkMerge [ (mailCommon "immae.eu") mailSend ];
+        subdomains.mail = lib.mkMerge [ (mailCommon "immae.eu" true) mailSend ];
         subdomains.smtp = ips servers.eldiron.ips.main;
 
         # DMARC reports
index 8e801dd938a00c0d2f4d95023aa91762da2f5666..07175e8a60f9008e7c07b4b1a88c17b080d509e5 100644 (file)
@@ -9,7 +9,7 @@ in
     myServices.dns.zones."immae.eu".subdomains.lists =
       with config.myServices.dns.helpers; lib.mkMerge [
         (ips servers.eldiron.ips.main)
-        (mailCommon "immae.eu")
+        (mailCommon "immae.eu" false)
         mailSend
       ];
 
index 397b644f4a7d49747fb6d61a2744b994d8b3ef21..338ed0b0cf0e6b22e55a0f0ef5a389516ccf45f2 100644 (file)
@@ -91,7 +91,7 @@ in {
       {
         outils = ips servers.eldiron.ips.main;
         tools  = lib.mkMerge [
-          (mailCommon "immae.eu")
+          (mailCommon "immae.eu" true)
           mailSend
           (ips servers.eldiron.ips.main)
         ];
index 6758db352d60f5d26dfe90ad330d5306b60ae3db..ec29221928708ae4d874b0d8992e7f2b8261d3f1 100644 (file)
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },
index 653ce9c0f4e681eec6d9979543da0df444063bd8..e23bbde45ac66c49363478500c623e29b21ec208 100644 (file)
       },
       "locked": {
         "lastModified": 1,
-        "narHash": "sha256-rybO4c9UB9a34Xgoh+ToYz36Dz2OM1sgYxi3m00+W+E=",
+        "narHash": "sha256-DN3hgnw6hXCrSGXep4mumwksWSggsuyyaKXuKvswXl8=",
         "path": "../../flakes/private/monitoring",
         "type": "path"
       },