On Sat, Nov 06, 2021 at 11:38:26PM -0500, Tyler Montney 
<montneyty...@gmail.com> wrote:

> Sorry for the long delay, wanted to do more research before posting it.
> I've replaced some real values, like myhostname, with generic ones.

I expect it's all fine or you would have had a response by now.
I'll have a look and make comments, but be warned that I might
easily misunderstand something and say something dumb. So don't
take it too seriously. 

> postconf -nf
> 
> command_directory = /usr/sbin

You seem to be explicitly setting many parameters to their defaults.
That's harmless but unnecessary.

> content_filter = smtp-amavis:[127.0.0.1]:10024

With a content filter, you want to only do address
mappings before or after the filter, not both. You have
the address mappings happening before, which means that
the filter doesn't have access to the original
addresses. It only has access to the mapped addresses.
That might be want you want. You have suppressed
address mappings after the filter by having this in
master.cf for the 127.0.0.1:10025 service:

    
receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_address_mappings

If you'd prefer to make the original addresses
available to the content filter, you could instead have
"receive_override_options = no_address_mappings" in
main.cf and remove "no_address_mappings" from
master.cf.

Both ways are fine.

However, I think you might want to add "no_milters" to
the receive_override_options parameter in master.cf.
Otherwise, the milters will probably run both before
and after the filter. It's unlikely that that's what
you want (but it might be - I don't know what the
milter on port 11332 is doing).

> header_checks = regexp:/etc/postfix/header_checks
> mime_header_checks = regexp:/etc/postfix/header_checks

If you have pcre available (it's a separate package on
Debian), you might want to use that instead of regexp
because pcre is faster.

> inet_interfaces = 192.168.0.3, 127.0.0.1

This probably isn't needed unless there are
other IP addresses that you want to exclude.

> inet_protocols = ipv4

This probably isn't needed unless you have IPv6 but
don't want to use it.

> message_size_limit = 52428800
> virtual_mailbox_limit = 5242880000

message_size_limit needs to be less than or equal to
virtual_mailbox_limit. Your virtual_mailbox_limit is
100 times message_size_limit. So that's fine, but they
could also be equal. I don't know if there's a reason
for virtual_mailbox_limit to be so much larger than
message_size_limit.

> milter_default_action = accept
> milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}

I don't know enough to comment sensibly on this. The
only milters I use are opendkim and opendmarc, and I
leave milter_mail_macros at it's default value. But
even if the milter on port 11332 needs the addition of
{client_addr} {client_name}, there's probably no reason
to remove {auth_type} {auth_author} {mail_host}. But I
expect that you understand this much better than I do,
so ignore the above. :-)

> mydestination = localhost.$mydomain, localhost
> myhostname = mail.foo.com
> mailbox_transport = lmtp:unix:private/dovecot-lmtp

Removing $myhostname from mydestination looks unusual
to me. I assume there's a good reason, but since you
have local delivery (using lmtp and dovecot in
mailbox_transport), it seems odd that the mail server's
hostname can't be used in an email address for the
local users. I assume that you just want locally
originating email for local users, and you want that
local email to be delivered to a dovecot mailbox.
So it's probably all fine.

> smtp_tls_mandatory_protocols = >=TLSv1.2
> smtp_tls_protocols = >=TLSv1.2

This can lead to your mail server transmitting email
unencrypted if the receiving server doesn't support
TLSv1.2 but does support TLSv1.0 or TLSv1.1. That
doesn't really do anyone any favours. Remember that
SMTP encryption is opportunistic. If you are too fussy,
you get nothing. SSLv2 and SSLv3 should be excluded
because they are broken, but TLSv1.0 and TLSv1.1 are
still OK to use for mail (even though they are
deprecated).

Even if you have some security theatre requirements not
to accept TLSv1.0 on your mail server, that is achieved
with the smtpd_ equivalents of these parameters
(below). As far as I am aware, nothing scans which
protocols are supported by your server for outgoing
mail.

> smtp_tls_security_level = may

This is fine, but you might be able to do better. If
your mail server runs a local DNSSEC-validating name
resolver (e.g., Bind9 or Unbound), then you could make
Postfix DANE-aware and avoid falling prey to
man-in-the-middle attacks when sending mail to remote
SMTP servers that implement DANE. To do this, your
/etc/resolv.conf would need to look something like this:

  nameserver 127.0.0.1
  options trust-ad

(with no other nameserver entries), and then you would replace
"smtp_tls_security_level = may" in main.cf with:

  smtp_dns_support_level = dnssec
  smtp_tls_security_level = dane

When sending mail to servers that don't implement DANE,
this is the same as "may".

> smtpd_discard_ehlo_keywords = chunking

You might want to add "silent-discard" to the above
to suppress warnings in your log files about it.

