Skip to content

docs: update DKIM/DMARC/SPF docs#3231

Merged
polarathene merged 22 commits intomasterfrom
docs/dns
Apr 10, 2023
Merged

docs: update DKIM/DMARC/SPF docs#3231
polarathene merged 22 commits intomasterfrom
docs/dns

Conversation

@georglauterbach
Copy link
Copy Markdown
Member

@georglauterbach georglauterbach commented Apr 8, 2023

Description

Updates the DNS docs about DKIM, DMARC & SPF; we now have one location for setup of these services. I hope all links were properly updated.

We may want to decide if we want to be even more precise / add even more details to the DKIM/DMARC/SPF page, but I think it is fine for now, as it already contains more information that previous versions of our docs.

Follow-Up to #3219

Type of change

  • This change is a documentation update

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own codey

@georglauterbach georglauterbach added kind/improvement Improve an existing feature, configuration file or the documentation area/documentation meta/feature freeze On hold due to upcoming release process kind/update Update an existing feature, configuration file or the documentation labels Apr 8, 2023
@georglauterbach georglauterbach added this to the v12.1.0 milestone Apr 8, 2023
@georglauterbach georglauterbach self-assigned this Apr 8, 2023
@georglauterbach
Copy link
Copy Markdown
Member Author

Diff is huge, but this is mainly due to the fact that I deleted files and basically copied their contents in one file; then added/revised some content.

@georglauterbach georglauterbach changed the title docs: update user management & DKIM/DMARC/SPF docs docs: update DKIM/DMARC/SPF docs Apr 8, 2023
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment on lines +97 to +102
By default, DMS offers no option to generate and configure signing e-mails with DKIM. This is because the parsing would be difficult. But don't worry: the process is relatively straightforward nevertheless. The [official Rspamd documentation for the DKIM signing module][rspamd-docs-dkim-signing] is pretty good. Basically, you need to

