Centos – Postfix 2.10 client certificate-based relay

centospostfixssl

I'm attempting to configure 2 Postfix 2.10.1 instances, each on separate CentOS 7 systems, to allow certificate-based relay from one system (which we'll call client.example.com) to the other (server.example.com), but I've hit a snag. The server absolutely refuses to accept the relay based on the client's certificate fingerprint.

Here's what I'm working with:

Output of postconf -n on the server:

alias_database = hash:/etc/aliases
alias_maps = hash:/etc/aliases
command_directory = /usr/sbin
config_directory = /etc/postfix
daemon_directory = /usr/libexec/postfix
data_directory = /var/lib/postfix
debug_peer_level = 2
debugger_command = PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin ddd $daemon_directory/$process_name $process_id & sleep 5
html_directory = no
inet_interfaces = all
inet_protocols = ipv4
local_recipient_maps =
mail_owner = postfix
mailq_path = /usr/bin/mailq.postfix
manpage_directory = /usr/share/man
mydestination = localhost
mydomain = example.com
myhostname = server.example.com
mynetworks = 127.0.0.0/8
newaliases_path = /usr/bin/newaliases.postfix
queue_directory = /var/spool/postfix
readme_directory = /usr/share/doc/postfix-2.10.1/README_FILES
relay_clientcerts = hash:/etc/postfix/relay_clientcerts
relayhost = [192.168.1.3]
sample_directory = /usr/share/doc/postfix-2.10.1/samples
sendmail_path = /usr/sbin/sendmail.postfix
setgid_group = postdrop
smtpd_recipient_restrictions = permit_tls_clientcerts, reject_unauth_destination
smtpd_tls_CAfile = /etc/pki/tls/certs/cacert.pem
smtpd_tls_ask_ccert = yes
smtpd_tls_cert_file = /etc/pki/tls/certs/server.example.com.crt
smtpd_tls_fingerprint_digest = sha1
smtpd_tls_key_file = /etc/pki/tls/private/server.example.com.key
smtpd_tls_loglevel = 2
smtpd_tls_received_header = yes
smtpd_tls_security_level = may
tls_random_source = dev:/dev/urandom
unknown_local_recipient_reject_code = 550

Output of postconf -n on the client:

alias_database = hash:/etc/aliases
alias_maps = hash:/etc/aliases
command_directory = /usr/sbin
config_directory = /etc/postfix
daemon_directory = /usr/libexec/postfix
data_directory = /var/lib/postfix
debug_peer_level = 2
debugger_command = PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin ddd $daemon_directory/$process_name $process_id & sleep 5
html_directory = no
inet_interfaces = localhost
inet_protocols = all
mail_owner = postfix
mailq_path = /usr/bin/mailq.postfix
manpage_directory = /usr/share/man
mydestination = $myhostname, localhost.$mydomain, localhost
newaliases_path = /usr/bin/newaliases.postfix
queue_directory = /var/spool/postfix
readme_directory = /usr/share/doc/postfix-2.10.1/README_FILES
relayhost = [server.example.com]
sample_directory = /usr/share/doc/postfix-2.10.1/samples
sendmail_path = /usr/sbin/sendmail.postfix
setgid_group = postdrop
smtp_tls_CAfile = /etc/pki/tls/certs/cacert.pem
smtp_tls_cert_file = /etc/pki/tls/certs/client.example.com.crt
smtp_tls_fingerprint_digest = sha1
smtp_tls_key_file = /etc/pki/tls/private/client.example.com.key
smtp_tls_loglevel = 3
smtp_tls_note_starttls_offer = yes
smtp_tls_security_level = may
tls_random_source = dev:/dev/urandom
unknown_local_recipient_reject_code = 550

Contents of relay_clientcerts on the server (this matches exactly the fingerprint in the logs and the output of the openssl x509 -fingerprint ... command):

12:34:56:78:90:AB:CD:EF:FE:DC:BA:09:87:65:43:21:C0:DE:BE:EF client.example.com

Outbound mail being initiated on the client via mail:

mail -s "Hello world" myemail@outside.org
hello world
.

