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

Reply via email to