1. Go inside the container with `docker exec -ti <CONTAINER NAME> bash`
2. Run a command similar to `rspamadm dkim_keygen -s 'selector-name' -b 2048 -d example.com -k example.private > example.txt`, adjusted to your needs
3. Make sure to then persists the files `example.private` and `example.txt` (created in step 2) in the container (for example with a Docker bind mount)
4. Create a configuration for the DKIM signing module, i.e. a file called `dkim_signing.conf` that you mount to `/etc/rspamd/local.d/` or `/etc/rspamd/override.d/`. We provide example configurations down below. We recommend mounting this file into the container as well (as described [here](#manually)); do not use [`rspamd-modules.conf`](#with-the-help-of-a-custom-file) for this purpose.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, the current setup config dkim support would also produce the example.private and example.txt files that Rspamd needs. They're very much the same, except OpenDKIM is generating with h=sha256; header option in the example.txt file.

The script would need to be adjusted to more generic (eg: only create open dkim related config if ENABLE_OPENDKIM=1?). They support most of the same command options as well (--subdomains in opendkim isn't necessary as it appears to be the default, --nosubdomains would add t=s;, but we don't support changing that). Other than that no -k / --privkey or -t / --type options are supported by OpenDKIM.


That leaves us with step 4. You can kind of generate this via concatenation of the top half of the config + some loops for domain (with conditional on selectors array injection), but that's a bit awkward to maintain in bash IMO. I think fetchmail and the current PR for getmail take this sort of approach at generating similar config.

From the examples below at least, it looks fairly doable, especially if we're in control of the file path / name conventions.

Comment on lines +172 to +174
!!! bug "File Permissions"

Make sure the user `_rspamd` is able to go into the directory where you persist the (private) key files, and ensure it can read them!
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the parsing concern? From the looks of it with OpenDKIM, and it's probably applicable to Rspamd support, the config duration could be generated instead via a runtime helper script:

# check if any keys are available
if [[ -e /tmp/docker-mailserver/opendkim/KeyTable ]]
then
cp -a /tmp/docker-mailserver/opendkim/* /etc/opendkim/
_log 'trace' "DKIM keys added for: $(find /etc/opendkim/keys/ -maxdepth 1 -type f -printf '%f ')"
chown -R opendkim:opendkim /etc/opendkim/
chmod -R 0700 /etc/opendkim/keys/
else
_log 'debug' 'OpenDKIM enabled but no DKIM key(s) provided'
fi

# write to KeyTable if necessary
KEYTABLEENTRY="${SELECTOR}._domainkey.${DKIM_DOMAIN} ${DKIM_DOMAIN}:${SELECTOR}:/etc/opendkim/keys/${DKIM_DOMAIN}/${SELECTOR}.private"
if [[ ! -f "/tmp/docker-mailserver/opendkim/KeyTable" ]]
then
_log 'debug' 'Creating DKIM KeyTable'
echo "${KEYTABLEENTRY}" >/tmp/docker-mailserver/opendkim/KeyTable
else
if ! grep -q "${KEYTABLEENTRY}" "/tmp/docker-mailserver/opendkim/KeyTable"
then
echo "${KEYTABLEENTRY}" >>/tmp/docker-mailserver/opendkim/KeyTable
fi
fi
# write to SigningTable if necessary
SIGNINGTABLEENTRY="*@${DKIM_DOMAIN} ${SELECTOR}._domainkey.${DKIM_DOMAIN}"
if [[ ! -f /tmp/docker-mailserver/opendkim/SigningTable ]]
then
_log 'debug' 'Creating DKIM SigningTable'
echo "*@${DKIM_DOMAIN} ${SELECTOR}._domainkey.${DKIM_DOMAIN}" >/tmp/docker-mailserver/opendkim/SigningTable
else
if ! grep -q "${SIGNINGTABLEENTRY}" /tmp/docker-mailserver/opendkim/SigningTable
then
echo "${SIGNINGTABLEENTRY}" >>/tmp/docker-mailserver/opendkim/SigningTable
fi
fi
done < <(_get_valid_lines_from_file "${DATABASE_VHOST}")
# create TrustedHosts if missing
if [[ -d /tmp/docker-mailserver/opendkim ]] && [[ ! -f /tmp/docker-mailserver/opendkim/TrustedHosts ]]
then
_log 'debug' 'Creating DKIM TrustedHosts'
echo "127.0.0.1" >/tmp/docker-mailserver/opendkim/TrustedHosts
echo "localhost" >>/tmp/docker-mailserver/opendkim/TrustedHosts
fi

The relevant information seems to be persisted into the file path, similar to how the LetsEncrypt support is, thus might be able to lean on logic from there:

# Identify a valid letsencrypt FQDN folder to use.
function _find_letsencrypt_domain
{
local LETSENCRYPT_DOMAIN
if [[ -n ${SSL_DOMAIN} ]] && [[ -e /etc/letsencrypt/live/$(_strip_wildcard_prefix "${SSL_DOMAIN}")/fullchain.pem ]]
then
LETSENCRYPT_DOMAIN=$(_strip_wildcard_prefix "${SSL_DOMAIN}")
elif [[ -e /etc/letsencrypt/live/${HOSTNAME}/fullchain.pem ]]
then
LETSENCRYPT_DOMAIN=${HOSTNAME}
elif [[ -e /etc/letsencrypt/live/${DOMAINNAME}/fullchain.pem ]]
then
LETSENCRYPT_DOMAIN=${DOMAINNAME}
else
_log 'error' "Cannot find a valid DOMAIN for '/etc/letsencrypt/live/<DOMAIN>/', tried: '${SSL_DOMAIN}', '${HOSTNAME}', '${DOMAINNAME}'"
_dms_panic__misconfigured 'LETSENCRYPT_DOMAIN' '_find_letsencrypt_domain'
fi
echo "${LETSENCRYPT_DOMAIN}"
}
# Verify the FQDN folder also includes a valid private key (`privkey.pem` for Certbot, `key.pem` for extraction by Traefik)
function _find_letsencrypt_key
{
local LETSENCRYPT_KEY
local LETSENCRYPT_DOMAIN=${1}
if [[ -z ${LETSENCRYPT_DOMAIN} ]]
then
_dms_panic__misconfigured 'LETSENCRYPT_DOMAIN' '_find_letsencrypt_key'
fi
if [[ -e /etc/letsencrypt/live/${LETSENCRYPT_DOMAIN}/privkey.pem ]]
then
LETSENCRYPT_KEY='privkey'
elif [[ -e /etc/letsencrypt/live/${LETSENCRYPT_DOMAIN}/key.pem ]]
then
LETSENCRYPT_KEY='key'
else
_log 'error' "Cannot find key file ('privkey.pem' or 'key.pem') in '/etc/letsencrypt/live/${LETSENCRYPT_DOMAIN}/'"
_dms_panic__misconfigured 'LETSENCRYPT_KEY' '_find_letsencrypt_key'
fi
echo "${LETSENCRYPT_KEY}"
}

We can see how OpenDKIM is sourcing the keys from a config mount, and copying them over to an internal location at start up. That ensures ownership is correct.

Likewise, this would probably enable both to leverage check-for-changes.sh to configure and reload instead of needing to restart the container fully? (potentially useful if you rotate DKIM keys)


I wouldn't encourage pursuing that in this PR though 😅 Might be a worthwhile improvement to open an issue about and implement in future?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reference, the open_dkim.bats test would extract out the public key and concatentate it (similar to what the DNS advice for web UI suggests further down):

# DKIM record, extract public key (base64 encoded, potentially multi-line)
# - tail to exclude first line,
# - then sed to extract values within quoted lines, then remove `p=` from the start,
# - and finally echo to concatenate all lines into single string
# Next decode and parse it with openssl to verify public-key key size is correct:
_run_in_container_bash "echo \$( \
tail -n +2 '${TARGET_DIR}/mail.txt' \
| sed -nE -e 's/.*\"(.*)\".*/\1/p' \
| sed -e 's/^p=//' \
) | openssl enc -base64 -d | openssl pkey -inform DER -pubin -noout -text
"
assert_success
assert_line --index 0 "RSA Public-Key: (${EXPECTED_KEYSIZE} bit)"

Smallstep CLI can generate the keypairs (including Ed25519), while another command from their CLI can inspect the private key or derive the public key from it (in PEM format). That would technically be capable of generating the main data for DKIM, the rest could be templated.

That said if OpenDKIM is going to be dropped by end of the year, setup config dkim could just replace opendkim for rspamd equivalent command 😅

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found this awful looking monstrosity one-liner that reads in a public key in PEM format, excludes the header/footer lines and concatenates the base64 encoded content to a single line:

awk 'NR>2 { sub(/\r/, ""); printf "%s\\n",last} { last=$0 }' example.pub `

Probably don't want the \n being added there, so removing that and optionally using fold to revert back to the same PEM width:

awk 'NR>2 { sub(/\r/, ""); printf "%s",last} { last=$0 }' example.pub
  | fold --width 64

DKIM key + dns record generator helper:

#!/bin/bash

SELECTOR=${1:-mail}
KEYSIZE=${2:-2048}

# Create your own keypair instead of via `opendkim-genkey` or `rspamadm dkim_keygen`:
#step crypto keypair "${SELECTOR}.pub" "${SELECTOR}.private" --kty RSA --size "${KEYSIZE}" --no-password --insecure

# Derive the public key from the private key as a single line
PUBLIC_KEY=$(
  step crypto key public "${SELECTOR}.private" \
    | awk 'NR>2 { sub(/\r/, ""); printf "%s",last} { last=$0 }'
)

# Format into multiline 255 char segments for DNS record zone file:
PUBLIC_KEY_SPLIT=$(
  fold --width 255 <<< "p=${PUBLIC_KEY}" \
    | sed -E 's#(.*)#        "\1"#'
)

# Template of rspamadm output:
cat << EOF > "${SELECTOR}.dns.txt"
${SELECTOR}._domainkey IN TXT ( "v=DKIM1; k=rsa; "
${PUBLIC_KEY_SPLIT}
) ;
EOF

There you go, does not depend on opendkim or rspamd to generate the keypair and record, and can output the single line entry or multi-part DNS zone record.

setup config dkim could be retrofitted with that to generate a key in config volume that is stored in a common folder that both opendkim and rspamd could copy from at runtime and generate their configs for.

Comment thread docs/mkdocs.yml
- 'DKIM': config/best-practices/dkim.md
- 'DMARC': config/best-practices/dmarc.md
- 'SPF': config/best-practices/spf.md
- 'DKIM, DMARC & SPF': config/best-practices/dkim_dmarc_spf.md
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know you've replaced our kebab-case naming convention with snake_case in some of the script files as of late, and now you're introducing that into the docs.

I really don't want to see this deteriorate further over time. Please decide on a convention and be consistent with it throughout. I don't recall your motivation for introducing snake_case into file names, but you'll typically find advice online, to use - for separation of words. Google has it's own guidelines that also advise this for directory and file names.

On the web with URLs hyphens are also preferred (and the only choice when it comes to DNS names IIRC). The anchor links to page sections strip special symbols and substitute spaces with -, so underscores won't be consistent there regardless (SEO tends to prefer - too IIRC).

Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
I may have got a bit carried away with admonitions and related features.

- DKIM section has been refactored to better cover both OpenDKIM and Rspamd flows.
- Some Rspamd links fixed that only pointed to section anchors from the rspamd docs page they were extracted from.
- Moved all reflinks to bottom of page as the convention was intended to be (_standard location, easy to get an organized overview of links and avoid any duplication_)
Copy link
Copy Markdown
Member

@polarathene polarathene left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost done, sorry about the adhoc way of applying revisions 😅

Comment thread docs/content/config/security/rspamd.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md Outdated
@georglauterbach
Copy link
Copy Markdown
Member Author

Almost done, sorry about the adhoc way of applying revisions 😅

Absolutely no worries! I like where this is going :)

@georglauterbach georglauterbach removed the meta/feature freeze On hold due to upcoming release process label Apr 10, 2023
Comment thread docs/content/config/best-practices/dkim_dmarc_spf.md
Copy link
Copy Markdown
Member

@polarathene polarathene left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for reference, since this section could probably benefit from a border, but every level of nesting makes it less pleasant to maintain / contribute to.

Another alternative is probably to just swap the content tabs for collapsed admonitions?


Back in 2021, when I first worked on introducing these docs, I had a branch I was working on to document and demonstrate the features, some like what was introduced here with Content Tabs.

Another interesting feature that'd probably be useful, is Snippets, which can import external content from files.

I remember it was a bit tricky to use back then, so I won't attempt to mess with that here. I might try dig up that branch (it's on a disk laying around from an older system), but that'd be later this year due to priorities 😅

Comment on lines +45 to +183
=== "OpenDKIM"

OpenDKIM is currently [enabled by default][docs-env-opendkim].

The command `docker exec <CONTAINER NAME> setup config dkim help` details supported config options, along with some examples.

!!! example "Create a DKIM key"

Generate the DKIM files with:

```sh
docker exec -ti <CONTAINER NAME> setup config dkim
```

Your new DKIM key(s) and OpenDKIM config files have been added to `/tmp/docker-mailserver/opendkim/`.

??? note "LDAP accounts need to specify domains explicitly"

The command is unable to infer the domains from LDAP user accounts, you must specify them:

```sh
setup config dkim domain 'example.com,example.io'
```

??? tip "Changing the key size"

The private key presently defaults to RSA-4096. To create an RSA 2048-bit key run:

```sh
setup config dkim keysize 2048
```

=== "Rspamd"

Opt-in via [`ENABLE_RSPAMD=1`][docs-env-rspamd] (_and disable the default OpenDKIM: `ENABLE_OPENDKIM=0`_).

Rspamd provides DKIM support through two separate modules:

1. [Verifying DKIM signatures from inbound mail][rspamd-docs-dkim-checks] is enabled by default.
2. [Signing outbound mail with your DKIM key][rspamd-docs-dkim-signing] needs additional setup (key + dns + config).

!!! example "Create a DKIM key"

Presently only OpenDKIM is supported with `setup config dkim`. To generate your DKIM key and DNS files you'll need to specify:

- `-s` The DKIM selector (_eg: `mail`, it can be anything you like_)
- `-d` The sender address domain (_everything after `@` from the email address_)

See `rspamadm dkim_keygen -h` for an overview of the supported options.

---

1. Go inside the container with `docker exec -ti <CONTAINER NAME> bash`
2. Add `rspamd/dkim/` folder to your config volume and switch to it: `cd /tmp/docker-mailserver/rspamd/dkim`
3. Run: `rspamadm dkim_keygen -s mail -b 2048 -d example.com -k mail.private > mail.txt` (_change `-d` to your domain-part_)
4. Presently you must ensure Rspamd can read the `<selector>.private` file, run:
-`chgrp _rspamd mail.private`
-`chmod g+r mail.private`

---

!!! bug inline end "DMS config volume support is not ready for Rspamd"

Presently you'll need to [explicitly mount `rspamd/modules/override.d/`][docs-rspamd-config-dropin] as an additional volume; do not use [`rspamd-modules.conf`][docs-rspamd-config-declarative] for this purpose.

Create a configuration file for the DKIM signing module at `rspamd/modules/override.d/dkim_signing.conf` and populate it with config as shown in the example below:

??? example "DKIM Signing Module Configuration Examples"

A simple configuration could look like this:

```cf
# documentation: https://rspamd.com/doc/modules/dkim_signing.html

enabled = true;

sign_authenticated = true;
sign_local = true;

use_domain = "header";
use_redis = false; # don't change unless Redis also provides the DKIM keys
use_esld = true;
check_pubkey = true; # you wan't to use this in the beginning

domain {
example.com {
path = "/tmp/docker-mailserver/rspamd/dkim/mail.private";
selector = "mail";
}
}
```

As shown next, you can:

- You can add more domains into the `domain { ... }` section.
- A domain can also be configured with multiple selectors and keys within a `selectors [ ... ]` array.

```cf
# ...

domain {
example.com {
selectors [
{
path = "/tmp/docker-mailserver/rspamd/dkim/example.com/rsa.private";
selector = "dkim-rsa";
},
{
path = /tmp/docker-mailserver/rspamd/example.com/ed25519.private";
selector = "dkim-ed25519";
}
]
}
example.org {
selectors [
{
path = "/tmp/docker-mailserver/rspamd/dkim/example.org/rsa.private";
selector = "dkim-rsa";
},
{
path = "/tmp/docker-mailserver/rspamd/dkim/example.org/ed25519.private";
selector = "dkim-ed25519";
}
]
}
}
```

!!! warning "Support for DKIM keys using Ed25519"

This modern elliptic curve is supported by Rspamd, but support by third-parties for [verifying Ed25519 DKIM signatures is unreliable][dkim-ed25519-support].

If you sign your mail with this key type, you should include RSA as a fallback, like shown in the above example.

!!! tip "DKIM Signing config: `check_pubkey = true;`"

This setting will have Rspamd query the DNS record for each DKIM selector, verifying each public key matches the private key configured.

If there is a mismatch, a warning will be omitted to the Rspamd log (`/var/log/supervisor/rspamd.log`).
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I won't commit this, but it's a bit of a hack indenting everything another level to use a title-less admonition as a clearer content boundary.

There doesn't seem to be any other supported way to achieve the same beyond the unavailable card grid feature. From what I can see the regular grid wouldn't add a border.

I'm pretty sure I can instead add a <div class="my-border-style"> to wrap the content without an indent, and use some custom CSS if we need that. Slight maintenance risk with the upstream updates potentially not liking that though.

Suggested change
=== "OpenDKIM"
OpenDKIM is currently [enabled by default][docs-env-opendkim].
The command `docker exec <CONTAINER NAME> setup config dkim help` details supported config options, along with some examples.
!!! example "Create a DKIM key"
Generate the DKIM files with:
```sh
docker exec -ti <CONTAINER NAME> setup config dkim
```
Your new DKIM key(s) and OpenDKIM config files have been added to `/tmp/docker-mailserver/opendkim/`.
??? note "LDAP accounts need to specify domains explicitly"
The command is unable to infer the domains from LDAP user accounts, you must specify them:
```sh
setup config dkim domain 'example.com,example.io'
```
??? tip "Changing the key size"
The private key presently defaults to RSA-4096. To create an RSA 2048-bit key run:
```sh
setup config dkim keysize 2048
```
=== "Rspamd"
Opt-in via [`ENABLE_RSPAMD=1`][docs-env-rspamd] (_and disable the default OpenDKIM: `ENABLE_OPENDKIM=0`_).
Rspamd provides DKIM support through two separate modules:
1. [Verifying DKIM signatures from inbound mail][rspamd-docs-dkim-checks] is enabled by default.
2. [Signing outbound mail with your DKIM key][rspamd-docs-dkim-signing] needs additional setup (key + dns + config).
!!! example "Create a DKIM key"
Presently only OpenDKIM is supported with `setup config dkim`. To generate your DKIM key and DNS files you'll need to specify:
- `-s` The DKIM selector (_eg: `mail`, it can be anything you like_)
- `-d` The sender address domain (_everything after `@` from the email address_)
See `rspamadm dkim_keygen -h` for an overview of the supported options.
---
1. Go inside the container with `docker exec -ti <CONTAINER NAME> bash`
2. Add `rspamd/dkim/` folder to your config volume and switch to it: `cd /tmp/docker-mailserver/rspamd/dkim`
3. Run: `rspamadm dkim_keygen -s mail -b 2048 -d example.com -k mail.private > mail.txt` (_change `-d` to your domain-part_)
4. Presently you must ensure Rspamd can read the `<selector>.private` file, run:
-`chgrp _rspamd mail.private`
-`chmod g+r mail.private`
---
!!! bug inline end "DMS config volume support is not ready for Rspamd"
Presently you'll need to [explicitly mount `rspamd/modules/override.d/`][docs-rspamd-config-dropin] as an additional volume; do not use [`rspamd-modules.conf`][docs-rspamd-config-declarative] for this purpose.
Create a configuration file for the DKIM signing module at `rspamd/modules/override.d/dkim_signing.conf` and populate it with config as shown in the example below:
??? example "DKIM Signing Module Configuration Examples"
A simple configuration could look like this:
```cf
# documentation: https://rspamd.com/doc/modules/dkim_signing.html
enabled = true;
sign_authenticated = true;
sign_local = true;
use_domain = "header";
use_redis = false; # don't change unless Redis also provides the DKIM keys
use_esld = true;
check_pubkey = true; # you wan't to use this in the beginning
domain {
example.com {
path = "/tmp/docker-mailserver/rspamd/dkim/mail.private";
selector = "mail";
}
}
```
As shown next, you can:
- You can add more domains into the `domain { ... }` section.
- A domain can also be configured with multiple selectors and keys within a `selectors [ ... ]` array.
```cf
# ...
domain {
example.com {
selectors [
{
path = "/tmp/docker-mailserver/rspamd/dkim/example.com/rsa.private";
selector = "dkim-rsa";
},
{
path = /tmp/docker-mailserver/rspamd/example.com/ed25519.private";
selector = "dkim-ed25519";
}
]
}
example.org {
selectors [
{
path = "/tmp/docker-mailserver/rspamd/dkim/example.org/rsa.private";
selector = "dkim-rsa";
},
{
path = "/tmp/docker-mailserver/rspamd/dkim/example.org/ed25519.private";
selector = "dkim-ed25519";
}
]
}
}
```
!!! warning "Support for DKIM keys using Ed25519"
This modern elliptic curve is supported by Rspamd, but support by third-parties for [verifying Ed25519 DKIM signatures is unreliable][dkim-ed25519-support].
If you sign your mail with this key type, you should include RSA as a fallback, like shown in the above example.
!!! tip "DKIM Signing config: `check_pubkey = true;`"
This setting will have Rspamd query the DNS record for each DKIM selector, verifying each public key matches the private key configured.
If there is a mismatch, a warning will be omitted to the Rspamd log (`/var/log/supervisor/rspamd.log`).
!!! quote ""
=== "OpenDKIM"
OpenDKIM is currently [enabled by default][docs-env-opendkim].
The command `docker exec <CONTAINER NAME> setup config dkim help` details supported config options, along with some examples.
!!! example "Create a DKIM key"
Generate the DKIM files with:
```sh
docker exec -ti <CONTAINER NAME> setup config dkim
```
Your new DKIM key(s) and OpenDKIM config files have been added to `/tmp/docker-mailserver/opendkim/`.
??? note "LDAP accounts need to specify domains explicitly"
The command is unable to infer the domains from LDAP user accounts, you must specify them:
```sh
setup config dkim domain 'example.com,example.io'
```
??? tip "Changing the key size"
The private key presently defaults to RSA-4096. To create an RSA 2048-bit key run:
```sh
setup config dkim keysize 2048
```
=== "Rspamd"
Opt-in via [`ENABLE_RSPAMD=1`][docs-env-rspamd] (_and disable the default OpenDKIM: `ENABLE_OPENDKIM=0`_).
Rspamd provides DKIM support through two separate modules:
1. [Verifying DKIM signatures from inbound mail][rspamd-docs-dkim-checks] is enabled by default.
2. [Signing outbound mail with your DKIM key][rspamd-docs-dkim-signing] needs additional setup (key + dns + config).
!!! example "Create a DKIM key"
Presently only OpenDKIM is supported with `setup config dkim`. To generate your DKIM key and DNS files you'll need to specify:
- `-s` The DKIM selector (_eg: `mail`, it can be anything you like_)
- `-d` The sender address domain (_everything after `@` from the email address_)
See `rspamadm dkim_keygen -h` for an overview of the supported options.
---
1. Go inside the container with `docker exec -ti <CONTAINER NAME> bash`
2. Add `rspamd/dkim/` folder to your config volume and switch to it: `cd /tmp/docker-mailserver/rspamd/dkim`
3. Run: `rspamadm dkim_keygen -s mail -b 2048 -d example.com -k mail.private > mail.txt` (_change `-d` to your domain-part_)
4. Presently you must ensure Rspamd can read the `<selector>.private` file, run:
-`chgrp _rspamd mail.private`
-`chmod g+r mail.private`
---
!!! bug inline end "DMS config volume support is not ready for Rspamd"
Presently you'll need to [explicitly mount `rspamd/modules/override.d/`][docs-rspamd-config-dropin] as an additional volume; do not use [`rspamd-modules.conf`][docs-rspamd-config-declarative] for this purpose.
Create a configuration file for the DKIM signing module at `rspamd/modules/override.d/dkim_signing.conf` and populate it with config as shown in the example below:
??? example "DKIM Signing Module Configuration Examples"
A simple configuration could look like this:
```cf
# documentation: https://rspamd.com/doc/modules/dkim_signing.html
enabled = true;
sign_authenticated = true;
sign_local = true;
use_domain = "header";
use_redis = false; # don't change unless Redis also provides the DKIM keys
use_esld = true;
check_pubkey = true; # you wan't to use this in the beginning
domain {
example.com {
path = "/tmp/docker-mailserver/rspamd/dkim/mail.private";
selector = "mail";
}
}
```
As shown next, you can:
- You can add more domains into the `domain { ... }` section.
- A domain can also be configured with multiple selectors and keys within a `selectors [ ... ]` array.
```cf
# ...
domain {
example.com {
selectors [
{
path = "/tmp/docker-mailserver/rspamd/dkim/example.com/rsa.private";
selector = "dkim-rsa";
},
{
path = /tmp/docker-mailserver/rspamd/example.com/ed25519.private";
selector = "dkim-ed25519";
}
]
}
example.org {
selectors [
{
path = "/tmp/docker-mailserver/rspamd/dkim/example.org/rsa.private";
selector = "dkim-rsa";
},
{
path = "/tmp/docker-mailserver/rspamd/dkim/example.org/ed25519.private";
selector = "dkim-ed25519";
}
]
}
}
```
!!! warning "Support for DKIM keys using Ed25519"
This modern elliptic curve is supported by Rspamd, but support by third-parties for [verifying Ed25519 DKIM signatures is unreliable][dkim-ed25519-support].
If you sign your mail with this key type, you should include RSA as a fallback, like shown in the above example.
!!! tip "DKIM Signing config: `check_pubkey = true;`"
This setting will have Rspamd query the DNS record for each DKIM selector, verifying each public key matches the private key configured.
If there is a mismatch, a warning will be omitted to the Rspamd log (`/var/log/supervisor/rspamd.log`).

Comment thread docs/mkdocs.yml Outdated
Copy link
Copy Markdown
Member

@polarathene polarathene left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides earlier commentary on this LGTM 👍

List of tasks to keep in mind:

  • Future work can improve config setup dkim to use neither opendkim-genkey / rspamadm dkim_keygen (although not too important with phasing out of OpenDKIM).
  • Future PR could shift OpenDKIM/Rspamd config generation to runtime based on a common config directory for DKIM config, using folder and file name to infer relevant values.
  • Future PR could support setup config dkim format web option if you wanted to simplify those instructions. A helper script example has been provided to output either TXT record format.
  • ENV docs for ENABLE_RSPAMD=1 conflict with advice to adopt Rspamd, as does other config concerns.
  • mail-server => mail server is a change you introduced in a recent PR and partially here, you need a PR that does a consistency pass throughout all pages in the docs to avoid drift.
  • kebab-case has recently been ignored, mixing filenames of scripts and docs (arguably worse). Advice is to revert back to kebab-case, but more importantly address the inconsistency with a future PR before the mix worsens.
  • DKIM key generation support should change default size back to 2048-bit, and update the associated mention in DKIM docs accordingly.
  • DKIM command also warns about selector support not being implemented, but it has been for some time now.

@github-actions
Copy link
Copy Markdown
Contributor

Documentation preview for this PR is ready! 🎉

Built with commit: 5835d4b

@polarathene
Copy link
Copy Markdown
Member

Merging.

@georglauterbach do you want the above bullet list of TODO items to be raised as issues?

@polarathene polarathene merged commit 34a1fd6 into master Apr 10, 2023
@polarathene polarathene deleted the docs/dns branch April 10, 2023 10:08
@georglauterbach
Copy link
Copy Markdown
Member Author

georglauterbach commented Apr 10, 2023

@georglauterbach do you want the above bullet list of TODO items to be raised as issues?

Yes, please :) I will make sure to resolve the points one by one.

@polarathene
Copy link
Copy Markdown
Member

Yes, please :)

I'll sort that out tomorrow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/documentation kind/improvement Improve an existing feature, configuration file or the documentation kind/update Update an existing feature, configuration file or the documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants