- Add Python script to extract certificates from Traefik acme.json - Mount extracted certs to /etc/ssl in container for TLS support - Enable smtpd_tls_security_level: may for incoming STARTTLS - Remove failed_when: false on cert extraction to catch failures early - Fix relayhost username to default to password (Postmark server token auth) - Change default Postmark port from 2525 to 587 (blocked on some networks) - Create SSL directory before extraction Fixes: SMTP authentication failures and enables TLS for Authelia password reset
90 lines
3.6 KiB
YAML
90 lines
3.6 KiB
YAML
---
|
|
|
|
- name: Configure Postfix (send-only)
|
|
block:
|
|
- name: Read Postfix relay host
|
|
set_fact:
|
|
postfix_relayhost: "{{ POSTFIX_RELAYHOST | default(lookup('env', 'POSTFIX_RELAYHOST') | default('smtp.postmarkapp.com', true), true) }}"
|
|
postfix_relayhost_port: "{{ POSTFIX_RELAYHOST_PORT | default(lookup('env', 'POSTFIX_RELAYHOST_PORT') | default('587', true), true) }}"
|
|
no_log: true
|
|
|
|
- name: Read Postfix relay host password
|
|
set_fact:
|
|
postfix_relayhost_password: "{{ POSTFIX_RELAYHOST_PASSWORD | default(lookup('env', 'POSTFIX_RELAYHOST_PASSWORD') | default('', true), true) }}"
|
|
no_log: true
|
|
|
|
- name: Read Postfix relay host username
|
|
set_fact:
|
|
postfix_relayhost_username: "{{ POSTFIX_RELAYHOST_USERNAME | default(lookup('env', 'POSTFIX_RELAYHOST_USERNAME') | default(postfix_relayhost_password, true), true) }}"
|
|
no_log: true
|
|
|
|
- name: Fail if Postfix relay host username/password pairing is invalid
|
|
fail:
|
|
msg: "POSTFIX_RELAYHOST_USERNAME and POSTFIX_RELAYHOST_PASSWORD must both be set, or both be empty"
|
|
when: (postfix_relayhost_username | length == 0) != (postfix_relayhost_password | length == 0)
|
|
|
|
- name: Read Postfix allowed sender domains
|
|
set_fact:
|
|
postfix_allowed_sender_domains: "{{ POSTFIX_ALLOWED_SENDER_DOMAINS | default(lookup('env', 'POSTFIX_ALLOWED_SENDER_DOMAINS') | default('', true), true) }}"
|
|
no_log: true
|
|
|
|
- name: Read Postfix allow empty sender domains
|
|
set_fact:
|
|
postfix_allow_empty_sender_domains: "{{ (POSTFIX_ALLOW_EMPTY_SENDER_DOMAINS | default(lookup('env', 'POSTFIX_ALLOW_EMPTY_SENDER_DOMAINS') | default('true', true), true)) | bool }}"
|
|
no_log: true
|
|
|
|
- name: Read Postfix SMTP TLS security level
|
|
set_fact:
|
|
postfix_smtp_tls_security_level: "{{ POSTFIX_SMTP_TLS_SECURITY_LEVEL | default(lookup('env', 'POSTFIX_SMTP_TLS_SECURITY_LEVEL') | default('may', true), true) }}"
|
|
no_log: true
|
|
|
|
- name: Create Postfix directory
|
|
file:
|
|
path: /opt/postfix
|
|
state: directory
|
|
|
|
- name: Create Postfix SSL directory
|
|
file:
|
|
path: /opt/postfix/ssl
|
|
state: directory
|
|
|
|
- name: Extract certificate from Traefik acme.json
|
|
shell: |
|
|
set -euo pipefail
|
|
ACME_FILE="/opt/traefik/letsencrypt/acme.json"
|
|
DEST_DIR="/opt/postfix/ssl"
|
|
DOMAIN="{{ auth_hostname }}"
|
|
|
|
if [ -f "$ACME_FILE" ]; then
|
|
python3 << 'PYEOF'
|
|
import json, base64, sys
|
|
with open("/opt/traefik/letsencrypt/acme.json") as f:
|
|
data = json.load(f)
|
|
for resolver in data.values():
|
|
if "Certificates" in resolver:
|
|
for cert in resolver["Certificates"]:
|
|
if cert.get("domain", {}).get("main") == "{{ auth_hostname }}":
|
|
with open("/opt/postfix/ssl/tls.crt", "wb") as f:
|
|
f.write(base64.b64decode(cert["certificate"]))
|
|
with open("/opt/postfix/ssl/tls.key", "wb") as f:
|
|
f.write(base64.b64decode(cert["key"]))
|
|
print("Certificates extracted successfully")
|
|
sys.exit(0)
|
|
print("Domain not found in acme.json")
|
|
sys.exit(1)
|
|
PYEOF
|
|
chmod 644 "$DEST_DIR/tls.crt"
|
|
chmod 600 "$DEST_DIR/tls.key"
|
|
fi
|
|
args:
|
|
executable: /bin/bash
|
|
|
|
- name: Copy Docker Compose file for Postfix
|
|
template:
|
|
src: docker-compose.yml.j2
|
|
dest: /opt/postfix/docker-compose.yml
|
|
|
|
- name: Deploy Postfix
|
|
command: docker compose up -d
|
|
args:
|
|
chdir: /opt/postfix
|