On Sat, Dec 24, 2022 at 07:51:42AM +0400, Samer Afach <samer.af...@msn.com> 
wrote:

> Dear Raf:
> 
> Thank you very much. I just tested my server with mxtoolbox, and all seems
> good. I didn't realize mxtoolbox works without MX records, thanks for that
> hint.
> 
> I applied 90% of your suggestions, and some I didn't out of fear. I'm
> working on understanding them more.

Good decision. :-)

> I have two questions if you don't mind.
> 
> 1. I see you're telling me to remove smtpd_client_restrictions (for both 465
> and 587?) and only keep smtpd_recipient_restrictions. Can you please
> elaborate on the difference? I thought clients connecting to the server are
> what we need to restrict. I kind of failed to understand why
> smtpd_recipient_restrictions even exists.

The reason is that the only important restriction that you need (In my
opinion) for ports 465/587 is SASL-authentication. It doesn't matter
what the source IP address is if the authentication succeeds (that's
assuming that you are certain that brute-force guessing of passwords
from around the world won't succeed).

The main purpose for smtpd_client_restrictions is to be able to reject
connections at the very earliest stage of an SMTP connection: when the
connection first happens, and the only information that is available
to Postfix is the IP address of the client. So it makes sense to only
put criteria there that are based on the source IP address (i.e.,
things like permit_mynetworks and RBL checks). If you put anything
else in smtpd_client_restrictions, its evaluation has to wait until
later in the connection. It'll still work, it's just not the "ideal"
place for other criteria. The reason that there are many
smtpd_*_restrictions parameters is that they each apply to a
particular point in time during the SMTP protocol (e.g., HELO/EHLO,
MAIL FROM, RCPT TO, DATA). So, you can specify checks that make sense
at each point in time. However, for the most part, you can actually
put all of the restrictions in a single smtpd_*_restrictions parameter
and it will be fine. By default, the decisions are delayed until it's
possible to evaluate the restrictions. The only real advantage to
splitting up the criteria into separate restrictions parameters is
that it makes it possible to reject connections at the earliest
possible time. But that probably only matters when the mail volume is
very high, and you want to maximise efficiency when rejecting
connections (i.e., why wait until the RCPT TO command or DATA command
if the HELO/EHLO command is unacceptable). The only real requirement
is that you either use smtpd_recipient_restrictions or
smtpd_relay_restrictions, and one of a certain set of items must
appear in either (or both) of them, or Postfix won't accept that you
have tried to prevent being an open relay.

See http://www.postfix.org/SMTPD_ACCESS_README.html and the
entries in postconf(5) for all of the smtpd_*_restrictions
parameters.

> With that logic, I only removed
> the smtp_* part of the enforced protocols. My fear, which is very paranoid,
> is that a peer of mine gets hacked, and then their email server uses nothing
> but unencrypted connection. Forcing encryption basically means this issue
> will be noticeable. (and if you're wondering why port 25's encryption is
> `may` in main.cf, it's because I still don't know how to get fetchmail to
> deliver emails without that... another issue to be solved).

The restrictions and whether or not encryption happens are not related
to each other. Port 25's encryption should definitely be "may". I said
that SASL-authentication shouldn't be enabled on port 25. That's not
the same thing. Encryption/STARTTLS for incoming connections on port
25 is enabled with smtpd_tls_security_level=may in main.cf. That's
great. Keep that. SASL-authenticated for incoming connections on port
25 is enabled with smtpd_sasl_auth_enable=yes in main.cf. That's not
useful (other MTAs won't SASL-authenticate with your server on port
25), so it can be removed. The only place that
smtpd_sasl_auth_enable=yes is useful is in master.cf when defining the
services for ports 465 and 587.

Also, you weren't forcing encryption. You you just excluding certain
TLS versions from being used when encryption was used. The parameters
with "mandatory" in their names excluded certain versions of TLS when
*mandatory* encryption was in place. But there was nothing in your
configuration that made encryption mandatory. Making encryption
mandatory requires something like smtpd_tls_security_level=encrypt or
smtpd_tls_wrappermode=yes but you can't do that for port 25. It's
important to realise that for email, encryption is almost always
opportunistic, not mandatory. Any encryption is better than none when
it comes to opportunistic encryption. There can be cases where you are
required to encrypt mail sent to particular peers, but that will be by
prior arrangement, and you will need to set up a different "transport"
in Postfix for that peer, and that transport can have different
properties such as mandatory encryption. Often, what that looks like
is a peer that you connect to over port 587 rather than port 25. And
your transport table specifies this. It can get much more complicated,
but that's enough for now. :-) Read the TLS_README if you want more
details.

If you are concerned about a peer getting hacked (or a MITM attack),
you could investigate DANE (DNS-based Authentication of Named
Entities). If a domain uses DNSSEC, it's possible to publish the
fingerprint of that domain's mail server's TLS key in the DNS. Then,
mail clients (other MTAs) can check and make sure not only that when
they send an email to that domain, they get a key to encrypt to, but
that it's the correct key owned by the domain, and not some other key
owned by a MITM attacker. Actually, if the mail server is hacked,
they'd keep using the correct key any way. This is really to prevent
MITM attacks. If a domain is using DANE to publish its legitimate key,
then clients can be configured to only send mail when they see the
correct key. The way to do this is that instead of having this in
main.cf:

  smtp_tls_security_level = yes

You have this:

  smtp_dns_support_level = dnssec
  smtp_tls_security_level = dane

AND (very important) you run a DNSSEC-validating DNS resolver like
Bind9 or Unbound on the localhost, and put this in /etc/resolv.conf:

  nameserver 127.0.0.1
  options trust-ad

That tells Postfix that it can trust DNSSEC lookups, and that
it should check if remote MTAs have published their TLS keys
and if so, only accept keys that match the published TLSA
DNS records when making outgoing SMTP connections.

And of course, if your own domain uses DNSSEC (much easier nowadays
than it used to be), you can publish TLSA records for your own TLS
keys, and just hope that other MTAs that send you email have been
configured to check for them. Most probably won't, but the number
should be increasing. However, setting that up doesn't have anything
to do with Postfix itself. But there are tools that can help with the
setup such as LetsDNS (https://letsdns.org/) and (my) danectl
(https://raf.org/danectl).

> 2. It's been too long and I'm too afraid to ask (Chris Pratt meme goes
> here): Is smtp strictly for outgoing connections, no matter what port, and
> smtpd for incoming connections, no matter what port?

That's right. smtpd_* is for incoming connections. When it's in
main.cf, it applies to port 25. When it's in master.cf, it applies to
the port of the particular service definition where it appears. smtp_*
is for outgoing connections whether it's going to a peer's port 25, or
to a peer's port 465/587 (which would only happen if there's an entry
for a particular domain in the transport table that tells Postfix to
connect via one of those ports - some peers might require
authentication and encryption).

> Btw, just a note since you mentioned it, while using one file for keys +
> certificates has an advantage, I have to say that letsencrypt really annoys
> me that it doesn't do that automatically. I have a to run cron jobs to
> recreate this for HAProxy... because HAProxy only accepts one file with
> everything in it. Your comment explained to me why HAProxy enforces this,
> but doesn't explain why letsencrypt cannot add a `cat` call after recreating
> the certificates.

Cron isn't the best choice because it doesn't know when the
certificate renews. You can automate this with LetsEncrypt's deploy
hooks. You can run a script that performs the cat as soon as the key
and certificate are renewed (rather than waiting for the cronjob to
happen). If you set up a deploy hook that runs the following script,
there will always be a single file containing the privkey and
fullchain that matches the underlying files:

  /etc/postfix/mktlschain:
  #!/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.
  # http://www.postfix.org/TLS_README.html

  # This is 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

Installing this as a LetEncrypt deploy hook depends on whether or not
you only have a single domain. If so, you can put the script file in
the /etc/letsencrypt/renewal-hooks/deploy directory.

It's more complicated if you have LetsEncrypt handling multiple
domains on the same host because LetsEncrypt wants to run the same
hook script for every domain, and you probably only need this for one
of them. But it should be easy to adapt. I have a setup that has
distinct per-domain hooks.

> Thanks a lot for looking into my configuration. That's very generous of you.

No worries. I hope you're having fun with Postfix!

> Cheers,
> Sam

cheers,
raf

Reply via email to