Updated opendkim to be built from source.

This commit is contained in:
2026-03-28 03:38:03 +01:00
parent e6fa15d9ec
commit 47f55ce96d
4 changed files with 401 additions and 108 deletions

View File

@@ -1,19 +1,99 @@
FROM ubuntu:22.04 # Build and runtime stages for OpenDKIM on Ubuntu 16.04
FROM ubuntu:16.04 AS builder
WORKDIR /opt/opendkim ARG DEBIAN_FRONTEND=noninteractive
ARG OPENDKIM_VERSION=2.10.3
ARG OPENDKIM_TARBALL=opendkim-${OPENDKIM_VERSION}.tar.gz
ARG OPENDKIM_URL=https://downloads.sourceforge.net/project/opendkim/${OPENDKIM_TARBALL}
RUN apt update && \ RUN apt-get update && apt-get install -y --no-install-recommends \
apt upgrade -y && \ build-essential \
apt install -y opendkim inetutils-syslogd curl ca-certificates \
wget \
tar \
gzip \
make \
autoconf \
automake \
libtool \
pkg-config \
libssl-dev \
libmilter-dev \
libbsd-dev \
zlib1g-dev \
&& rm -rf /var/lib/apt/lists/*
RUN curl -SsfL -o /usr/bin/gomplate "https://github.com/hairyhenderson/gomplate/releases/download/v3.11.5/gomplate_linux-amd64-slim" && \ WORKDIR /build
chmod 755 /usr/bin/gomplate && \
mkdir -p /etc/rsyslog.d/ && \
touch /etc/rsyslog.d/stdout.conf && \
echo "*.* /dev/stdout" > /etc/rsyslog.d/stdout.conf
COPY entrypoint.sh . RUN wget -O ${OPENDKIM_TARBALL} ${OPENDKIM_URL} \
COPY opendkim.conf.tpl . && tar xzf ${OPENDKIM_TARBALL}
EXPOSE 8892/tcp WORKDIR /build/opendkim-${OPENDKIM_VERSION}
CMD ["/bin/bash", "entrypoint.sh"]
# Basic build:
# - prefix /usr
# - config in /etc/opendkim
# - pid file under /run/opendkim
RUN ./configure \
--prefix=/usr \
--sysconfdir=/etc \
--localstatedir=/var \
--disable-shared \
--enable-static
RUN make -j"$(nproc)"
# Install into staging root
RUN make DESTDIR=/opt/opendkim-dist install
# Collect runtime libs actually needed by installed binaries
RUN mkdir -p /opt/opendkim-libs \
&& find /opt/opendkim-dist -type f -executable -exec ldd {} \; \
| awk '/=> \// {print $3} /^\// {print $1}' \
| sort -u \
| xargs -r -I '{}' cp -v --parents '{}' /opt/opendkim-libs
# Pack staged install and copied libs as tarballs to avoid BuildKit COPY-to-/ issues
RUN cd /opt/opendkim-dist \
&& tar -cf /opt/opendkim-dist.tar .
RUN cd /opt/opendkim-libs \
&& tar -cf /opt/opendkim-libs.tar .
# Final runtime image
FROM ubuntu:16.04
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
ssl-cert \
inetutils-syslogd \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /opt/opendkim-dist.tar /tmp/opendkim-dist.tar
COPY --from=builder /opt/opendkim-libs.tar /tmp/opendkim-libs.tar
RUN tar -C / -xf /tmp/opendkim-dist.tar \
&& tar -C / -xf /tmp/opendkim-libs.tar \
&& rm -f /tmp/opendkim-dist.tar /tmp/opendkim-libs.tar
RUN groupadd -f opendkim \
&& (id -u opendkim >/dev/null 2>&1 || useradd -r -g opendkim -d /var/lib/opendkim -s /usr/sbin/nologin opendkim)
RUN mkdir -p \
/etc/opendkim \
/etc/opendkim/keys \
/run/opendkim \
/var/lib/opendkim \
&& chown -R opendkim:opendkim /etc/opendkim/keys /run/opendkim /var/lib/opendkim
RUN touch /etc/opendkim/KeyTable /etc/opendkim/SigningTable /etc/opendkim/TrustedHosts \
&& chown opendkim:opendkim /etc/opendkim/KeyTable /etc/opendkim/SigningTable /etc/opendkim/TrustedHosts
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
EXPOSE 8891
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

212
README.md
View File

@@ -4,55 +4,215 @@ docker build --rm -t opendkim:latest .
``` ```
# Generating private key # Generating private key
Before running the private key must be generated using opendkim-keygen or supplied. Before running the container, a private key must be generated using `opendkim-genkey` or supplied manually.
```sh
# Generate private key.
opendkim-genkey --bits=2048 --selector=dkim --restrict --verbose
# Getting publickey for DNS record. ```sh
# Generate private key and DNS record files.
opendkim-genkey --bits=2048 --selector=dkim --restrict --verbose --domain=example.com
# Generated files:
# dkim.private
# dkim.txt
```
To extract the public key value for a DNS TXT record:
```sh
cat dkim.txt | tr -d "\"\n\" \t" | sed -r "s/.*\((.*)\).*/\\1\n/" cat dkim.txt | tr -d "\"\n\" \t" | sed -r "s/.*\((.*)\).*/\\1\n/"
``` ```
Example DNS record name:
```txt
dkim._domainkey.example.com
```
# Running the image # Running the image
```sh ```sh
docker run -it --rm --name opendkim -p 8892:8892 -v /path/dkim.private:/opt/opendkim/keys/dkim.private opendkim:latest docker run -it --rm \
--name opendkim \
-p 8892:8892 \
-v /path/to/dkim.private:/opt/opendkim/keys/dkim.private:ro \
opendkim:latest
```
Example with custom domain and selector:
```sh
docker run -it --rm \
--name opendkim \
-p 8892:8892 \
-e OPENDKIM_DOMAIN=example.com \
-e OPENDKIM_SELECTOR=mail \
-e OPENDKIM_SOCKET="inet:8892@0.0.0.0" \
-v /path/to/mail.private:/opt/opendkim/keys/dkim.private:ro \
opendkim:latest
``` ```
# Environment variables # Environment variables
These values are default and can be overriden by declaring environment variable with naother value. These values are defaults and can be overridden by setting environment variables.
```sh
# Attempts to become the specified userid before starting operations. The value is of the form userid[:group].
OPENDKIM_USERID="opendkim"
# Specifies the socket that should be established by the filter to receive connections. ```sh
# Runtime user name.
OPENDKIM_USER="opendkim"
# Runtime group name.
OPENDKIM_GROUP="opendkim"
# User and group used by OpenDKIM. Format: user:group
OPENDKIM_USERID="opendkim:opendkim"
# Socket used by the milter service.
OPENDKIM_SOCKET="inet:8892@0.0.0.0" OPENDKIM_SOCKET="inet:8892@0.0.0.0"
# A set of domains whose mail should be signed by this filter. # Domain whose mail should be signed.
OPENDKIM_DOMAIN="*" OPENDKIM_DOMAIN="*"
# Gives the location of a PEM-formatted private key to be used for signing all messages. Ignored if a KeyTable is defined. # DKIM selector.
OPENDKIM_KEYFILE="/opt/opendkim/keys/dkim.private"
# Defines the name of the selector to be used when signing messages.
OPENDKIM_SELECTOR="dkim" OPENDKIM_SELECTOR="dkim"
# Selects the canonicalization method(s) to be used when signing messages. # Path to private key mounted into the container.
OPENDKIM_KEYFILE="/opt/opendkim/keys/dkim.private"
# Canonicalization method used when signing.
OPENDKIM_CANONICALIZATION="relaxed/simple" OPENDKIM_CANONICALIZATION="relaxed/simple"
# Selects operating modes. The string is a concatenation of characters # Operating mode:
# that indicate which mode(s) of operation are desired. Valid modes are s (signer) and v (verifier). # s = signer
# v = verifier
# sv = sign and verify
OPENDKIM_MODE="sv" OPENDKIM_MODE="sv"
# Sign subdomains of those listed by the Domain parameter as well as the actual domains. # Whether to sign subdomains too.
OPENDKIM_SUBDOMAINS="true" OPENDKIM_SUBDOMAINS="true"
# Specifies a set of header fields that should be included in all signature header lists (the "h=" tag) # Headers to oversign.
# once more than the number of times they were actually present in the signed message.
OPENDKIM_OVERSIGNHEADERS="From" OPENDKIM_OVERSIGNHEADERS="From"
# Specifies a file from which trust anchor data should be read when doing DNS queries and applying the DNSSEC protocol. # Optional DNSSEC trust anchor file.
OPENDKIM_TRUSTANCHORFILE="/usr/share/dns/root.key" # Added to config only if the file exists.
OPENDKIM_TRUSTANCHORFILE=""
# Identifies a set internal hosts whose mail should be signed rather than verified. # Internal hosts whose mail should be signed instead of verified.
OPENDKIM_INTERNALHOSTS="127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8" OPENDKIM_INTERNALHOSTS="127.0.0.1,localhost,127.0.0.0/8,192.168.0.0/16,172.16.0.0/12,10.0.0.0/8"
# ExternalIgnoreList value for OpenDKIM.
OPENDKIM_EXTERNALIGNORELIST="refile:/etc/opendkim/TrustedHosts"
# Path to file used for InternalHosts.
OPENDKIM_INTERNALHOSTS_FILE="/etc/opendkim/TrustedHosts"
# Path to KeyTable.
OPENDKIM_KEYTABLE="/etc/opendkim/KeyTable"
# Path to SigningTable.
OPENDKIM_SIGNINGTABLE="refile:/etc/opendkim/SigningTable"
# PID file path.
OPENDKIM_PIDFILE="/run/opendkim/opendkim.pid"
# Umask used by OpenDKIM.
OPENDKIM_UMASK="002"
# Whether OpenDKIM should auto-restart.
OPENDKIM_AUTO_RESTART="no"
# Auto restart rate.
OPENDKIM_AUTO_RESTART_RATE="10/1h"
# DNS query timeout in seconds.
OPENDKIM_DNS_TIMEOUT="5"
# Signing algorithm.
OPENDKIM_SIGNATURE_ALGORITHM="rsa-sha256"
# Refuse unsafe private key permissions.
OPENDKIM_REQUIRE_SAFE_KEYS="yes"
# Remove old signatures before signing.
OPENDKIM_REMOVE_OLD_SIGNATURES="no"
# Add SoftwareHeader.
OPENDKIM_LOGRESULTS="yes"
# Milter debug level.
OPENDKIM_MILTER_DEBUG="6"
# Optional custom nameservers.
OPENDKIM_NAMESERVERS=""
``` ```
# Behavior
At startup the container:
- creates OpenDKIM runtime directories
- copies the mounted private key to `/var/opendkim/dkim.private`
- sets secure ownership and permissions on the copied key
- generates `TrustedHosts`, `KeyTable`, and `SigningTable` if they are empty
- generates `/etc/opendkim.conf` from environment variables
- starts OpenDKIM using `/etc/opendkim.conf`
# Generated files
The entrypoint generates these files automatically:
```txt
/etc/opendkim.conf
/etc/opendkim/TrustedHosts
/etc/opendkim/KeyTable
/etc/opendkim/SigningTable
/var/opendkim/dkim.private
```
# Default generated tables
For example, with:
```sh
OPENDKIM_DOMAIN=example.com
OPENDKIM_SELECTOR=dkim
```
the generated files look like this:
## /etc/opendkim/KeyTable
```txt
dkim._domainkey.example.com example.com:dkim:/var/opendkim/dkim.private
```
## /etc/opendkim/SigningTable
```txt
*@example.com dkim._domainkey.example.com
```
## /etc/opendkim/TrustedHosts
```txt
127.0.0.1
localhost
127.0.0.0/8
192.168.0.0/16
172.16.0.0/12
10.0.0.0/8
```
# Postfix example
Example Postfix settings when OpenDKIM runs in another container named `opendkim`:
```conf
smtpd_milters = inet:opendkim:8892
non_smtpd_milters = inet:opendkim:8892
milter_protocol = 6
milter_default_action = accept
```
# Notes
- The private key must be mounted into the container at the path specified by `OPENDKIM_KEYFILE`.
- The entrypoint copies the private key to `/var/opendkim/dkim.private` and locks down permissions to `0600`.
- `OPENDKIM_TRUSTANCHORFILE` is optional and is only written to config if the file exists.
- `OPENDKIM_NAMESERVERS` is optional and is only written to config if non-empty.
- `OPENDKIM_DOMAIN="*"` is allowed by the script, but for real signing setups you usually want a concrete domain such as `example.com`.
- The default socket is `inet:8892@0.0.0.0`, so map port `8892` unless you override `OPENDKIM_SOCKET`.
- The current entrypoint starts OpenDKIM with:
```sh
./usr/sbin/opendkim -x /etc/opendkim.conf
syslogd -n -f /etc/rsyslog.d/stdout.conf
```
so the image expects syslog configuration to be present.

