From 7ebfd568bc2abd8e158425361552c304437ca6cc Mon Sep 17 00:00:00 2001 From: f Date: Sat, 22 Jun 2024 15:47:08 -0300 Subject: [PATCH] feat: dynamic selector registration #1 regular key rotation is important because it prevents email impersonation if private keys are lost. once an email is verified, there's no reason to have the private key lying around. this implementation uses knot's dynamic dns features to allow every opendkim node to issue its own key pairs and selectors, and publish them on the _domainkey zone. we don't need central coordination between dns and opendkim, and between opendkim nodes. each works on its own and announces selectors individually. --- Dockerfile | 2 +- opendkimd.sh | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 72c9ed6..0ea6642 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ ARG BASE_IMAGE=gitea.nulo.in/sutty/monit FROM ${BASE_IMAGE}:${ALPINE_VERSION} LABEL org.opencontainers.image.authors="f@sutty.nl" -RUN apk add --no-cache opendkim mini-sendmail +RUN apk add --no-cache opendkim opendkim-utils mini-sendmail drill COPY ./monit.conf /etc/monit.d/opendkim.conf COPY ./opendkimd.sh /usr/local/bin/opendkimd diff --git a/opendkimd.sh b/opendkimd.sh index 2bd6b54..7537800 100755 --- a/opendkimd.sh +++ b/opendkimd.sh @@ -1,6 +1,19 @@ #!/bin/sh pid=/tmp/opendkim.pid +dir=/etc/opendkim +key=$dir/key_table +sig=$dir/signing_table + +SUTTY="${SUTTY:-${DOMAIN#*.}}" + +ok() { + logger -s -t $0 "ok - $@" +} + +not_ok() { + logger -s -t $0 "not ok - $@" +} case $1 in stop) @@ -9,12 +22,71 @@ case $1 in ;; start) install -dm 2750 -o opendkim -g opendkim /run/opendkim + touch $key $sig chown -R opendkim:opendkim /etc/opendkim /usr/sbin/opendkim ;; rotate) - test -f $pid || exit 0 - test $pid -ot /etc/opendkim/dkim.private && cat $pid | xargs -r kill -USR1 + node="${DOMAIN%%.*}" + date="`date +%Y%m`" + selc="${date}${node}" + pkey="${dir}/${selc}.private" + tkey="${dir}/${selc}.txt" + dkey="$selc._domainkey.$SUTTY" + + # Do nothing if it already exists + test -f "$pkey" && exit 0 + + # Remove old keys later + prev="`find $dir -name "*.private" -o -name "*.txt"`" + + ok "Generating new keys for selector ${selc}" + opendkim-genkey --directory=$dir --selector=$selc --subdomains --domain=$SUTTY + + # Discard previous keys + echo "$dkey $SUTTY:$selc:$pkey" > $key + echo "$SUTTY $dkey" > $sig + + txt="`cat $tkey | tr -d "\n" | cut -d '"' -f 2,4 | tr -d '"' | tr -d " "`" + + # Craft record + cat >/tmp/dns <