On Thu, Mar 23, 2023 at 05:58:13PM +1100, duluxoz via Postfix-users <postfix-users@postfix.org> wrote:
> Hi All, > > TL:DR: Could someone(s) please have a look-see at our config as a sanity > check for us, and also answer the questions at the end of this post - > thanks. Hi, I probably can't help with everything but I'll see what I can do. > So we're finally putting in an email stack and while I've read just about > every tutorial I can find on the web - and read *all* of the Postfix > documentation (yes, my brains *are* leaking out my ears :-) ) - we've got a > somewhat complex environment and none of the online tutorials cover exactly > how we're set up. Oh, our entire set-up is covered across multiple > tutorials, but not one single tutorial covers everything, so we've had to do > a bit of a "mix-and-match" to achieve what we want, and I'm a bit worried > about (actually I'm scared sh!tless of) our domains ending up on Blacklists. > > So we're hoping that someone (or someones) would be kind enough to have a > look-see at our (primarily Postfix) config as a "2nd set of eyes", a "sanity > check", an/or a "wise old postfix admin" and let us know if we've > "fire-trucked" things up in any way. > > Our Environment > --------------- > > Note: All of the following is currently working without issue, both for the > internal network and for the external Internet. > > - We have a single internal domain: example.local > - We use the following private IP networks: > - DMZ - 192.168.1.0/24 > - Internal - 192.168.2.0/24 > - We currently have the below servers on the indicated IP addresses (Note: > these are the relevant hosts; there are more/others in the domain as well): > - dns-external.example.local - 192.168.1.10 > - dns-internal.example.local - 192.168.2.10 > - freeipa.example.local - 192.168.2.11 > - haproxy.example.local - 192.168.1.11 > - mysql.example.local - 192.168.2.12 > - www.example.local - 192.168.2.13 > - There is a Gateway/NAT box on the network perimeter: > - External IP - 1.2.3.4 (ie *not* the real IP address) > - Internal IP - 192.168.1.1 > - All of the internal hosts have a FreeIPA certificate assigned to them (ie > we run our own internal Certificate Authority) > - The internal FreeIPA certificates are being renewed automatically. > - We are running a Split-Horizon DNS set-up. > - We have the below four external-facing domains: > - example.com > - example.net > - example.biz > - example.org > - We have a wildcard certificate from Let's Encrypt (LE) for each of the > external domains - ie there are four certificates > - haproxy.example.local is acting as a bastion host > - (we're thinking of loading Fail2Ban on it, but haven't done so yet as > the Gateway/NAT box is keeping things under control at the moment - but it's > not really designed for that hence thinking about Fail2Ban). > - Currently all inbound traffic (except for DNS queries to the > external-facing DNS host (dns-external.example.local)) passes through > haproxy.example.local before being forwarded to the relevant internal > server. At the moment this is primarily web traffic (for our multiple > websites). > - dns-external.example.local has the correct zones set up for the external > domains (including mx records) > - haproxy.example.local is the termination point for all inbound (ie web) > TLS traffic - ie this is the host where the LE certificates are located. > - The LE certificates are being renewed automatically. > > Desired Outcome > --------------- > > - A "mail-stack" server (mail.example.local - 192.168.2.14) with Postfix, > Dovecot, ClamAV, OpenDKIM, OpenDMARC, and SpamAssassin (with Pyzor and > Razor) installed > - We are using Postfix version 3.7.4 > - We are using Dovecot version 2.3.20 > - All domains will be Virtual Mailbox Domains > - All users will be Virtual Users > - Mailboxes will be Maildir style mailboxes > - The local email user account is vmail:vmail > - MySQL (ie mysql.example.local) will be used as the primary data > store/source (except for actual emails, of course) > - The LE certificates are being periodically scp'd automatically from > haproxy.example.local to mail.example.local (this is currently working) > - A Null Client Postfix install on all other hosts for forwarding reports, > web app emails, etc, to mail.example.local for further > processing/forwarding/dovecot-delivery/etc. (This config can be provided if > requested, but should not be required for this discussion.) > - All internal inbound mail will be sent/forwarded to mail.example.local > - By the above mentioned Null Client Postfix instances > - By Dovecot for user emails > - All mail for local delivery will be forwarded to Dovecot > - All external inbound mail will be routed via HAProxy > (haproxy.example.local) > - The use of an SNI Map for the external domains (to ensure we use the > correct LE certificate) > - All outbound mail needs to be forwarded to a mail relay service (eg > www.sendinblue.com) because our ISP will not / cannot allow us to set up a > PTR DNS record (yes, we're seriously considering changing ISPs) > > Extra/Optional Desired Outcomes > ------------------------------- > > - RoundCube set up on www.example.local as an additional website and using > mysql.example.local for data storage > - PostfixAdmin set up on www.example.local as an additional website and > using mysql.example.local for data storage > > Postfix Configuration - main.cf > ------------------------------- > > Note: I've (arbitrarily) rearranged, alphabetically sorted (within each > section), and commented this file for my own sanity. > > ~~~ > ############ > # Defaults # > ############ > > alias_database = hash:/etc/aliases > command_directory = /usr/sbin > daemon_directory = /usr/libexec/postfix > data_directory = /var/lib/postfix > html_directory = no > mailq_path = /usr/bin/mailq.postfix > manpage_directory = /usr/share/man > meta_directory = /etc/postfix > newaliases_path = /usr/bin/newaliases.postfix > queue_directory = /var/spool/postfix > readme_directory = /usr/share/doc/postfix3-3.7.4/README_FILES > sample_directory = /usr/share/doc/postfix3-3.7.4/samples > sendmail_path = /usr/sbin/sendmail.postfix > setgid_group = postdrop > shlib_directory = /usr/lib/postfix > unknown_local_recipient_reject_code = 550 > > ############ > # About Me # > ############ > > mydomain = example.local > myhostname = mail.example.local > smtpd_banner = $myhostname ESMTP > > ################## > # Email Delivery # > ################## > > alias_maps = mysql:/etc/postfix/sql_aliases.cf > default_destination_concurrency_limit = 20 > dovecot_destination_recipient_limit = 1 > home_mailbox = Maildir/ > local_recipient_maps = > mailbox_size_limit = 0 > message_size_limit = 104857600 > > #################### > # General Settings # > #################### > > biff = no > compatibility_level = 3.7 The above isn't a really a meaningful value. It's OK, but the only meaningful values are 0 (default), 1, 2, and 3.6. It should probably be changed to 3.6. But it's probably OK as it is. See http://www.postfix.org/COMPATIBILITY_README.html > debug_peer_list = 192.168.2.0/24, sendinblue.com > disable_vrfy_command = yes > fallback_transport = > smtputf8_enable = no The above is a strange choice. I assume you have your reasons. > > ########### > # Logging # > ########### > > maillog_file=/var/log/postfix.log > > ########### > # Milters # > ########### > > milter_default_action = accept > milter_connect_macros = j {daemon_name} v {if_name} _ > non_smtpd_milters = $smtpd_milters > smtpd_milters = > unix:/opendkim/opendkim.sock > unix:/opendmarc/opendmarc.sock > unix:/spamass/spamass.sock > unix:/clamav/clamav-milter.ctl > > ############## > # PostScreen # > ############## > > postscreen_access_list = permit_mynetworks > postscreen_bare_newline_action = enforce > postscreen_bare_newline_enable = yes > postscreen_dnsbl_action = enforce > postscreen_dnsbl_sites = > zen.spamhaus.org > b.barracudacentral.org > bl.spamcop.net > postscreen_dnsbl_whitelist_threshold = -2 > postscreen_greet_action = enforce > postscreen_non_smtp_command_action = enforce > postscreen_non_smtp_command_enable = yes > postscreen_pipelining_action = enforce > postscreen_pipelining_enable = yes > postscreen_upstream_proxy_protocol = haproxy > postscreen_upstream_proxy_timeout = 5s > > ################## > # Receiving Mail # > ################## > > canonical_maps = hash:/etc/postfix/canonical > inet_protocols = ipv4 > mydestination = > $myhostname > localhost.$mydomain > localhost > $mydomain > proxy_interfaces = 1.2.3.4 > recipient_delimiter = + > smtp_address_preference = ipv4 The above isn't needed when inet_protocols=ipv4. It's only needed when you support IPv4 and IPv6 but you don't want to use IPv6 for outgoing connections (for example when your IPv6 address and its whole network is caught up in a stupid RBL but your IPv4 address isn't). > smtpd_discard_ehlo_keywords = silent-discard, dsn > smtpd_helo_required = yes > smtpd_reject_unlisted_sender = yes > strict_rfc821_envelopes = yes > unknown_address_reject_code = 550 > unknown_client_reject_code = 550 > unknown_hostname_reject_code = 550 > unverified_recipient_reject_code = 550 > unverified_recipient_reject_reason = Address lookup failed > > ######## > # SASL # > ######## > > smtp_sasl_auth_enable = yes > smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd > smtp_sasl_security_options = noplaintext, noanonymous > smtp_sasl_type = dovecot > smtp_tls_security_level = may > smtpd_sasl_auth_enable = yes > smtpd_sasl_authenticated_header = yes > smtpd_sasl_local_domain = $mydomain > smtpd_sasl_path = private/auth-dovecot > smtpd_sasl_type = dovecot > > ################ > # Sending Mail # > ################ > > header_size_limit = 4096000 > mynetworks = > 127.0.0.0/8 > 192.168.1.0/24 > 192.168.2.0/24 > myorigin = $mydomain > relay_destination_concurrency_limit = 1 > relay_domains = $mydestination > relayhost = [www.sendinblue.com]:submission If all email is being sent to sendinblue, then you don't need to worry about your IP address ending up in RBLs. All your recipients will only see sendinblue's IP addresses. If course, that can change if you change ISP, get PTR records, and send your emails directly. Are you sure that the www. address is correct. I used sendinblue briefly (when Microsoft didn't like my IP address), and I used this as a transport: relay:[smtp-relay.sendinblue.com]:587 But if sendinblue's instructions have changed, and they now say to use www.sendinblue.com, then it's probably OK. But they do have different IP addresses, so it doesn't look right: > host www.sendinblue.com www.sendinblue.com has address 104.17.133.96 www.sendinblue.com has address 104.16.255.96 www.sendinblue.com has IPv6 address 2606:4700::6811:8560 www.sendinblue.com has IPv6 address 2606:4700::6810:ff60 > host smtp-relay.sendinblue.com smtp-relay.sendinblue.com has address 1.179.113.51 So I suspect the above should be: relayhost = [smtp-relay.sendinblue.com]:submission > smtpd_sender_login_maps = $virtual_mailbox_maps > > ########### > # SSL/TSL # > ########### > > smtp_tls_chain_files = /etc/postfix/ssl/'*.example.com.pem' > smtpd_tls_chain_files = /etc/postfix/ssl/'*.example.com.pem' I hope the above two lines were modified for this list. That's not valid syntax. Postfix doesn't do file glob expansion like this. Also, smtp_tls_chain_files only needs to be set when outgoing mail goes to servers that check the client certificates of incoming connections (I'm pretty sure). Since you are relaying all outgoing mail to sendinblue, that will not be the case. It's rarely needed. Also, note that when using smtp_tls_chain_files/smtpd_tls_chain_files the order of files is important. For each key algorithm (rsa, ed25519, ...), there needs to be either a single file that contains the private key(s) followed by the certificate chain, or two files, the first containing the private key(s) and the second containing the certificate chain. It's best to use a single file for each key algorithm to eliminate the chance of a little race condition when keys rollover. You are probably just using multiple files because you have multiple domains and a separate file or two for each domain (based on your use of tls_server_sni_maps), but I mention this because of your attempted use of globbing. It orders files lexicographically by name which might or might not meet postfix's ordering requirement (depending on your file naming convention). > smtp_tls_loglevel = 1 > smtp_tls_mandatory_protocols = >=TLSv1.2 > smtp_tls_note_starttls_offer = yes > smtp_tls_protocols = >=TLSv1.2 The above isn't a good idea. If a receiving mail server doesn't support TLSv1.2, the mail to them will be sent unencrypted. This won't matter while everything is being sent to sendinblue which supports TLSv1.2, but in future, when you have a better ISP and stop using sendinblue, it's not helpful. In fact, the only reason to exclude TLSv1 and TLS1.1 is to look "good" for the purpose of misguided security assessments that think that what's best for HTTPS (mandatory encryption) is also good for SMTP (opportunistic encryption). It isn't. And that only matters (if at all) for incoming connections that can be checked as part of a security "assessment". The above parameter only affects outgoing connections which can't be scanned for in a simple security assessment. > smtp_tls_security_level = may > smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache > smtpd_starttls_timeout = 300s > smtpd_tls_ask_ccert = yes The above is probably unhelpful unless you actually check client certificates for incoming connections. Perhaps you do. If not, it's a waste of bandwidth. You aren't using permit_tls_clientcerts so the above isn't needed. > smtpd_tls_auth_only = yes > smtpd_tls_loglevel = 1 > smtpd_tls_mandatory_protocols = >=TLSv1.2 > smtpd_tls_protocols = >=TLSv1.2 See above. This would be more interoperable and more secure if it was >=TLSv1 but misguided security assessments might disagree. > smtpd_tls_received_header = yes > smtpd_tls_security_level = may > smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache The above isn't needed since postfix 2.11. It should be left empty. > smtpd_use_tls=yes The above is a redundant old version of smtpd_tls_security_level=may and can be removed. > tls_random_source = dev:/dev/urandom > tls_server_sni_maps = hash:/etc/postfix/sni_maps I don't know much above the above except that it isn't generally important. Most incoming connections won't care what the domain name in the certificate is. But perhaps yours do. > ############################### > # Virtual Domains & Mailboxes # > ############################### > > virtual_alias_maps=mysql:/etc/postfix/sql_virtual_aliases.cf > virtual_mailbox_domains=mysql:/etc/postfix/sql_virtual_domains.cf > virtual_mailbox_maps=mysql:/etc/postfix/sql_virtual_mailboxes.cf > virtual_transport = lmtp:unix:private/dovecot-lmtp > > ################ > # Restrictions # > ################ > > # Restriction lists are evaluated in the order given below. > > smtpd_client_restrictions = > permit_mynetworks > reject > smtpd_helo_restrictions = > permit_mynetworks > reject_non_fqdn_helo_hostname > reject_invalid_helo_hostname > reject_unknown_helo_hostname Since smtpd_client_restrictions only allows connections from your own infrastructure, the smtpd_helo_restrictions might not add anything. Unless the haproxy forwards the originating HELO name? > smtpd_sender_restrictions = > reject_unknown_sender_domain > reject_sender_login_mismatch I'd recommend always including the default at the end of all the restrictions parameters. For example, the default for smtpd_sender_restrictions is "permit". But perhaps that's just a matter of style. I really think it's best not to require the reader to remember the implicit defaults. But it's not wrong. Feel free to ignore this. > smtpd_relay_restrictions = > permit_mynetworks > permit_sasl_authenticated > defer_unauth_destination > smtpd_recipient_restrictions = > reject_unknown_client_hostname > reject_unknown_sender_domain > reject_unknown_recipient_domain > reject_unauth_pipelining > reject_unauth_destination > reject_unverified_recipient > check_policy_service unix:private/quota-status > reject_invalid_hostname > reject_non_fqdn_recipient > reject_non_fqdn_sender > reject_rbl_client zen.spamhaus.org > reject_rhsbl_reverse_client dbl.spamhaus.org > reject_rhsbl_helo dbl.spamhaus.org > reject_rhsbl_sender dbl.spamhaus.org > > ~~~ > > Postfix Configuration - master.cf > --------------------------------- > > Note: Again, I've alphabetically sorted this file for my own sanity as well. > > ~~~ > #================================================================================= > #service type private unpriv chroot wakeup maxproc command + > args > # (yes) (yes) (no) (never) (100) > #================================================================================= > anvil unix - - - - 1 anvil > bounce unix - - - - 0 bounce > cleanup unix n - - - 0 cleanup > defer unix - - - - 0 bounce > discard unix - - - - - discard > dnsblog unix - - - - 0 dnsblog > dovecot unix - n - - - pipe > flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d > ${recipient} > error unix - - - - - error > flush unix n - - 1000? 0 flush > lmtp unix - - - - - lmtp > local unix - n - - - local > pickup unix n - - 60 1 pickup > postlog unix-dgram n - - - 1 postlogd > proxymap unix - - - - - proxymap > proxywrite unix - - - - 1 proxymap > qmgr unix n - - 300 1 qmgr > relay unix - - - - - smtp > -o smtp_connect_timeout=5 > -o smtp_helo_timeout=5 > -o syslog_name=postfix/$service_name > retry unix - - - - - error > rewrite unix - - - - - > trivial-rewrite > scache unix - - - - 1 scache > showq unix n - - - - showq > smtp inet n - - - 1 postscreen > -o postscreen_upstream_proxy_protocol=haproxy > -o postscreen_upstream_proxy_timeout=50s > smtp unix - - - - - smtp > smtpd pass - - - - - smtpd > submission inet n - - - - smtpd > -o milter_macro_daemon_name=ORIGINATING > -o smtpd_relay_restrictions=permit_sasl_authenticated,reject > -o smtpd_reject_unlisted_recipient=no > -o smtpd_sasl_auth_enable=yes > -o smtpd_sender_restrictions=reject_sender_login_mismatch > -o smtpd_tls_auth_only=yes > -o smtpd_tls_security_level=encrypt > -o syslog_name=postfix/submission > tlsmgr unix - - - 1000? 1 tlsmgr > tlsproxy unix - - - - 0 tlsproxy > trace unix - - - - 0 bounce > verify unix - - - - 1 verify > virtual unix - n - - - virtual > ~~~ I haven't examined your master.cf much, but since you have enabled tlsproxy, you might want to consider setting smtp_tls_connection_reuse=yes in main.cf. Since all mail is being relayed to the same server (sendinblue), reusing TLS connections should be more efficient. It requires tlsproxy which isn't enabled by default, but you have enabled it, so you might as well get the most benefit from it. > Further Questions > ----------------- > > 1) Do we need to add the mail.example.local's FreeIPA certificate to the > sni_maps? I don't think so. I don't think the sni_maps are needed at all but I could be wrong about that. If so, ignore this answer. Most SMTP clients don't care about the domain names in SMTP server certificates. But all of your incoming connections are from your own infrastructure so maybe you know something unusual about your internal clients that you haven't mentioned. > 2) Does it matter which external LE certificate we use for > smtp_tls_chain_files and/or smtpd_tls_chain_files? See above comments on these two parameters. smtp_tls_chain_files isn't needed at all because all outgoing mail is going to sendinblue which will not be requiring specific client certificates from you. As for smtpd_tls_chain_files, all incoming connections are coming from your own infrastructure (e.g. haproxy) which (like most SMTP clients) probably won't care what domain is used in your SMTP server certificate. > 3) Instead of using example.local for mydomain should we instead be using > example.com (or whichever of the external domain names we decide to use)? No. I think example.local is correct because it's the default value given that myhostname = mail.example.com. It's not supposed (necessarily) to reflect any of the domains whose mail is being handled. It's the domain name of the mail server itself, which is just whatever it is. When the internal and the external don't match, it's important to tell postfix by setting the proxy_interfaces parameter to the external IP address, and you have done that. > Thanks in advance > > Dulux-Oz Good luck! cheers, raf _______________________________________________ Postfix-users mailing list -- postfix-users@postfix.org To unsubscribe send an email to postfix-users-le...@postfix.org