View File

@@ -1,25 +1,125 @@
#!/bin/bash #!/bin/bash
# Misc default variables. # Core defaults.
export OPENDKIM_USERID=${OPENDKIM_USERID:-opendkim} : "${OPENDKIM_USER:=opendkim}"
export OPENDKIM_SOCKET=${OPENDKIM_SOCKET:-inet:8892@0.0.0.0} : "${OPENDKIM_GROUP:=opendkim}"
export OPENDKIM_DOMAIN=${OPENDKIM_DOMAIN:-*} : "${OPENDKIM_USERID:=${OPENDKIM_USER}:${OPENDKIM_GROUP}}"
export OPENDKIM_KEYFILE=${OPENDKIM_KEYFILE:-/opt/opendkim/keys/dkim.private} : "${OPENDKIM_SOCKET:=inet:8892@0.0.0.0}"
export OPENDKIM_SELECTOR=${OPENDKIM_SELECTOR:-dkim}
export OPENDKIM_CANONICALIZATION=${OPENDKIM_CANONICALIZATION:-relaxed/simple}
export OPENDKIM_MODE=${OPENDKIM_MODE:-sv}
export OPENDKIM_SUBDOMAINS=${OPENDKIM_SUBDOMAINS:-true}
export OPENDKIM_OVERSIGNHEADERS=${OPENDKIM_OVERSIGNHEADERS:-From}
export OPENDKIM_TRUSTANCHORFILE=${OPENDKIM_TRUSTANCHORFILE:-/usr/share/dns/root.key}
export OPENDKIM_INTERNALHOSTS=${OPENDKIM_INTERNALHOSTS:-127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8}
# Configuration templates. # Signing defaults.
gomplate -f opendkim.conf.tpl > /opt/opendkim/opendkim.conf : "${OPENDKIM_DOMAIN:=*}"
: "${OPENDKIM_SELECTOR:=dkim}"
: "${OPENDKIM_KEYFILE:=/opt/opendkim/keys/dkim.private}"
: "${OPENDKIM_CANONICALIZATION:=relaxed/simple}"
: "${OPENDKIM_MODE:=sv}"
: "${OPENDKIM_SUBDOMAINS:=true}"
: "${OPENDKIM_OVERSIGNHEADERS:=From}"
mkdir -p /var/opendkim # DNS / trust defaults.
cp $OPENDKIM_KEYFILE /var/opendkim/dkim.private : "${OPENDKIM_TRUSTANCHORFILE:=}"
chown opendkim:opendkim /var/opendkim/dkim.private : "${OPENDKIM_INTERNALHOSTS:=127.0.0.1,localhost,127.0.0.0/8,192.168.0.0/16,172.16.0.0/12,10.0.0.0/8}"
chmod 0600 /var/opendkim/dkim.private : "${OPENDKIM_EXTERNALIGNORELIST:=refile:/etc/opendkim/TrustedHosts}"
: "${OPENDKIM_INTERNALHOSTS_FILE:=/etc/opendkim/TrustedHosts}"
opendkim -x /opt/opendkim/opendkim.conf # Table files.
: "${OPENDKIM_KEYTABLE:=/etc/opendkim/KeyTable}"
: "${OPENDKIM_SIGNINGTABLE:=refile:/etc/opendkim/SigningTable}"
: "${OPENDKIM_PIDFILE:=/run/opendkim/opendkim.pid}"
# Behavior.
: "${OPENDKIM_UMASK:=002}"
: "${OPENDKIM_BACKGROUND:=no}"
: "${OPENDKIM_AUTO_RESTART:=no}"
: "${OPENDKIM_AUTO_RESTART_RATE:=10/1h}"
: "${OPENDKIM_DNS_TIMEOUT:=5}"
: "${OPENDKIM_SIGNATURE_ALGORITHM:=rsa-sha256}"
# Optional extras.
: "${OPENDKIM_REQUIRE_SAFE_KEYS:=yes}"
: "${OPENDKIM_REMOVE_OLD_SIGNATURES:=no}"
: "${OPENDKIM_LOGRESULTS:=yes}"
: "${OPENDKIM_MILTER_DEBUG:=6}"
: "${OPENDKIM_NAMESERVERS:=}"
mkdir -p \
/etc/opendkim \
/run/opendkim \
/var/lib/opendkim \
/var/opendkim
touch /etc/opendkim/TrustedHosts /etc/opendkim/KeyTable /etc/opendkim/SigningTable
chown -R "${OPENDKIM_USER}:${OPENDKIM_GROUP}" /run/opendkim /var/lib/opendkim /var/opendkim
chmod 0755 /run/opendkim /var/lib/opendkim /var/opendkim
# Copy private key to runtime location with safe permissions.
if [ -f "${OPENDKIM_KEYFILE}" ]; then
cp "${OPENDKIM_KEYFILE}" /var/opendkim/dkim.private
chown "${OPENDKIM_USER}:${OPENDKIM_GROUP}" /var/opendkim/dkim.private
chmod 0600 /var/opendkim/dkim.private
fi
# Generate TrustedHosts from env if file is empty.
if [ ! -s /etc/opendkim/TrustedHosts ]; then
printf '%s\n' "${OPENDKIM_INTERNALHOSTS}" | tr ',' '\n' > /etc/opendkim/TrustedHosts
fi
# Generate KeyTable from env if file is empty.
if [ ! -s /etc/opendkim/KeyTable ]; then
printf '%s._domainkey.%s %s:%s:/var/opendkim/dkim.private\n' \
"${OPENDKIM_SELECTOR}" \
"${OPENDKIM_DOMAIN}" \
"${OPENDKIM_DOMAIN}" \
"${OPENDKIM_SELECTOR}" \
> /etc/opendkim/KeyTable
fi
# Generate SigningTable from env if file is empty.
if [ ! -s /etc/opendkim/SigningTable ]; then
printf '*@%s %s._domainkey.%s\n' \
"${OPENDKIM_DOMAIN}" \
"${OPENDKIM_SELECTOR}" \
"${OPENDKIM_DOMAIN}" \
> /etc/opendkim/SigningTable
fi
chown "${OPENDKIM_USER}:${OPENDKIM_GROUP}" /etc/opendkim/TrustedHosts /etc/opendkim/KeyTable /etc/opendkim/SigningTable
cat > /etc/opendkim.conf <<EOF
Syslog yes
LogWhy yes
UMask ${OPENDKIM_UMASK}
Canonicalization ${OPENDKIM_CANONICALIZATION}
Mode ${OPENDKIM_MODE}
SubDomains ${OPENDKIM_SUBDOMAINS}
OversignHeaders ${OPENDKIM_OVERSIGNHEADERS}
UserID ${OPENDKIM_USERID}
Socket ${OPENDKIM_SOCKET}
PidFile ${OPENDKIM_PIDFILE}
KeyTable ${OPENDKIM_KEYTABLE}
SigningTable ${OPENDKIM_SIGNINGTABLE}
ExternalIgnoreList ${OPENDKIM_EXTERNALIGNORELIST}
InternalHosts refile:${OPENDKIM_INTERNALHOSTS_FILE}
AutoRestart ${OPENDKIM_AUTO_RESTART}
AutoRestartRate ${OPENDKIM_AUTO_RESTART_RATE}
DNSTimeout ${OPENDKIM_DNS_TIMEOUT}
SignatureAlgorithm ${OPENDKIM_SIGNATURE_ALGORITHM}
RequireSafeKeys ${OPENDKIM_REQUIRE_SAFE_KEYS}
RemoveOldSignatures ${OPENDKIM_REMOVE_OLD_SIGNATURES}
MilterDebug ${OPENDKIM_MILTER_DEBUG}
EOF
if [ -n "${OPENDKIM_TRUSTANCHORFILE}" ] && [ -f "${OPENDKIM_TRUSTANCHORFILE}" ]; then
echo "TrustAnchorFile ${OPENDKIM_TRUSTANCHORFILE}" >> /etc/opendkim.conf
fi
if [ "${OPENDKIM_LOGRESULTS}" = "yes" ]; then
echo "SoftwareHeader yes" >> /etc/opendkim.conf
fi
if [ -n "${OPENDKIM_NAMESERVERS}" ]; then
echo "Nameservers ${OPENDKIM_NAMESERVERS}" >> /etc/opendkim.conf
fi
./usr/sbin/opendkim -x /etc/opendkim.conf
syslogd -n -f /etc/rsyslog.d/stdout.conf syslogd -n -f /etc/rsyslog.d/stdout.conf

View File

@@ -1,47 +0,0 @@
# Disable log to syslog because we want to log in stdout.
Syslog true
# Log via calls to syslog(3) additional entries indicating successful signing or verification of messages.
SyslogSuccess true
# If logging is enabled (see Syslog below), issues very detailed logging about the
# logic behind the filters decision to either sign a message or verify it.
LogWhy true
# Specifies the path to a file that should be created at process start containing the process ID.
PidFile /var/run/opendkim/opendkim.pid
# Attempts to become the specified userid before starting operations. The value is of the form userid[:group].
UserID {{ .Env.OPENDKIM_USERID }}
# Specifies the socket that should be established by the filter to receive connections.
Socket {{ .Env.OPENDKIM_SOCKET }}
# A set of domains whose mail should be signed by this filter.
Domain {{ .Env.OPENDKIM_DOMAIN }}
# Gives the location of a PEM-formatted private key to be used for signing all messages. Ignored if a KeyTable is defined.
KeyFile /var/opendkim/dkim.private
# Defines the name of the selector to be used when signing messages.
Selector {{ .Env.OPENDKIM_SELECTOR }}
# Selects the canonicalization method(s) to be used when signing messages.
Canonicalization {{ .Env.OPENDKIM_CANONICALIZATION }}
# Selects operating modes. The string is a concatenation of characters
# that indicate which mode(s) of operation are desired. Valid modes are s (signer) and v (verifier).
Mode {{ .Env.OPENDKIM_MODE }}
# Sign subdomains of those listed by the Domain parameter as well as the actual domains.
SubDomains {{ .Env.OPENDKIM_SUBDOMAINS }}
# Specifies a set of header fields that should be included in all signature header lists (the "h=" tag)
# once more than the number of times they were actually present in the signed message.
OversignHeaders {{ .Env.OPENDKIM_OVERSIGNHEADERS }}
# Specifies a file from which trust anchor data should be read when doing DNS queries and applying the DNSSEC protocol.
TrustAnchorFile {{ .Env.OPENDKIM_TRUSTANCHORFILE }}
# Identifies a set internal hosts whose mail should be signed rather than verified.
InternalHosts {{ .Env.OPENDKIM_INTERNALHOSTS }}