Files
SODEW/sodew-bash-main/libs/commands/postfix.sh
T
2026-08-18 09:40:08 +02:00

277 lines
9.1 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() {
printSection "Initialization..."
touch "$postfixConfigPath/$postfixDomainsFile" || return 1
touch "$postfixConfigPath/$postfixAliasesFile" || return 1
touch "$postfixConfigPath/$postfixSendersFile" || return 1
postfixDkimAdd "$postfixHost" || {
printDotText "Add DKIM for host" "$labelFail"
return 1
}
printDotText "Add DKIM for host" "$labelDone"
local error
if ! runError error postfixExec chown postfix:postfix /config/sasldb2; then
printDotText "Set owner /config/sasldb2" "$labelFail"
printDanger "$error"
return 1
fi
printDotText "Set owner /config/sasldb2" "$labelDone"
}
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
cmdPostfixInit || return 1
}
# Uninstalls Postfix Kubernetes resources.
function cmdPostfixUninstall() {
"$k3sCmd" kubectl delete -f "$postfixYaml"
}
function cmdPostfixUser() {
local output error
printRow
if ! run output error postfixUserList; then
printDanger "$error"
elif [[ -z "$output" ]]; then
printText "$labelNull"
else
printText "$output"
fi
}
# 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
local ready reason
while IFS='|' read -r pod ready phase reason; do
printSection "$pod"
if [[ "$ready" != "1" ]]; then
printDotText "Status" "$fontGray$reason $fontRed$phase$fontReset"
else
printDotText "Status" "$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
}
# Checks MTA host DNS records (A, SPF, PTR, DKIM) against configured values.
function cmdPostfixMtaDnsCheck() {
local label output error text
printSection "MTA DNS: $postfixHost"
# A record
if ! run output error dig +short A "$postfixHost" "$dnsResolver"; then
printDotText "A record" "$fontRed${output:-$error}$fontReset"
else
text=$(printf '%s' "$output" | paste -sd, - | sed 's/,/ \/ /g')
if grep -Fxq -- "$postfixIp" <<<"$output"; then
printDotText "A record" "$fontGreen$text$fontReset"
else
printDotText "A record" "$fontYellow$text$fontReset"
fi
fi
# SPF record
if ! run output error dig +short TXT "$postfixHost" "$dnsResolver"; then
printDotText "SPF record" "$fontRed${output:-$error}$fontReset"
elif grep -Eq '^"?v=spf1([[:space:]]|")' <<<"$output"; then
printDotText "SPF record" "$fontGreen$output$fontReset"
else
printDotText "SPF record" "$fontRed$output$fontReset"
fi
# PTR record
if ! run output error dig -x "$postfixIp" +short "$dnsResolver"; then
printDotText "PTR record" "$fontRed${output:-$error}$fontReset"
else
text=$(printf '%s' "$output" | paste -sd, - | sed 's/,/ \/ /g')
if grep -Fxq -- "$postfixHost." <<<"$output"; then
printDotText "PTR record" "$fontGreen$text$fontReset"
else
printDotText "PTR record" "$fontYellow$text$fontReset"
fi
fi
# DKIM record
if ! run output error dig +short TXT "$postfixDkimSelector._domainkey.$postfixHost"; then
printDotText "DKIM record" "$fontRed${output:-$error}$fontReset"
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
printText "$fontGreen$dkimDnsNorm$fontReset"
else
printText "DNS : $fontYellow$dkimDnsNorm$fontReset"
printText "File: $fontYellow$dkimFileNorm$fontReset"
fi
fi
}