forked from arugifa/simplelogin-postfix-docker
-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathgenerate_config.py
executable file
·148 lines (113 loc) · 5.54 KB
/
generate_config.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/env python3
"""Generate configuration files for SimpleLogin Postfix and Certbot.
Greatly inspired by:
https://aoeex.com/phile/postfix-dovecot-and-lets-encrypt-certificates/
"""
import os
import re
import sys
from os import environ
from pathlib import Path
from jinja2 import Environment, FileSystemLoader, StrictUndefined
from jinja2.exceptions import UndefinedError
# Certbot
CERTBOT_CONFIG_DIR = Path('/etc/letsencrypt')
CERTBOT_CONFIG_FILENAME = 'cli.ini'
# Let's Encrypt
LETSENCRYPT_CONFIG_DIR = CERTBOT_CONFIG_DIR / 'live'
LETSENCRYPT_CERTIFICATE = 'fullchain.pem'
LETSENCRYPT_PRIVATE_KEY = 'privkey.pem'
# Postfix
POSTFIX_CONFIG_DIR = Path('/etc/postfix')
POSTFIX_CONFIG_FILENAMES = ['main.cf', 'pgsql-relay-domains.cf', 'pgsql-transport-maps.cf', 'dnsbl-reply-map'] # noqa: E501
# Templates
TEMPLATES_DIR = Path('/src/templates')
templates = Environment(
loader=FileSystemLoader(TEMPLATES_DIR),
undefined=StrictUndefined,
trim_blocks=True, # To not show empty lines in place of block statements
)
def generate_certbot_config():
"""Generate Certbot's configuration file."""
with (CERTBOT_CONFIG_DIR / CERTBOT_CONFIG_FILENAME).open('w') as f:
template = templates.get_template(f'certbot/{CERTBOT_CONFIG_FILENAME}')
f.write(template.render(env=environ))
def generate_postfix_config():
"""Generate Postfix's configuration files."""
for filename in POSTFIX_CONFIG_FILENAMES:
# If DQN KEY is provided
if filename == 'dnsbl-reply-map' and environ.get('POSTFIX_DQN_KEY') is None:
# skip generation of mapping file - not needed.
continue
filepath = POSTFIX_CONFIG_DIR / filename
print(f"Generating Postfix configuration file: {filepath}")
with (filepath).open('w') as config_file:
template = templates.get_template(f'postfix/{filename}')
cert_file = None
key_file = None
# Use custom certificate if provided or use Let's Encrypt certificate.
if environ.get('TLS_KEY_FILE') is not None and environ.get('TLS_CERT_FILE') is not None:
cert_file = Path(environ.get('TLS_CERT_FILE'))
key_file = Path(environ.get('TLS_KEY_FILE'))
print(f"|Using custom certificate:")
print(f"| with key file: {key_file}")
print(f"| with certificate file: {cert_file}")
else:
print("|Using Let's Encrypt certificate")
ssl_cert_folder = environ.get('POSTFIX_FQDN')
cert_file = LETSENCRYPT_CONFIG_DIR / ssl_cert_folder / LETSENCRYPT_CERTIFICATE
key_file = LETSENCRYPT_CONFIG_DIR / ssl_cert_folder / LETSENCRYPT_PRIVATE_KEY
# Check if certificate and key files exist.
enable_tls = cert_file.is_file() and key_file.is_file()
if not enable_tls:
print(f"|Certificate files are missing: {cert_file} and {key_file}")
else:
print("|Certificate files are present")
# Existing checks for creds didn't seem to work using {% if 'RELAY_HOST_USERNAME' in env and 'RELAY_HOST_PASSWORD' in env %}
# Generated main.cf didn't contain smtp_sasl_auth_enable = yes
# Following three tests address RELAY config settings
# Set up Relay Creds
relay_creds_flag = (environ.get('RELAY_HOST_USERNAME') is not None and environ.get('RELAY_HOST_PASSWORD') is not None)
# Set up Relay Host and Port
relay_host_port_flag = (environ.get('RELAY_HOST') is not None and environ.get('RELAY_PORT') is not None)
# Set up Relay Host Only
relay_host_only_flag = (environ.get('RELAY_HOST') is not None and environ.get('RELAY_HOST_PASSWORD') is None)
# Set up Use DQN
use_dqn_flag = environ.get('POSTFIX_DQN_KEY') is not None
# Enable Proxy Protocal if postfix is behind a reverse proxy that can use Proxy Protocol like trafik or haproxy.
enable_proxy_protocol = os.getenv("ENABLE_PROXY_PROTOCOL", 'False').lower() in ('true', '1', 't')
if enable_proxy_protocol:
print(f"|Proxy Protocol is enabled.")
else:
print(f"|Proxy Protocol is disabled.")
# Set up mynetworks
use_mynetworks_flag = (environ.get('MYNETWORKS') is not None)
# Generate config_file file.
config_file.write(template.render(
env=environ,
tls=enable_tls,
tls_cert=cert_file,
tls_key=key_file,
proxy_protocol=enable_proxy_protocol,
relay_creds=relay_creds_flag,
relay_host_only=relay_host_only_flag,
relay_host_port=relay_host_port_flag,
use_dqn=use_dqn_flag,
use_mynetworks=use_mynetworks_flag,
))
def main():
"""Generate Certbot and/or Postfix's configuration files."""
try:
if '--certbot' in sys.argv or len(sys.argv) == 1:
generate_certbot_config()
if '--postfix' in sys.argv or len(sys.argv) == 1:
generate_postfix_config()
except (KeyError, UndefinedError) as exc:
if isinstance(exc, KeyError):
missing = exc.args[0]
else:
missing = re.match(r"'.+' .+ '(.+)'", exc.message)[1]
print("Impossible to generate Postfix configuration files")
sys.exit(f"You forgot to define the following environment variable: {missing}")
if __name__ == '__main__':
main()