> smtpd_helo_required = yes
> smtpd_helo_restrictions = check_helo_access hash:/etc/postfix/helo,
>     reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname,
>     reject_unknown_helo_hostname, permit
> smtpd_milters = local:opendkim/opendkim.sock,
>     local:opendmarc/opendmarc.sock,
>     inet:127.0.0.1:11332
> smtpd_proxy_options = speed_adjust
> smtpd_recipient_restrictions = reject_non_fqdn_recipient,
>     reject_non_fqdn_sender, reject_unknown_sender_domain,
>     reject_unknown_recipient_domain, reject_unauth_pipelining,
>     permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination,
>     check_recipient_access hash:/etc/postfix/specialaccounts,
>     reject_multi_recipient_bounce, reject_unknown_client_hostname,
>     check_policy_service inet:127.0.0.1:10023, reject_rhsbl_helo
>     dbl.spamhaus.org, reject_rhsbl_reverse_client dbl.spamhaus.org,
>     reject_rhsbl_sender dbl.spamhaus.org, reject_rbl_client zen.spamhaus.org,
>     permit

This looks fine. I assume port 10023 is running Postgrey. Postgrey is great.

> smtpd_sasl_auth_enable = yes
> smtpd_sasl_local_domain = foo.mylocal
> smtpd_sasl_path = private/auth
> smtpd_sasl_security_options = noanonymous
> smtpd_sasl_type = dovecot

smtpd_sasl_auth_enable  shouldn't be in main.cf. Having
it here means that port 25 offers authentication. It's
better to remove it from main.cf, and add it to the
submission service in master.cf. You can leave the
other smtpd_sasl_ parameters here in main.cf, or move
them as well, whichever you prefer.

It might not really matter. It just means that people
that want to bombard your server with brute force
authentication attempts have to do it on port 587
rather than port 25, but it's generally recommended on
this mailing list not to support authentication on port
25. But if you can restrict access to port 587 to known
non-mobile clients, then it might make a difference. If
you can't do that, you can limit brute force
authentication attempts with something like this:

  smtpd_client_auth_rate_limit = 10

That limits authentication attempts (successful or not)
to that many every $anvil_rate_time_unit (default: 60s).

> smtpd_tls_cert_file =
>     /etc/letsencrypt/live/mail.foo.com/fullchain.pem
> smtpd_tls_key_file = /etc/letsencrypt/live/mail.foo.com/privkey.pem

It's better to use the new smtpd_tls_chain_files parameter
rather than smtpd_tls_cert_file and smtpd_tls_key_file.
But it's better still if you can also set up a certbot renewal hook
to combine the privkey.pem and fullchain.pem files into a
single file every time it renews the certificate. That way,
you eliminate the chance of a race condition when Postfix
reads the new key and chain.

For example, if you set up a renewal hook that executes a script
like this:

    #!/bin/sh -e
    
    # Postfix recommends a single file, containing both the private key
    # and the certificate chain, as that makes it possible to rollover
    # keys atomically and avoid race conditions.
    # See http://www.postfix.org/TLS_README.html
    
    # This needs to run automatically when the LetsEncrypt certificate is 
renewed.
    # Note: a Postfix reload is not required after this.
    # Note: this puts the file in $RENEWED_LINEAGE (i.e., 
/etc/letsencrypt/live/CERTNAME)
    # so that multiple lineages for the same domain can coexist. This is needed 
for use
    # with danectl(1). When using danectl, refer to /etc/letsencrypt/current 
rather
    # than /etc/letsencrypt/live in main.cf.
    
    [ -n "$RENEWED_LINEAGE" -a -d "$RENEWED_LINEAGE" ] || exit 1
    cd "$RENEWED_LINEAGE"
    chain=privkey-then-fullchain-for-postfix.pem
    umask 077
    touch $chain.tmp
    chmod 600 $chain.tmp
    cat privkey.pem fullchain.pem > $chain.tmp
    mv $chain.tmp $chain
    chmod 600 $chain

Then you can wait for the next certificate renewal and then
put this in main.cf:

    smtpd_tls_chain_files =
        
/etc/letsencrypt/live/mail.foo.com/privkey-then-fullchain-for-postfix.pem

> smtpd_tls_mandatory_protocols = >=TLSv1.2
> smtpd_tls_protocols = >=TLSv1.2

See the above note for the smtp_ versions of these parameters.

> postconf -Mf
> 
> smtp       inet  n       -       y       -       -       smtpd
> dovecot    unix  -       n       n       -       -       pipe flags=DRhu
>     user=vmail:mail argv=/usr/lib/dovecot/dovecot-lda -f ${sender} -d
>     ${recipient}
> submission inet  n       -       y       -       -       smtpd
>     -o syslog_name=postfix/submission
>     -o smtpd_tls_security_level=encrypt
>     -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
>     -o content_filter=smtp-amavis:[127.0.0.1]:10026

I didn't realise you had a separate Amavis service
running for authenticated users when I mentioned
receive_override_options earlier. I think the same
would apply here.

