Compare commits

...

5 Commits

Author SHA1 Message Date
Brennan Kinney 6076faee3a
chore: Add smallstep step-cli command 2025-02-15 21:25:24 +13:00
Brennan Kinney d046ab5b57
chore: Add notes for legacy packages 2025-02-15 21:24:40 +13:00
Brennan Kinney 523f5b8fbb
chore: open-dkim config generator refactor 2025-02-15 21:23:14 +13:00
Brennan Kinney 466602c66d
chore: Better organize open-dkim config generator 2025-02-15 14:21:16 +13:00
Brennan Kinney 8fa186ae76
chore: Revise open-dkim config generator 2025-02-15 13:43:56 +13:00
5 changed files with 498 additions and 92 deletions

255
target/bin/dkim Normal file
View File

@ -0,0 +1,255 @@
#!/bin/bash
# shellcheck source=../scripts/helpers/index.sh
source /usr/local/bin/helpers/index.sh
function _main() {
# Default parameters (updated by `_parse_arguments()`):
local KEYSIZE=2048
local SELECTOR=mail
local DMS_DOMAINS=
_require_n_parameters_or_print_usage 0 "${@}"
_parse_arguments "${@}"
_generate_dkim_keys
}
function __usage() {
printf '%s' "${PURPLE}OPEN-DKIM${RED}(${YELLOW}8${RED})
${ORANGE}NAME${RESET}
open-dkim - Configure DKIM (DomainKeys Identified Mail)
${ORANGE}SYNOPSIS${RESET}
setup config dkim [ OPTIONS${RED}...${RESET} ]
${ORANGE}DESCRIPTION${RESET}
Creates DKIM keys and configures them within DMS for OpenDKIM.
OPTIONS can be used when your requirements are not met by the defaults.
When not using 'ACCOUNT_PROVISIONER=FILE' (default), you may need to explicitly
use the 'domain' option to generate DKIM keys for your mail account domains.
${ORANGE}OPTIONS${RESET}
${BLUE}Generic Program Information${RESET}
help Print the usage information.
${BLUE}Configuration adjustments${RESET}
keysize Set the size of the keys to be generated.
Possible values: 1024, 2048 and 4096
Default: 2048
selector Set a manual selector for the key.
Default: mail
domain Provide the domain(s) for which to generate keys for.
Default: The FQDN assigned to DMS, excluding any subdomain.
'ACCOUNT_PROVISIONER=FILE' also sources domains from mail accounts.
${ORANGE}EXAMPLES${RESET}
${LWHITE}setup config dkim keysize 4096${RESET}
Creates keys with their length increased to a size of 4096-bit.
${LWHITE}setup config dkim keysize 1024 selector 2023-dkim${RESET}
Creates 1024-bit sized keys, and changes the DKIM selector to '2023-dkim'.
${LWHITE}setup config dkim domain 'example.com,another-example.com'${RESET}
Only generates DKIM keys for the specified domains: 'example.com' and 'another-example.com'.
${ORANGE}EXIT STATUS${RESET}
Exit status is 0 if command was successful. If wrong arguments are provided or arguments contain
errors, the script will exit early with a non-zero exit status.
"
}
function _parse_arguments() {
# Parse the command args through iteration:
while [[ ${#} -gt 0 ]]; do
case "${1}" in
( 'keysize' )
if [[ -n ${2+set} ]]; then
KEYSIZE="${2}"
_log 'debug' "Keysize set to '${KEYSIZE}'"
else
_exit_with_error "No keysize provided after 'keysize' argument"
fi
;;
( 'selector' )
if [[ -n ${2+set} ]]; then
SELECTOR="${2}"
_log 'debug' "Selector set to '${SELECTOR}'"
else
_exit_with_error "No selector provided after 'selector' argument"
fi
;;
( 'domain' )
if [[ -n ${2+set} ]]; then
DMS_DOMAINS="${2}"
_log 'debug' "Domain(s) set to '${DMS_DOMAINS}'"
else
_exit_with_error "No domain(s) provided after 'domain' argument"
fi
;;
( 'help' )
__usage
exit 0
;;
( * )
__usage
_exit_with_error "Unknown option(s) '${1}' ${2:+"and '${2}'"}"
;;
esac
# Discard these two args (option + value) now that they've been processed:
shift 2
done
}
# 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 <<< "${PUBLIC_KEY}" | sed -E 's#(.*)# "\1"#')
# Create a complimentary TXT record formatted as an RFC 1035 DNS zone file:
cat << EOF > "${SELECTOR}.zone"
${SELECTOR}._domainkey IN TXT ( "v=DKIM1; k=rsa; "
${PUBLIC_KEY_MULTILINE}
) ;
EOF
function _generate_dkim_keys() {
_generate_domains_config
if [[ ! -s ${DATABASE_VHOST} ]]; then
_log 'warn' 'No entries found, no keys to make'
exit 0
fi
# Initialize OpenDKIM configs if necessary:
_create_opendkim_configs
# Generate a keypair per domain and add reference to OpenDKIM configs:
local ENTRY_KEY KEY_TABLE_ENTRY SIGNING_TABLE_ENTRY
while read -r DKIM_DOMAIN; do
_create_dkim_key "${DKIM_DOMAIN}"
# Create / Update OpenDKIM configs with new DKIM key:
ENTRY_KEY="${SELECTOR}._domainkey.${DKIM_DOMAIN}"
KEY_TABLE_ENTRY="${ENTRY_KEY} ${DKIM_DOMAIN}:${SELECTOR}:/etc/dms/keys/${SELECTOR}.private"
SIGNING_TABLE_ENTRY="*@${DKIM_DOMAIN} ${ENTRY_KEY}"
# If no existing entry, add one:
if ! grep -q "${KEY_TABLE_ENTRY}" "${KEY_TABLE_FILE}"; then
echo "${KEY_TABLE_ENTRY}" >> "${KEY_TABLE_FILE}"
fi
if ! grep -q "${SIGNING_TABLE_ENTRY}" "${SIGNING_TABLE_FILE}"; then
echo "${SIGNING_TABLE_ENTRY}" >> "${SIGNING_TABLE_FILE}"
fi
done < <(_get_valid_lines_from_file "${DATABASE_VHOST}")
# No longer needed, remove:
rm "${DATABASE_VHOST}"
# Ensure ownership is consistent for all content belonging to the base directory,
# During container startup, an internal copy will be made via `_setup_opendkim()`
# with ownership we expect, while this chown is for the benefit of the users ownership.
chown -R "$(stat -c '%U:%G' "${OPENDKIM_BASE_DIR}")" "${OPENDKIM_BASE_DIR}"
}
# Prepare a file with one domain per line (iterated via while loop as DKIM_DOMAIN):
# Depends on methods from `scripts/helpers/postfix.sh`:
DATABASE_VHOST='/tmp/vhost.dkim'
function _generate_domains_config() {
local TMP_VHOST='/tmp/vhost.dkim.tmp'
# Generate the default vhost (equivalent to /etc/postfix/vhost),
# unless CLI arg DMS_DOMAINS provided an alternative list to use instead:
if [[ -z ${DMS_DOMAINS} ]]; then
_obtain_hostname_and_domainname
# uses TMP_VHOST:
_vhost_collect_postfix_domains
else
tr ',' '\n' <<< "${DMS_DOMAINS}" >"${TMP_VHOST}"
fi
# Uses DATABASE_VHOST + TMP_VHOST:
_create_vhost
}
# `opendkim-genkey` generates two files at the configured `--directory`:
# - <selector>.private (Private key, PEM encoded)
# - <selector>.txt (Public key, formatted as a TXT record for a RFC 1035 DNS Zone file)
function _create_dkim_key() {
DKIM_DOMAIN=${1?Expected to be provided a domain}
OPENDKIM_DOMAINKEY_DIR="${OPENDKIM_BASE_DIR}/keys/${DKIM_DOMAIN}"
mkdir -p "${OPENDKIM_DOMAINKEY_DIR}"
DKIM_KEY_FILE="${OPENDKIM_DOMAINKEY_DIR}/${SELECTOR}.private"
if [[ ! -f "${DKIM_KEY_FILE}" ]]; then
_log 'info' "Creating DKIM private key '${DKIM_KEY_FILE}'"
# NOTE:
# --domain only affects a comment in the generated DNS Zone file
# --subdomains is the default,
# --nosubdomains would add `t=s` to the DNS TXT record generated
# http://www.opendkim.org/opendkim-genkey.8.html
opendkim-genkey \
--bits="${KEYSIZE}" \
--subdomains \
--domain="${DKIM_DOMAIN}" \
--selector="${SELECTOR}" \
--directory="${OPENDKIM_DOMAINKEY_DIR}"
fi
}
OPENDKIM_BASE_DIR='/tmp/docker-mailserver/opendkim'
KEY_TABLE_FILE="${OPENDKIM_BASE_DIR}/KeyTable"
SIGNING_TABLE_FILE="${OPENDKIM_BASE_DIR}/SigningTable"
TRUSTED_HOSTS_FILE="${OPENDKIM_BASE_DIR}/TrustedHosts"
# Create configs if missing:
function _create_opendkim_configs() {
_log 'debug' 'Creating any missing OpenDKIM configs'
mkdir -p "${OPENDKIM_BASE_DIR}"
local OPENDKIM_CONFIGS=(
"${KEY_TABLE_FILE}"
"${SIGNING_TABLE_FILE}"
"${TRUSTED_HOSTS_FILE}"
)
# Only create if the file doesn't exist (avoids modifying mtime):
for FILE in ${OPENDKIM_CONFIGS[@]}; do
[[ ! -f "${FILE}" ]] && touch "${FILE}"
done
# If file exists but is empty, add default hosts to trust:
if [[ ! -s "${TRUSTED_HOSTS_FILE}" ]]; then
_log 'debug' 'Adding default trust to OpenDKIM TrustedHosts config'
echo "127.0.0.1" > "${TRUSTED_HOSTS_FILE}"
echo "localhost" >> "${TRUSTED_HOSTS_FILE}"
fi
}
_main "${@}"
function _transform_public_key_file_to_dns_record_contents() {
_log 'trace' 'Transforming DNS zone format to DNS record content now'
: >"${PUBLIC_KEY_DNS_FILE}"
grep -o '".*"' "${PUBLIC_KEY_FILE}" | tr -d '"\n' >>"${PUBLIC_KEY_DNS_FILE}"
echo '' >>"${PUBLIC_KEY_DNS_FILE}"
if ! _log_level_is '(warn|error)'; then
_log 'info' "Here is the content of the TXT DNS record ${SELECTOR}._domainkey.${DOMAIN} that you need to create:\n"
cat "${PUBLIC_KEY_DNS_FILE}"
printf '\n'
fi
}

View File

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
# shellcheck source=../scripts/helpers/index.sh # shellcheck source=../scripts/helpers/index.sh
source /usr/local/bin/helpers/index.sh source /usr/local/bin/helpers/index.sh
@ -12,9 +12,17 @@ if [[ -f /etc/dms-settings ]] && [[ $(_get_dms_env_value 'ENABLE_RSPAMD') -eq 1
fi fi
fi fi
KEYSIZE=2048 function _main() {
SELECTOR=mail # Default parameters (updated by `_parse_arguments()`):
DOMAINS= local KEYSIZE=2048
local SELECTOR=mail
local DMS_DOMAINS=
_require_n_parameters_or_print_usage 0 "${@}"
_parse_arguments "${@}"
_generate_dkim_keys
}
function __usage() { function __usage() {
printf '%s' "${PURPLE}OPEN-DKIM${RED}(${YELLOW}8${RED}) printf '%s' "${PURPLE}OPEN-DKIM${RED}(${YELLOW}8${RED})
@ -57,20 +65,20 @@ ${ORANGE}EXAMPLES${RESET}
${ORANGE}EXIT STATUS${RESET} ${ORANGE}EXIT STATUS${RESET}
Exit status is 0 if command was successful. If wrong arguments are provided or arguments contain Exit status is 0 if command was successful. If wrong arguments are provided or arguments contain
errors, the script will exit early with exit status 2. errors, the script will exit early with a non-zero exit status.
" "
} }
_require_n_parameters_or_print_usage 0 "${@}" function _parse_arguments() {
# Parse the command args through iteration:
while [[ ${#} -gt 0 ]]; do while [[ ${#} -gt 0 ]]; do
case "${1}" in case "${1}" in
( 'keysize' ) ( 'keysize' )
if [[ -n ${2+set} ]]; then if [[ -n ${2+set} ]]; then
KEYSIZE="${2}" KEYSIZE="${2}"
shift _log 'debug' "Keysize set to '${KEYSIZE}'"
shift
else else
_exit_with_error "No keysize provided after 'keysize' argument" _exit_with_error "No keysize provided after 'keysize' argument"
fi fi
@ -78,10 +86,8 @@ while [[ ${#} -gt 0 ]]; do
( 'selector' ) ( 'selector' )
if [[ -n ${2+set} ]]; then if [[ -n ${2+set} ]]; then
# shellcheck disable=SC2034
SELECTOR="${2}" SELECTOR="${2}"
shift _log 'debug' "Selector set to '${SELECTOR}'"
shift
else else
_exit_with_error "No selector provided after 'selector' argument" _exit_with_error "No selector provided after 'selector' argument"
fi fi
@ -89,90 +95,140 @@ while [[ ${#} -gt 0 ]]; do
( 'domain' ) ( 'domain' )
if [[ -n ${2+set} ]]; then if [[ -n ${2+set} ]]; then
DOMAINS="${2}" DMS_DOMAINS="${2}"
shift _log 'debug' "Domain(s) set to '${DMS_DOMAINS}'"
shift
else else
_exit_with_error "No domain(s) provided after 'domain' argument" _exit_with_error "No domain(s) provided after 'domain' argument"
fi fi
;; ;;
( * ) ( 'help' )
__usage __usage
_exit_with_error "Unknown options '${1}' ${2:+and \'${2}\'}" exit 0
;; ;;
( * )
__usage
_exit_with_error "Unknown option(s) '${1}' ${2:+"and '${2}'"}"
;;
esac esac
done
# Discard these two args (option + value) now that they've been processed:
shift 2
done
}
function _generate_dkim_keys() {
_generate_domains_config
if [[ ! -s ${DATABASE_VHOST} ]]; then
_log 'warn' 'No entries found, no keys to make'
exit 0
fi
# Initialize OpenDKIM configs if necessary:
_create_opendkim_configs
# Generate a keypair per domain and add reference to OpenDKIM configs:
local ENTRY_KEY KEY_TABLE_ENTRY SIGNING_TABLE_ENTRY
while read -r DKIM_DOMAIN; do
_create_dkim_key "${DKIM_DOMAIN}"
# Create / Update OpenDKIM configs with new DKIM key:
ENTRY_KEY="${SELECTOR}._domainkey.${DKIM_DOMAIN}"
KEY_TABLE_ENTRY="${ENTRY_KEY} ${DKIM_DOMAIN}:${SELECTOR}:/etc/opendkim/keys/${DKIM_DOMAIN}/${SELECTOR}.private"
SIGNING_TABLE_ENTRY="*@${DKIM_DOMAIN} ${ENTRY_KEY}"
# If no existing entry, add one:
if ! grep -q "${KEY_TABLE_ENTRY}" "${KEY_TABLE_FILE}"; then
echo "${KEY_TABLE_ENTRY}" >> "${KEY_TABLE_FILE}"
fi
if ! grep -q "${SIGNING_TABLE_ENTRY}" "${SIGNING_TABLE_FILE}"; then
echo "${SIGNING_TABLE_ENTRY}" >> "${SIGNING_TABLE_FILE}"
fi
done < <(_get_valid_lines_from_file "${DATABASE_VHOST}")
# No longer needed, remove:
rm "${DATABASE_VHOST}"
# Ensure ownership is consistent for all content belonging to the base directory,
# During container startup, an internal copy will be made via `_setup_opendkim()`
# with ownership we expect, while this chown is for the benefit of the users ownership.
chown -R "$(stat -c '%U:%G' "${OPENDKIM_BASE_DIR}")" "${OPENDKIM_BASE_DIR}"
}
# Prepare a file with one domain per line (iterated via while loop as DKIM_DOMAIN):
# Depends on methods from `scripts/helpers/postfix.sh`:
DATABASE_VHOST='/tmp/vhost.dkim' DATABASE_VHOST='/tmp/vhost.dkim'
# Prepare a file with one domain per line:
function _generate_domains_config() { function _generate_domains_config() {
local TMP_VHOST='/tmp/vhost.dkim.tmp' local TMP_VHOST='/tmp/vhost.dkim.tmp'
# Generate the default vhost (equivalent to /etc/postfix/vhost), # Generate the default vhost (equivalent to /etc/postfix/vhost),
# unless CLI arg DOMAINS provided an alternative list to use instead: # unless CLI arg DMS_DOMAINS provided an alternative list to use instead:
if [[ -z ${DOMAINS} ]]; then if [[ -z ${DMS_DOMAINS} ]]; then
_obtain_hostname_and_domainname _obtain_hostname_and_domainname
# uses TMP_VHOST: # uses TMP_VHOST:
_vhost_collect_postfix_domains _vhost_collect_postfix_domains
else else
tr ',' '\n' <<< "${DOMAINS}" >"${TMP_VHOST}" tr ',' '\n' <<< "${DMS_DOMAINS}" >"${TMP_VHOST}"
fi fi
# uses DATABASE_VHOST + TMP_VHOST: # Uses DATABASE_VHOST + TMP_VHOST:
_create_vhost _create_vhost
} }
_generate_domains_config # `opendkim-genkey` generates two files at the configured `--directory`:
if [[ ! -s ${DATABASE_VHOST} ]]; then # - <selector>.private (Private key, PEM encoded)
_log 'warn' 'No entries found, no keys to make' # - <selector>.txt (Public key, formatted as a TXT record for a RFC 1035 DNS Zone file)
exit 0 function _create_dkim_key() {
fi DKIM_DOMAIN=${1?Expected to be provided a domain}
while read -r DKIM_DOMAIN; do OPENDKIM_DOMAINKEY_DIR="${OPENDKIM_BASE_DIR}/keys/${DKIM_DOMAIN}"
mkdir -p "/tmp/docker-mailserver/opendkim/keys/${DKIM_DOMAIN}" mkdir -p "${OPENDKIM_DOMAINKEY_DIR}"
if [[ ! -f "/tmp/docker-mailserver/opendkim/keys/${DKIM_DOMAIN}/${SELECTOR}.private" ]]; then DKIM_KEY_FILE="${OPENDKIM_DOMAINKEY_DIR}/${SELECTOR}.private"
_log 'info' "Creating DKIM private key '/tmp/docker-mailserver/opendkim/keys/${DKIM_DOMAIN}/${SELECTOR}.private'" if [[ ! -f "${DKIM_KEY_FILE}" ]]; then
_log 'info' "Creating DKIM private key '${DKIM_KEY_FILE}'"
# NOTE:
# --domain only affects a comment in the generated DNS Zone file
# --subdomains is the default,
# --nosubdomains would add `t=s` to the DNS TXT record generated
# http://www.opendkim.org/opendkim-genkey.8.html
opendkim-genkey \ opendkim-genkey \
--bits="${KEYSIZE}" \ --bits="${KEYSIZE}" \
--subdomains \ --subdomains \
--domain="${DKIM_DOMAIN}" \ --domain="${DKIM_DOMAIN}" \
--selector="${SELECTOR}" \ --selector="${SELECTOR}" \
--directory="/tmp/docker-mailserver/opendkim/keys/${DKIM_DOMAIN}" --directory="${OPENDKIM_DOMAINKEY_DIR}"
fi fi
}
# fix permissions to use the same user:group as /tmp/docker-mailserver/opendkim/keys OPENDKIM_BASE_DIR='/tmp/docker-mailserver/opendkim'
chown -R "$(stat -c '%U:%G' /tmp/docker-mailserver/opendkim/keys)" "/tmp/docker-mailserver/opendkim/keys/${DKIM_DOMAIN}" KEY_TABLE_FILE="${OPENDKIM_BASE_DIR}/KeyTable"
SIGNING_TABLE_FILE="${OPENDKIM_BASE_DIR}/SigningTable"
TRUSTED_HOSTS_FILE="${OPENDKIM_BASE_DIR}/TrustedHosts"
# Create configs if missing:
function _create_opendkim_configs() {
_log 'debug' 'Creating any missing OpenDKIM configs'
# write to KeyTable if necessary mkdir -p "${OPENDKIM_BASE_DIR}"
KEYTABLEENTRY="${SELECTOR}._domainkey.${DKIM_DOMAIN} ${DKIM_DOMAIN}:${SELECTOR}:/etc/opendkim/keys/${DKIM_DOMAIN}/${SELECTOR}.private" local OPENDKIM_CONFIGS=(
if [[ ! -f "/tmp/docker-mailserver/opendkim/KeyTable" ]]; then "${KEY_TABLE_FILE}"
_log 'debug' 'Creating DKIM KeyTable' "${SIGNING_TABLE_FILE}"
echo "${KEYTABLEENTRY}" >/tmp/docker-mailserver/opendkim/KeyTable "${TRUSTED_HOSTS_FILE}"
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 # Only create if the file doesn't exist (avoids modifying mtime):
SIGNINGTABLEENTRY="*@${DKIM_DOMAIN} ${SELECTOR}._domainkey.${DKIM_DOMAIN}" for FILE in ${OPENDKIM_CONFIGS[@]}; do
if [[ ! -f /tmp/docker-mailserver/opendkim/SigningTable ]]; then [[ ! -f "${FILE}" ]] && touch "${FILE}"
_log 'debug' 'Creating DKIM SigningTable' done
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 file exists but is empty, add default hosts to trust:
if [[ -d /tmp/docker-mailserver/opendkim ]] && [[ ! -f /tmp/docker-mailserver/opendkim/TrustedHosts ]]; then if [[ ! -s "${TRUSTED_HOSTS_FILE}" ]]; then
_log 'debug' 'Creating DKIM TrustedHosts' _log 'debug' 'Adding default trust to OpenDKIM TrustedHosts config'
echo "127.0.0.1" >/tmp/docker-mailserver/opendkim/TrustedHosts echo "127.0.0.1" > "${TRUSTED_HOSTS_FILE}"
echo "localhost" >>/tmp/docker-mailserver/opendkim/TrustedHosts echo "localhost" >> "${TRUSTED_HOSTS_FILE}"
fi fi
}
_main "${@}"

View File

@ -36,20 +36,41 @@ function _pre_installation_steps() {
apt-get "${QUIET}" install --no-install-recommends "${EARLY_PACKAGES[@]}" 2>/dev/null apt-get "${QUIET}" install --no-install-recommends "${EARLY_PACKAGES[@]}" 2>/dev/null
} }
# Install third-party commands to /usr/local/bin
function _install_utils() { function _install_utils() {
local ARCH_A=$(uname -m)
# Alternate naming convention support: x86_64 (amd64) / aarch64 (arm64)
# https://en.wikipedia.org/wiki/X86-64#Industry_naming_conventions
local ARCH_B
case "${ARCH_A}" in
( 'x86_64' ) ARCH_B='amd64' ;;
( 'aarch64' ) ARCH_B='arm64' ;;
esac
# TIP: `*.tar.gz` releases tend to forget to reset UID/GID ownership when archiving.
# When extracting with `tar` as `root` the archived UID/GID is kept, unless using `--no-same-owner`.
# Likewise when the binary is in a nested location the full archived path
# must be provided + `--strip-components` to extract the file to the target directory.
# Doing this avoids the need for (`mv` + `rm`) or (`--to-stdout` + `chmod +x`)
_log 'debug' 'Installing utils sourced from Github' _log 'debug' 'Installing utils sourced from Github'
_log 'trace' 'Installing jaq' _log 'trace' 'Installing jaq'
local JAQ_TAG='v2.1.0' local JAQ_TAG='v2.1.0'
curl -sSfL "https://github.com/01mf02/jaq/releases/download/${JAQ_TAG}/jaq-$(uname -m)-unknown-linux-gnu" -o /usr/bin/jaq curl -sSfL "https://github.com/01mf02/jaq/releases/download/${JAQ_TAG}/jaq-${ARCH_A}-unknown-linux-gnu" -o /usr/local/bin/jaq
chmod +x /usr/bin/jaq chmod +x /usr/local/bin/jaq
_log 'trace' 'Installing step'
local STEP_RELEASE='0.28.2'
curl -sSfL "https://github.com/smallstep/cli/releases/download/v${STEP_RELEASE}/step_linux_${STEP_RELEASE}_${ARCH_B}.tar.gz" \
| tar -xz --directory /usr/local/bin --no-same-owner --strip-components=2 "step_${STEP_RELEASE}/bin/step"
_log 'trace' 'Installing swaks' _log 'trace' 'Installing swaks'
# `perl-doc` is required for `swaks --help` to work:
apt-get "${QUIET}" install --no-install-recommends perl-doc apt-get "${QUIET}" install --no-install-recommends perl-doc
local SWAKS_VERSION='20240103.0' local SWAKS_VERSION='20240103.0'
local SWAKS_RELEASE="swaks-${SWAKS_VERSION}" local SWAKS_RELEASE="swaks-${SWAKS_VERSION}"
curl -sSfL "https://github.com/jetmore/swaks/releases/download/v${SWAKS_VERSION}/${SWAKS_RELEASE}.tar.gz" | tar -xz curl -sSfL "https://github.com/jetmore/swaks/releases/download/v${SWAKS_VERSION}/${SWAKS_RELEASE}.tar.gz" \
mv "${SWAKS_RELEASE}/swaks" /usr/local/bin | tar -xz --directory /usr/local/bin --no-same-owner --strip-components=1 "${SWAKS_RELEASE}/swaks"
rm -r "${SWAKS_RELEASE}"
} }
function _install_postfix() { function _install_postfix() {

View File

@ -1,5 +1,39 @@
#!/bin/bash #!/bin/bash
# Legacy service support for DKIM, DMARC, SPF
# TODO: Migrate this file into a common legacy feature dir
# Debian 12 package: opendkim 2.11.0
# https://salsa.debian.org/debian/opendkim
# Official project page (no HTTPS available):
# http://www.opendkim.org/
# Links to SourceForge for project source which directs users to Github:
# Last commit Dec 2022:
# https://github.com/trusteddomainproject/OpenDKIM/tree/develop
# Last release 2.11.0 (Nov 2018):
# https://github.com/trusteddomainproject/OpenDKIM/releases
# Debian 12 package: opendmarc 1.4.2
# https://salsa.debian.org/kitterman/opendmarc
# Official project page (no HTTPS available):
# http://www.trusteddomain.org/opendmarc/
# Links to SourceForge for project source which directs users to Github (since April 2021):
# Last commit Dec 2021:
# https://github.com/trusteddomainproject/OpenDMARC/branches/all
# Last release 1.4.2 (Dec 2021):
# https://github.com/trusteddomainproject/OpenDMARC/blob/master/RELEASE_NOTES
# Debian 12 package: postfix-policyd-spf-python 3.0.4 (April 2023)
# https://salsa.debian.org/python-team/packages/spf-engine
# Previously `policyd-spf` until Dec 2016, then renamed to `spf-engine`:
# https://launchpad.net/pypolicyd-spf
# https://salsa.debian.org/kitterman/postfix-policyd-spf-perl
# Official project page + repo:
# https://code.launchpad.net/spf-engine
# Last commit and release 3.1.0 (Aug 2024):
# https://git.launchpad.net/spf-engine/
# Set up OpenDKIM # Set up OpenDKIM
# #
# ## Attention # ## Attention
@ -23,7 +57,11 @@ function _setup_opendkim() {
# check if any keys are available # check if any keys are available
if [[ -e /tmp/docker-mailserver/opendkim/KeyTable ]]; then if [[ -e /tmp/docker-mailserver/opendkim/KeyTable ]]; then
cp -a /tmp/docker-mailserver/opendkim/* /etc/opendkim/ cp -a /tmp/docker-mailserver/opendkim/* /etc/opendkim/
_log 'trace' "DKIM keys added for: $(find /etc/opendkim/keys/ -maxdepth 1 -type f -printf '%f ')"
local DKIM_DOMAINS
DKIM_DOMAINS=$(find /etc/opendkim/keys/ -maxdepth 1 -type f -printf '%f ')
_log 'trace' "DKIM keys added for: ${DKIM_DOMAINS}"
chown -R opendkim:opendkim /etc/opendkim/ chown -R opendkim:opendkim /etc/opendkim/
chmod -R 0700 /etc/opendkim/keys/ chmod -R 0700 /etc/opendkim/keys/
else else

View File

@ -1,5 +1,41 @@
#!/bin/bash #!/bin/bash
# Legacy service support with Postgrey, SpamAssassin, Amavis
# TODO: Migrate these services into a common legacy feature dir
# Debian 12 package: postgrey 1.37
# https://salsa.debian.org/debian/postgrey
# Official project page:
# https://postgrey.schweikert.ch/
# Last commit Feb 2024 (mostly whitelist updates since 2016):
# https://github.com/schweikert/postgrey
# Last release 1.37 (Sep 2016):
# https://github.com/schweikert/postgrey/tags
# Debian 12 package: spamassassin 4.0.0 (Dec 2022)
# Lack of 4.0.1 potentially causing regression/bugs in DMS v14+
# https://salsa.debian.org/debian/spamassassin
# Official project page:
# https://spamassassin.apache.org/
# NOTE: Github repo is a mirror (antiquated process for contributions/reports)
# Last commit Feb 2025:
# https://github.com/apache/spamassassin
# Last release 4.0.1 (March 2024):
# https://github.com/apache/spamassassin/tags
# Debian 12 package: amavisd-new 2.13.0 (Jan 2023)
# https://salsa.debian.org/debian/amavisd-new
# Official project page:
# https://www.ijs.si/software/amavisd/
# https://www.amavis.org/
# Last announced release 2.11.0 (2016) + 2.11.1 (Oct 2018):
# https://www.ijs.si/software/amavisd/release-notes.txt
# Development migrated to Gitlab with release 2.12.0 (July 2019)
# Last commit Feb 2025:
# https://gitlab.com/amavis/amavis
# Last release 2.13.1 (March 2024):
# https://gitlab.com/amavis/amavis/-/tags
function _setup_security_stack() { function _setup_security_stack() {
_log 'debug' 'Setting up Security Stack' _log 'debug' 'Setting up Security Stack'