Using DMS image with custom entrypoint and keeping rspamd DKIM enabled? #3803
Replies: 1 comment 4 replies
-
This is due to implementation to add the rspamd support not being how I would have approached it. docker-mailserver/target/bin/open-dkim Lines 3 to 13 in 3cbcdb2 The original As that logic is required to pass to run the alternative rspamd generation script, it relies upon DMS to have been started and to have run it's initial setup scripts which involves a step ( You could instead have the entrypoint run the rspamd script directly, ignoring the convenience of Look at the help content there and just ignore the Lines 297 to 301 in 3cbcdb2
I'll cover this in a guide below (eventually it'll be integrated into DMS), feel free to skip to the TLDR section and for any further understanding check through the more verbose step-by-step guide above that 👍 If you want to run the current rspamd DKIM CLI script, follow advice above with Below advice ignores OpenDKIM/Rspamd in favor of generic generation of DKIM keypair. Follow-up post has the rspamd specific Generating DKIM keypairIf you only need to generate the DKIM key itself, none of the additional features related to that script, this has nothing to do with OpenDKIM or Rspamd and can be done as I'd rather see it implemented (OpenDKIM / Rspamd agnostic): #3630 That issue also links to earlier feedback from me where I was suggesting how we should approach it in more detail to be generic. I'm not sure why you'd want to generate DKIM keys at the entrypoint considering this would need to update DNS records and really shouldn't be part of the container startup process (I guess you can have an entrypoint script that only creates the key based on some condition like the files not existing yet though?). You could have a side-car container that provides the same support / functionality? Let's use # `--user "$(id -u):$(id -g)"` assigns ownership of generated DKIM key files to your running user.
# NOTE: If the local volume path is not created, it may be created as root,
# in which case you'd need `--user "0:0"` instead to have write permissions.
# `--workdir` sets the location the command is run at, which is where the files will be generated.
#
# `step crypto keypair` command options:
# `--insecure --no-password` opts-out of requiring a password to use the keypair (like you might for SSH).
# `--kty RSA --size 2048` generates a RSA 2048-bit keypair which is appropriately secure.
# `mail.public mail.private` the pubic and private key file names
# NOTE: `mail` here is the DKIM selector (it is useful to have the selector as the file name for rspamd config to reference)
docker run --rm -it \
--user "0:0" \
--volume "${PWD}/docker-data/dms/config/:/tmp/step-cli/" \
--workdir "/tmp/step-cli/" \
smallstep/step-cli \
step crypto keypair \
--insecure --no-password \
--kty RSA --size 2048 \
mail.public mail.privateExtract out the public key to use with DNS # This is to handle the part covered by of our DKIM DNS docs (expand the collapsed admonition on `<selector>.txt` formatting):
# https://docker-mailserver.github.io/docker-mailserver/v13.3/config/best-practices/dkim_dmarc_spf/#dkim-dns
# The public key can be derived from the private key:
# https://smallstep.com/docs/step-cli/reference/crypto/key/
$ step crypto key public mail.private | awk 'NR>2 { sub(/\r/, ""); printf "%s",last} { last=$0 }'
# But since we already have the private key, you could also just feed that through to awk instead:
$ cat mail.public | awk 'NR>2 { sub(/\r/, ""); printf "%s",last} { last=$0 }'
# From this mail.public:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxU5Knu4K6WVxI5oMLNmw
STXkv9lxD2tdfhX/+J14RmW2cdG85vyvQTvn8Togmbwy7khkBZShw1wS/0zen4sK
Ea2eFNUMPhbfrZ001sEvOpUhqHmmjb7DV3+tsOVLRXxWBZG027ZGYO0eELJaaJWq
3rZ4DJOBagdg2E1Hwpik0sOyPJDGV4clDDFgyXZ5vW5cQFI3AUEXahrST2Kz6va8
Uo389Oa2npYOCGFhyq95kKtwbbq9gKPOhAdoM4EUHcXT0d6wfA4tTBKJ3lfT17Gn
fOkN8US/dot+XsgAHl76ADULmqqJfO583MK+DyHlvpQEdd/jr6o4jwxd/itJkX3E
uQIDAQAB
-----END PUBLIC KEY-----
# To this (single line):
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxU5Knu4K6WVxI5oMLNmwSTXkv9lxD2tdfhX/+J14RmW2cdG85vyvQTvn8Togmbwy7khkBZShw1wS/0zen4sKEa2eFNUMPhbfrZ001sEvOpUhqHmmjb7DV3+tsOVLRXxWBZG027ZGYO0eELJaaJWq3rZ4DJOBagdg2E1Hwpik0sOyPJDGV4clDDFgyXZ5vW5cQFI3AUEXahrST2Kz6va8Uo389Oa2npYOCGFhyq95kKtwbbq9gKPOhAdoM4EUHcXT0d6wfA4tTBKJ3lfT17GnfOkN8US/dot+XsgAHl76ADULmqqJfO583MK+DyHlvpQEdd/jr6o4jwxd/itJkX3EuQIDAQABHowever an RSA 2048-bit public key is large, which some DNS services expect you to split into multiple 255-byte lengths/chunks (if you don't have a service that transparently handles that for you). No worries, that's the next part I documented: # Here we've got the initial `cat` + `awk`, followed by another series of commands to format the value into chunks:
# My original suggestion for this differed a little bit, notably `fold` in Alpine Linux is the BusyBox version which
# doesn't have `--width`, only `-w`. It also lacks redirection support `<<<` unless using bash.
$ cat mail.public \
| awk 'NR>2 { sub(/\r/, ""); printf "%s",last} { last=$0 }' \
| awk '{print "p="$1}' | fold -w 255 | sed -E 's#(.*)# "\1"#'
# The final line of the above command:
# 1. The 2nd `awk` => Prepends `p=` to the start of the public key value
# 2. `fold` splits to lines of max width 255 characters
# 3. `sed` takes each line and indents it with 8 spaces, followed by wrapping the value in double quotes.
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxU5Knu4K6WVxI5oMLNmwSTXkv9lxD2tdfhX/+J14RmW2cdG85vyvQTvn8Togmbwy7khkBZShw1wS/0zen4sKEa2eFNUMPhbfrZ001sEvOpUhqHmmjb7DV3+tsOVLRXxWBZG027ZGYO0eELJaaJWq3rZ4DJOBagdg2E1Hwpik0sOyPJDGV4clDDFgyXZ5vW5cQFI3AUEXahrST2Kz6"
"va8Uo389Oa2npYOCGFhyq95kKtwbbq9gKPOhAdoM4EUHcXT0d6wfA4tTBKJ3lfT17GnfOkN8US/dot+XsgAHl76ADULmqqJfO583MK+DyHlvpQEdd/jr6o4jwxd/itJkX3EuQIDAQAB"You'd then provide whichever value format above is relevant to your DNS service, unless you're managing the DNS zone file yourself, you'd have something like: # NOTE: This is the same zone file format generated by rspamd.
#
# Variables:
# SELECTOR=mail
# PUBLIC_KEY_SPLIT=<multi-line value output from above>
cat <<EOF
${SELECTOR}._domainkey IN TXT ( "v=DKIM1; k=rsa; "
${PUBLIC_KEY_SPLIT}
) ;
EOFGiving us: TLDRFor good measure, ignoring the # Create an RSA 2048-bit keypair for DKIM usage:
step crypto keypair mail.public mail.private --kty RSA --size 2048 --no-password --insecure
# Format multi-line split public key for DNS record:
cat mail.public \
| awk 'NR>2 { sub(/\r/, ""); printf "%s",last} { last=$0 }' \
| awk '{print "p="$1}' | fold -w 255 | sed -E 's#(.*)# "\1"#'And now as a script you can mount and call with your preferred selector / keysize if you don't like those defaults: #!/bin/bash
# Args:
SELECTOR=${1:-mail}
KEYSIZE=${2:-2048}
# Create your own keypair instead of via `opendkim-genkey` or `rspamadm dkim_keygen`:
step crypto keypair "${SELECTOR}.public" "${SELECTOR}.private" --kty RSA --size "${KEYSIZE}" --no-password --insecure
# Extract public key contents into single line prepended with `p=`
PUBLIC_KEY=$(cat "${SELECTOR}.public" | awk 'NR>2 { sub(/\r/, ""); printf "%s",last} { last=$0 }' | awk '{print "p="$1}')
# Split into quote wrapped lines 255 chars wide, then indent (8 spaces)
PUBLIC_KEY_MULTILINE=$(fold -w 255 <(cat "${PUBLIC_KEY}") | sed -E 's#(.*)# "\1"#')
# Create a complimentary DNS zone file record (like rspamd does):
cat << EOF > "${SELECTOR}.dns.txt"
${SELECTOR}._domainkey IN TXT ( "v=DKIM1; k=rsa; "
${PUBLIC_KEY_MULTILINE}
) ;
EOFExample of usage: $ chmod +x ./create_dkim_keypair.sh
$ ./create_dkim_keypair.sh dms 3072
Your public key has been saved in dms.public.
Your private key has been saved in dms.private.
# Files created locally:
$ ls -l
create_dkim_keypair.sh
dms.dns.txt
dms.private
dms.public
# RSA 3072-bit with custom selector like requested:
# https://smallstep.com/docs/step-cli/reference/crypto/key/inspect
$ step crypto key inspect dms.private | grep bit
RSA Private-Key: (3072 bit) |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi,
I created an init container in K8s that will do some work that I do not want to do in the main container. Basically DKIM initialization using Rspamd.
This container runs the same DMS image as the normal container but with simplified settings:
setup config dkimwith some other work.Though, the command
setup config dkimgenerates the DKIM using OpenDKIM instead of RSPAMD.Is that because I am not using the official entrypoint? I checked the code but could not really figure out why is that happening.
What is the easiest way to get the DKIM generated using RSPAMD (using setup script for simplicity) in this custom container?
Beta Was this translation helpful? Give feedback.
All reactions