> pickup     unix  n       -       y       60      1       pickup
> cleanup    unix  n       -       y       -       0       cleanup
> qmgr       unix  n       -       n       300     1       qmgr
> tlsmgr     unix  -       -       y       1000?   1       tlsmgr
> rewrite    unix  -       -       y       -       -       trivial-rewrite
> bounce     unix  -       -       y       -       0       bounce
> defer      unix  -       -       y       -       0       bounce
> trace      unix  -       -       y       -       0       bounce
> verify     unix  -       -       y       -       1       verify
> flush      unix  n       -       y       1000?   0       flush
> proxymap   unix  -       -       n       -       -       proxymap
> proxywrite unix  -       -       n       -       1       proxymap
> smtp       unix  -       -       y       -       -       smtp
> relay      unix  -       -       y       -       -       smtp
>     -o syslog_name=postfix/$service_name
> showq      unix  n       -       y       -       -       showq
> error      unix  -       -       y       -       -       error
> retry      unix  -       -       y       -       -       error
> discard    unix  -       -       y       -       -       discard
> local      unix  -       n       n       -       -       local
> virtual    unix  -       n       n       -       -       virtual
> lmtp       unix  -       -       y       -       -       lmtp
> anvil      unix  -       -       y       -       1       anvil
> scache     unix  -       -       y       -       1       scache
> postlog    unix-dgram n  -       n       -       1       postlogd
> smtp-amavis unix -       -       n       -       2       smtp
>     -o syslog_name=postfix/amavis
>     -o smtp_data_done_timeout=1200
>     -o smtp_send_xforward_command=yes
>     -o disable_dns_lookups=yes

It's best not to disable_dns_lookups. The Amavis guide says to do it,
but the Postfix documentation says to ignore old guides that say to do
it (See http://www.postfix.org/postconf.5.html#smtp_dns_support_level).

>     -o max_use=20
>     -o smtp_tls_security_level=none

This is probably unnecessary. The amavis smtp client probably doesn't
offer STARTTLS.

> 127.0.0.1:10025 inet n   -       n       -       -       smtpd
>     -o syslog_name=postfix/10025
>     -o content_filter=
>     -o mynetworks_style=host

This is the default and wasn't modified in main.cf. It could be removed.

>     -o mynetworks=127.0.0.0/8

I don't think that this isn't needed since it's only listening
on 127.0.0.1 anyway, but I think you might need:

  -o smtpd_authorized_xforward_hosts=127.0.0.0/8

>     -o local_recipient_maps=
>     -o relay_recipient_maps=

These are the default and weren't modified in main.cf. It could be removed.

>     -o strict_rfc821_envelopes=yes

It might make more sense to move this to main.cf to have
an effect for all mail when it first arrives.

>     -o smtp_tls_security_level=none
>     -o smtpd_tls_security_level=none

These probably aren't needed.

>     -o smtpd_restriction_classes=

This is the default and wasn't modified in main.cf. It could be removed.

>     -o smtpd_delay_reject=no

This is harmless because you aren't using any restrictions
that could be broken by it, but it also probably doesn't do
any good. Not delaying rejections makes more sense when
the client is a remote mail client, not Amavis running locally.
At least, I think so. But I could be wrong.

>     -o smtpd_client_restrictions=permit_mynetworks,reject

This could probably be removed since it's the default, wasn't
modified in main.cf, and smtpd_recipient_restrictions (below)
does the same thing. But it does no harm.

>     -o smtpd_sender_restrictions=

This is the default and wasn't modified in main.cf. It could be removed.

>     -o smtpd_recipient_restrictions=permit_mynetworks,reject

Yep.

>     -o smtpd_end_of_data_restrictions=

This is the default and wasn't modified in main.cf. It could be removed.

>     -o smtpd_error_sleep_time=0
>     -o smtpd_soft_error_limit=1001
>     -o smtpd_hard_error_limit=1000
>     -o smtpd_client_connection_count_limit=0
>     -o smtpd_client_connection_rate_limit=0

Yep.

>     -o
> receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_address_mappings

See comments above about probably wanting to add
"no_milters" to the above, and possibly wanting to move
"no_address_mappings" from here to main.cf.



Having said all that, I think it all looks fine and
workable, except that "no_milters" should probably be
added to "receive_override_options" in master.cf, to
prevent milters running twice. Am I mistaken about
that? It's possible.

One other thing. Since you are using OpenDKIM and
OpenDMARC, you might also want to add SPF checking (for
domains that use SPF but not DMARC).

For example, on Debian, install the
postfix-policyd-spf-perl package (there's also a Python
alternative), and add this to master.cf:

    # SPF check policy service 
(https://www.linuxbabe.com/mail-server/setting-up-dkim-and-spf)
    spfcheck  unix  -       n       n       -       0  spawn
        user=policyd-spf argv=/usr/sbin/postfix-policyd-spf-perl

And add this to smtpd_recipient_restrictions in main.cf:

    check_policy_service unix:private/spfcheck

cheers,
raf

> On Sun, Oct 17, 2021 at 6:25 PM raf <post...@raf.org> wrote:
> 
> > On Fri, Oct 15, 2021 at 12:20:55PM -0500, Tyler Montney <
> > montneyty...@gmail.com> wrote:
> >
> > > One other thing while I wait...
> > >
> > > Once I'm done researching (in a week or two), I'd like someone to
> > provide a
> > > sanity check on my Postfix config by posting it here. Is that allowed?
> >
> > Sure. When you're ready, post the output of "postconf -nf" and "postconf
> > -Mf".
> >
> > cheers,
> > raf
> >
> >

Reply via email to