-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpostfix.sh
More file actions
executable file
·368 lines (314 loc) · 11 KB
/
postfix.sh
File metadata and controls
executable file
·368 lines (314 loc) · 11 KB
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
#!/bin/bash
unwanted_ciphers='CBC'
default_cipherlist=`openssl ciphers 'HIGH:MEDIUM:!LOW:!ADH:!SSLv2:!EXP:!aNULL:!NULL:!CAMELLIA:!RC4:!MD5:!SEED:!3DES' \
| sed -e 's/:/\n/g' \
| grep -Ev "$unwanted_ciphers" \
| sed -e ':a;N;$!ba;s/\n/:/g'`
# Set Postfix configuration from environment.
myhostname=${myhostname:-docker.example.com}
smtpd_helo_restrictions=${smtpd_helo_restrictions:-permit_sasl_authenticated, permit_mynetworks}
smtpd_recipient_restrictions=${smtpd_recipient_restrictions:-reject_unknown_sender_domain, reject_unknown_recipient_domain, reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, reject_invalid_hostname, reject_non_fqdn_sender}
smtpd_tls_security_level=${smtpd_tls_security_level:-may}
smtp_tls_security_level=${smtp_tls_security_level:-may}
smtpd_tls_ciphers=${smtpd_tls_ciphers:-high}
smtp_tls_ciphers=${smtp_tls_ciphers:-high}
tls_high_cipherlist=${tls_high_cipherlist:-$default_cipherlist}
tls_preempt_cipherlist=${tls_preempt_cipherlist:-yes}
smtpd_tls_mandatory_protocols=${smtpd_tls_mandatory_protocols:-'!SSLv2,!SSLv3'}
smtpd_tls_protocols=${smtpd_tls_protocols:-'!SSLv2,!SSLv3'}
smtpd_tls_eecdh_grade=${smtpd_tls_eecdh_grade:-ultra}
smtp_tls_mandatory_protocols=${smtp_tls_mandatory_protocols:-'!SSLv2,!SSLv3'}
smtp_tls_protocols=${smtp_tls_protocols:-'!SSLv2,!SSLv3'}
# Set Dovecot configuration from environment
dovecot_ssl_protocols=${dovecot_ssl_protocols:-'!SSLv2 !SSLv3'}
dovecot_ssl_cipher_list=${dovecot_ssl_cipher_list:-$default_cipherlist}
dovecot_verbose_ssl=${dovecot_verbose_ssl:-no}
dovecot_mail_plugins=${dovecot_mail_plugins:-'$mail_plugins quota'}
dovecot_mail_debug=${dovecot_mail_debug:-no}
dovecot_auth_debug=${dovecot_auth_debug:-no}
# Export environment variables for cron use
cat > /postfix_env << EOF
myhostname=$myhostname
EOF
if [ -z ${tls_cert_file+x} ]; then
tls_cert_file="/etc/ssl/private/$myhostname.pem"
fi
if [ -z ${tls_key_file+x} ]; then
tls_key_file="/etc/ssl/private/$myhostname.key"
fi
if [ -z ${dhparam_file+x} ]; then
dhparam_file="/etc/ssl/private/dhparam.pem"
fi
postconf -e "myhostname = $myhostname"
postconf -e "smtpd_helo_restrictions = $smtpd_helo_restrictions"
postconf -e "smtpd_recipient_restrictions = $smtpd_recipient_restrictions"
postconf -e "smtpd_tls_cert_file = $tls_cert_file"
postconf -e "smtpd_tls_key_file = $tls_key_file"
postconf -e "smtpd_tls_security_level = $smtpd_tls_security_level"
postconf -e "smtp_tls_security_level = $smtp_tls_security_level"
postconf -e "smtpd_tls_ciphers = $smtpd_tls_ciphers"
postconf -e "smtp_tls_ciphers = $smtp_tls_ciphers"
postconf -e "tls_high_cipherlist = $tls_high_cipherlist"
postconf -e "tls_preempt_cipherlist = $tls_preempt_cipherlist"
postconf -e "smtpd_tls_mandatory_protocols = $smtpd_tls_mandatory_protocols"
postconf -e "smtpd_tls_protocols = $smtpd_tls_protocols"
postconf -e "smtpd_tls_dh1024_param_file = $dhparam_file"
postconf -e "smtpd_tls_eecdh_grade = $smtpd_tls_eecdh_grade"
postconf -e "smtp_tls_mandatory_protocols = $smtp_tls_mandatory_protocols"
postconf -e "smtp_tls_protocols = $smtp_tls_protocols"
# setup self-signed SSL certificate if no certificate exists
if [ ! -f "$tls_key_file" ]; then
echo "No SSL certificate found for $myhostname. Creating a self-signed one."
openssl req \
-nodes \
-x509 \
-newkey rsa:4096 \
-keyout "$tls_key_file" \
-out "$tls_cert_file" \
-subj "/C=PH/ST=NCR/L=NCR/O=$myhostname/OU=$myhostname/CN=$myhostname" && \
chown root:root $tls_cert_file $tls_key_file && \
chmod 400 $tls_cert_file $tls_key_file
fi
# create DH Param file if none is available
if [ ! -f "$dhparam_file" ]; then
echo "No DH param file found. Creating a new one: $dhparam_file"
openssl dhparam -out "$dhparam_file" 2048
fi
# alias map config
db_host=${db_host:-postfix-db}
db_user=${db_user:-root}
db_password=${db_password:-password}
db_name=${db_name:-postfix}
cat > /etc/postfix/mysql-virtual-mailbox-domains.cf << EOF
user = $db_user
password = $db_password
dbname = $db_name
hosts = $db_host
query = SELECT name FROM postfix_domain WHERE name='%s' AND active=true
EOF
cat > /etc/postfix/mysql-virtual-mailbox-maps.cf << EOF
user = $db_user
password = $db_password
dbname = $db_name
hosts = $db_host
query = SELECT e.email FROM (SELECT concat(eu.username, '@', d.name) as email FROM postfix_emailuser eu, postfix_domain d WHERE d.id=eu.domain_id AND eu.active=true AND d.active=true) e WHERE e.email='%s'
EOF
cat > /etc/postfix/mysql-virtual-alias-maps.cf << EOF
user = $db_user
password = $db_password
dbname = $db_name
hosts = $db_host
query = SELECT destination FROM postfix_alias WHERE source='%s' AND active=true
EOF
# dovecot config
cat > /etc/dovecot/conf.d/99-mail-stack-delivery.conf << EOF
# Some general options
protocols = imap sieve
ssl = yes
verbose_ssl = $dovecot_verbose_ssl
ssl_cert = <$tls_cert_file
ssl_key = <$tls_key_file
ssl_client_ca_dir = /etc/ssl/certs
ssl_prefer_server_ciphers = yes
ssl_dh_parameters_length = 2048
ssl_protocols = $dovecot_ssl_protocols
ssl_cipher_list = $dovecot_ssl_cipher_list
mail_home = /var/mail/vmail/%d/%n
mail_uid = 5000
mail_gid = 5000
mail_location = maildir:/var/mail/vmail/%d/%n/mail:LAYOUT=fs
mail_plugins = $dovecot_mail_plugins
mail_debug = $dovecot_mail_debug
auth_debug = $dovecot_auth_debug
auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@
# IMAP configuration
protocol imap {
mail_plugins = \$mail_plugins imap_quota
mail_max_userip_connections = 10
imap_client_workarounds = delay-newmail tb-extra-mailbox-sep
}
# LDA configuration
protocol lda {
mail_plugins = \$mail_plugins sieve
postmaster_address = postmaster@$myhostname
quota_full_tempfail = yes
deliver_log_format = msgid=%m: %$
rejection_reason = Your message to <%t> was automatically rejected:%n%r
}
# Plugins configuration
plugin {
sieve=~/.dovecot.sieve
sieve_dir=~/sieve
sieve_before = /var/mail/vmail/sieve-before
sieve_after = /var/mail/vmail/sieve-after
quota = maildir:User quota
quota_grace = 0%%
quota_rule = *:storage=2GB
quota_rule2 = Trash:storage=+10%%
quota_rule3 = Junk:ignore
}
# Authentication configuration
auth_mechanisms = plain login
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf
deny = no
master = no
pass = no
skip = never
result_failure = continue
result_internalfail = continue
result_success = return-ok
}
userdb {
driver = prefetch
}
userdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf
}
# Log all failed authentication attempts
auth_verbose=yes
service auth {
# Postfix smtp-auth
unix_listener /var/spool/postfix/private/dovecot-auth {
mode = 0660
user = postfix
group = postfix
}
}
EOF
cat > /etc/dovecot/dovecot-sql.conf << EOF
driver = mysql
connect = host=$db_host dbname=$db_name user=$db_user password=$db_password
default_pass_scheme = SHA512-CRYPT
password_query = \
SELECT \
eu.username as user, \
d.name as domain, \
eu.password, \
'/var/mail/vmail/%d/%n' as userdb_home, \
'5000' as userdb_uid, \
'5000' as userdb_gid, \
concat('*:storage=', d.user_quota_limit) as userdb_quota_rule \
FROM \
postfix_emailuser eu, \
postfix_domain d \
WHERE \
d.id=eu.domain_id \
AND eu.active=true \
AND d.active=true \
AND eu.username='%n' \
and d.name='%d'
user_query = \
SELECT \
'/var/mail/vmail/%d/%n' as home, \
'5000' as uid, \
'5000' as gid, \
concat('*:storage=', d.user_quota_limit) as quota_rule \
FROM \
postfix_emailuser eu, \
postfix_domain d \
WHERE \
d.id=eu.domain_id \
AND eu.active=true \
AND d.active=true \
AND eu.username='%n' \
and d.name='%d'
iterate_query = \
SELECT \
eu.username as username, \
d.name as domain \
FROM \
postfix_emailuser eu, \
postfix_domain d \
WHERE \
d.id=eu.domain_id \
AND eu.active=true \
AND d.active=true
EOF
# OpenDKIM configuration
if [ ! -f /etc/opendkim/mail ]; then
echo "No OpenDKIM key found. Generating a new one."
pushd /etc/opendkim > /dev/null
opendkim-genkey -r -h sha256 -d $myhostname -s mail && \
mv mail.private mail
echo "mail.$myhostname $myhostname:mail:/etc/opendkim/mail" > /etc/opendkim/KeyTable
echo "*@$myhostname mail.$myhostname" > /etc/opendkim/SigningTable
echo "127.0.0.1" > /etc/opendkim/TrustedHosts
popd > /dev/null
fi
# ensure spamassasin config is correct
spamassassin --lint
# Update sieve
mkdir -p /var/mail/vmail/sieve-before /var/mail/vmail/sieve-after
if find /var/mail/vmail/sieve-before -mindepth 1 -name "*.sieve" -print -quit | grep -q .; then
echo "Compiling sieve-before."
sievec /var/mail/vmail/sieve-before/*.sieve
fi
if find /var/mail/vmail/sieve-after -mindepth 1 -name "*.sieve" -print -quit | grep -q .; then
echo "Compiling sieve-after."
sievec /var/mail/vmail/sieve-after/*.sieve
fi
# Create postfix folder if it doesn't exist
mkdir -p /var/lib/postfix
# Ensure files/folders have the proper permissions.
chown -R opendkim:opendkim /etc/opendkim
chown -R opendkim:root /var/spool/postfix/opendkim
chown -R debian-spamd:debian-spamd /var/lib/spamassassin
chown -R debian-spamd:root /var/spool/postfix/spamassassin/
chown -R vmail:vmail /var/mail/vmail
chown -R postfix:postfix /var/lib/postfix
chown -R root:root /var/log/*
chown -R clamav:clamav /var/log/clamav /var/lib/clamav
chown root:utmp /var/log/btmp* /var/log/lastlog* /var/log/wtmp*
chown root:adm /var/log/dmesg*
chown syslog:adm /var/log/kern.log* /var/log/mail* /var/log/syslog*
chmod 400 $tls_cert_file $tls_key_file
if [ "$(ls -A /var/lib/clamav)" ]; then
echo "Clamav signatures found."
else
echo "Clamav signatures not found. running freshclam for the first time."
freshclam
fi
# start Postfix and its related services.
function start_all() {
# ensure that postfix and crond pid file has been removed.
rm -f \
/var/spool/postfix/pid/master.pid \
/var/run/spamass/spamass.pid \
/var/run/opendkim/opendkim.pid \
/var/run/*.pid
tail -n 0 -F /var/log/syslog &
TAIL_PID=$!
service rsyslog start
cron
service opendkim start
service spamassassin start
service spamass-milter start
service clamav-daemon start
service clamav-milter start
service clamav-freshclam start
service postfix start
dovecot
wait $TAIL_PID
}
function stop_all() {
echo "Stopping primary services..."
dovecot stop
postfix stop
service clamav-freshclam stop
service clamav-milter stop
service clamav-daemon stop
kill `cat /var/run/spamass/spamass.pid`
service spamassassin stop
kill `cat /var/run/opendkim/opendkim.pid`
echo "Stopping cron and rsyslog..."
kill `cat /var/run/crond.pid`
kill `cat /var/run/rsyslogd.pid`
echo "Stopping remaining processes..."
kill "$TAIL_PID"
echo "Shutdown complete!"
}
trap stop_all EXIT
start_all