Files
SODEW/sodew-bash-main/libs/commands/postfix.sh
T
2026-08-12 10:59:38 +02:00

304 lines
9.8 KiB
Bash

postfixLabel="[Postfix]"
# Generates a self-signed TLS certificate for Postfix if one does not already exist.
function cmdPostfixPreparation() {
printSection "Preparation..."
if [[ ! -f "$postfixTlsCrtFile" || ! -f "$postfixTlsKeyFile" ]]; then
local crtPath; crtPath=$(dirname "$postfixTlsCrtFile")
local tlsCnfFile="$crtPath/openssl.cnf"
local cn="${postfixHost:-$postfixDomain}"
local sanList="DNS:${cn}"
[[ -n "$postfixDomain" ]] && sanList="${sanList},DNS:${postfixDomain}"
mkdir -p "$crtPath" || {
printDotText "preparation" "$labelFail"
printDanger "Failed to create folder for certificate";
return 1;
}
cat >"$tlsCnfFile" <<EOF
[req]
distinguished_name = dn
x509_extensions = v3_req
prompt = no
[dn]
CN = ${cn}
[v3_req]
subjectAltName = ${sanList}
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
EOF
openssl req -x509 -nodes -newkey rsa:2048 -days 365 -keyout "$postfixTlsKeyFile" -out "$postfixTlsCrtFile" -config "$tlsCnfFile" || {
printDotText "preparation" "$labelFail"
printDanger "TLS gen failed";
return 1;
}
fi
printDotText "preparation" "$labelDone"
}
# Renders the Postfix Kubernetes YAML manifest via Helm.
function cmdPostfixYamlRender() {
local templateFile="templates/$postfixKube.yaml"
printSection "Render YAML file | Helm"
printDotText "Template" "$appAssetsPath/k3s/$templateFile"
[[ -f "$appAssetsPath/k3s/$templateFile" ]] || {
printDanger "Template file not found"
return 1
}
local val postfixTlsCrtB64 postfixTlsKeyB64
val=$(base64 -w0 "$postfixTlsCrtFile") || {
printDotText "render" "$labelFail"
printDanger "Base64 gen failed (1)"
return 1
}
postfixTlsCrtB64=$(sed 's/[&\\]/\\&/g' <<<"$val") || {
printDotText "render" "$labelFail"
printDanger "Base64 gen failed (2)"
return 1
}
val=$(base64 -w0 "$postfixTlsKeyFile") || {
printDotText "render" "$labelFail"
printDanger "Base64 gen failed (3)"
return 1
}
postfixTlsKeyB64=$(sed 's/[&\\]/\\&/g' <<<"$val") || {
printDotText "render" "$labelFail"
printDanger "Base64 gen failed (4)"
return 1
}
local varsFile
varsFile=$(mktemp "/tmp/$postfixKube.vars.XXXXXX.yaml") || {
printDotText "render" "$labelFail"
printDanger "Create temp variables file"
return 1
}
printDotText "Variables" "$varsFile"
trap 'rm -f -- "$varsFile"' RETURN
cat > "$varsFile" <<EOF
postfixHelm: true
namespace: $k3sNamespace
postfix: $postfixKube
postfixPath: $postfixPath
postfixTlsCrtB64: $postfixTlsCrtB64
postfixTlsKeyB64: $postfixTlsKeyB64
postfixHost: $postfixHost
postfixPostmaster: $postfixPostmaster
postfixDefaultRealm: $postfixDefaultRealm
postfixConfigPath: $postfixConfigPath
postfixDkimPath: $postfixDkimPath
postfixDkimSelector: $postfixDkimSelector
postfixDomainsFile: $postfixDomainsFile
postfixAliasesFile: $postfixAliasesFile
postfixSendersFile: $postfixSendersFile
EOF
printDotText "Result" "$postfixYaml"
mkdir -p -- "$(dirname -- "$postfixYaml")" || return 1
fileBackup "$postfixYaml"
helm template stack "$appAssetsPath/k3s" -f "$varsFile" --show-only "$templateFile" > "$postfixYaml" || {
printDotText "render" "$labelFail"
printDanger "Render failed"
return 1
}
printDotText "render" "$labelDone"
}
# Initializes Postfix after install: generates DKIM for postfixHost and sets sasldb2 ownership.
function cmdPostfixInit() {
postfixDkimAdd "$postfixHost" || return 1
local error
if ! runError error postfixExec chown postfix:postfix /config/sasldb2; then
printDanger "$postfixLabel | $error"
fi
}
function cmdPostfixUpdate() {
cmdPostfixYamlRender || return 1
cmdK3sYamlApplyEx "$postfixYaml" || return 1
}
# Installs Postfix into Kubernetes.
function cmdPostfixInstall() {
cmdPostfixPreparation || return 1
cmdPostfixYamlRender || return 1
cmdK3sYamlApplyEx "$postfixYaml" || return 1
}
# Uninstalls Postfix Kubernetes resources.
function cmdPostfixUninstall() {
"$k3sCmd" kubectl delete -f "$postfixYaml"
}
# Prints the Postfix mail version.
function cmdPostfixInfo() {
local output error podList ver pid
if ! run podList error k3sPodListStatus "$postfixKube"; then
printDanger "Get pods: $error"
elif [[ -z "$podList" ]]; then
printDanger "Pods not found"
else
while IFS='|' read -r pod phase; do
printSection "$pod"
if [[ "$phase" != "Running" ]]; then
printDotText "Phase" "$fontRed$phase$fontReset"
else
printDotText "Phase" "$fontGreen$phase$fontReset"
if ! run output error postfixPodExec "$pod" postfix status; then
printDotText "Postfix status" "$fontRed$labelFail$fontReset"
printDanger "$error"
else
output="${output:-$error}"
if [[ $output == *"is running"* ]]; then
pid=${output##*PID: }
pid=${pid%%[^0-9]*}
printDotText "Postfix status" "$labelRunning"
printDotText "pid" "$pid"
else
printDotText "Postfix status" "$fontRed$output$fontReset"
fi
fi
if ! run output error postfixPodExec "$pod" postconf mail_version; then
printDotText "Postfix mail version" "$fontRed$labelFail$fontReset"
printDanger "$error"
else
ver=$(printf '%s' "$output" | cut -d '=' -f2 | tr -d '\r\n')
printDotText "Postfix mail version" "$ver"
fi
fi
done < <(awk 'NF' <<< "$podList")
fi
printRow
}
# Sets a virtual alias forward-to address for a domain and saves it to site config.
# $1 (domain): site domain name.
# $2 (mail): forward-to email address.
function cmdPostfixVirtualAliasSetEx() {
local domain="$1"
[[ -n "$domain" ]] || { printDanger "$postfixLabel Domain not specified"; return 1; }
local mail="$2"
[[ -n "$mail" ]] || { printDanger "$postfixLabel Mail not specified"; return 1; }
local domainList output error
if ! run domainList error postfixDomainList; then
printDanger "$postfixLabel postfixDomainList: $error"
return 1
elif ! listContains "$domain" "$domainList"; then
printDanger "$postfixLabel Domain not found in postfixDomainList"
return 1
elif ! run output error siteConfigSet "$domain" "postfixForwardTo" "$mail"; then
printDanger "$postfixLabel siteConfigSet: $error"
elif ! run output error postfixVirtualAliasSet "@$domain" "$mail"; then
printDanger "$postfixLabel postfixVirtualAliasSet: $error"
fi
}
# Checks MTA host DNS records (A, SPF, PTR, DKIM) against configured values.
function cmdPostfixMtaDnsCheck() {
local label output error text
label="$postfixLabel A record: $postfixHost"
if ! run output error dig +short A "$postfixHost" "$postfixResolver"; then
printDanger "$label"
else
text=$(printf '%s' "$output" | paste -sd, - | sed 's/,/ \/ /g')
if grep -Fxq -- "$postfixIp" <<<"$output"; then
printSuccess "$label | $text"
else
printWarning "$label | $text"
fi
fi
label="$postfixLabel SPF record: $postfixHost"
if ! run output error dig +short TXT "$postfixHost" "$postfixResolver"; then
printDanger "$label"
elif grep -Eq '^"?v=spf1([[:space:]]|")' <<<"$output"; then
printSuccess "$label | $output"
else
printWarning "$label | $output"
fi
label="$postfixLabel PTR record: $postfixHost"
if ! run output error dig -x "$postfixIp" +short "$postfixResolver"; then
printDanger "$label"
else
text=$(printf '%s' "$output" | paste -sd, - | sed 's/,/ \/ /g')
if grep -Fxq -- "$postfixHost." <<<"$output"; then
printSuccess "$label | $text"
else
printWarning "$label | $text"
fi
fi
label="$postfixLabel DKIM record: $postfixHost"
if ! run output error dig +short TXT "$postfixDkimSelector._domainkey.$postfixHost"; then
printDanger "$label | $error"
else
local dkimDnsNorm dkimFileRaw dkimFileNorm
dkimDnsNorm=$(
printf '%s\n' "$output" |
tr -d '\n' |
sed -e 's/"//g' -e 's/[[:space:]]//g' |
sed -n 's/.*p=\([^;]*\).*/\1/p'
)
dkimFileRaw=$(postfixDkimGet "$postfixHost")
dkimFileNorm=$(
printf '%s\n' "$dkimFileRaw" |
tr -d '\n' |
sed -e 's/[()"]//g' -e 's/[[:space:]]//g' |
sed -n 's/.*p=\([^;]*\).*/\1/p'
)
if [[ "$dkimDnsNorm" == "$dkimFileNorm" ]]; then
printSuccess "$label | OK"
else
printWarning "$label | DNS : $dkimDnsNorm"
printWarning "$label | FILE: $dkimFileNorm"
fi
fi
}
# Prints domain/alias/sender/SASL lists; accepts domain/alias/senders/sasl as filter.
# [$1] (filter): domain|alias|senders|sasl; omit to print all.
function cmdPostfixList() {
case "$1" in
'domain')
postfixDomainList
;;
'alias')
postfixAliasList
;;
'senders')
postfixSendersList
;;
'sasl')
postfixSaslUserList
;;
*)
printInfo "$postfixLabel Domains"
postfixDomainList
printInfo "$postfixLabel Aliases"
postfixAliasList
printInfo "$postfixLabel Senders"
postfixSendersList
printInfo "$postfixLabel SASL users"
postfixSaslUserList
;;
esac
}