Log output from the server:

Nov 30 21:40:39 server postfix/smtpd[7859]: client.example.com[192.168.1.1]: subject_CN=client.example.com, issuer=ca.example.com, fingerprint=12:34:56:78:90:AB:CD:EF:FE:DC:BA:09:87:65:43:21:C0:DE:BE:EF, pkey_fingerprint=XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
Nov 30 21:40:39 server postfix/smtpd[7859]: Trusted TLS connection established from client.example.com[192.168.1.1]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
Nov 30 21:40:39 server postfix/smtpd[7859]: NOQUEUE: reject: RCPT from client.example.com[192.168.1.1]: 454 4.7.1 <myemail@outside.org>: Relay access denied; from=<root@client.example.com> to=<myemail@outside.org> proto=ESMTP helo=<client.example.com>
Nov 30 21:40:39 server postfix/smtpd[7859]: disconnect from client.example.com[192.168.1.1]

Log output from the client:

Nov 30 21:40:39 client postfix/smtp[15525]: server.example.com[192.168.1.2]:25: subject_CN=server.example.com, issuer_CN=ca.example.com, fingerprint=XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX, pkey_fingerprint=XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
Nov 30 21:40:39 client postfix/smtp[15525]: Trusted TLS connection established to server.example.com[192.168.1.2]:25: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
Nov 30 21:40:39 client postfix/smtp[15525]: 563502306537: to=<myemail@outside.org>, relay=server.example.com[192.168.1.2]:25, delay=431, delays=430/0.02/0.07/0.11, dsn=4.7.1, status=deferred (host server.example.com[192.168.1.2] said: 454 4.7.1 <myemail@outside.org>: Relay access denied (in reply to RCPT TO command))

Additional details:

  • Both systems have valid certificates signed by my internal CA
  • Both systems have valid A and PTR records
  • I can successfully query the fingerprint in the relay_clientcerts DB with postmap -q
  • Specifying smtpd_recipient_restrictions = permit_tls_clientcerts, permit_mynetworks, reject_unauth_destination and mynetworks = 127.0.0.0/8, 192.168.1.0/24 on the server does allow the client to relay mail through the server with no problem

I've pored over the Postfix documentation, the postfix-users mailing list archive, and Google in general and my configuration appears correct to me (at least correct enough to work). My understanding is that the combination of permit_tls_clientcerts and relay_clientcerts should be sufficient to allow the relay. Obviously, I'm either wrong or just not seeing it.

What am I missing that is preventing the server from allowing the relay based on the client's fingerprint?

Best Answer

I continued to dig around in the Postfix documentation and stumbled on the answer:

In Postfix 2.10, a new configuration parameter called smtpd_relay_restrictions was introduced to address issues where permissive spam-blocking policies in smtpd_recipient_restrictions resulted in permissive relay policies. Per the documentation (http://www.postfix.org/postconf.5.html#smtpd_relay_restrictions), this parameter accepts the same values, and should "preferably" be used to configure the relay policy:

As of Postfix 2.10, relay permission rules are preferably implemented with smtpd_relay_restrictions, so that a permissive spam blocking policy under smtpd_recipient_restrictions will no longer result in a permissive mail relay policy.

...

Specify a list of restrictions, separated by commas and/or whitespace. Continue long lines by starting the next line with whitespace. The same restrictions are available as documented under smtpd_recipient_restrictions.

What was not immediately apparent (to me, at least), was that the smtpd_relay_restrictions parameter has a default value of permit_mynetworks, permit_sasl_authenticated, defer_unauth_destination (as revealed by running postconf with no options), and overrides smtpd_recipient_restrictions completely when it has a non-empty value. From the documentation:

For backwards compatibility, sites that migrate from Postfix versions before 2.10 can set smtpd_relay_restrictions to the empty value, and use smtpd_recipient_restrictions exactly as before.

The solution, therefore, is to either set smtpd_relay_restrictions to the empty value in main.cf and utilize smtpd_recipient_restrictions as with previous versions, or to configure the relay policy using the new parameter. I chose the latter, and certificate-based relay is now working as expected.