Reverse Proxy with Dovecot – How to Use Dovecot as a Proxy with SMTP Auth

dovecotreverse-proxysmtp-auth

In my infrastructure I have several mailservers (mailcow) serving different domains per instance. I want to build a mail-proxy in front of them to reduce the number of used IPs per service and allow customers to have their own domain names in their client presets anyway.

SMTP as MTA is handled differently. Incoming messages via Postfix are handled by a central server (because MX records are not visible for the customer). So this is not my problem.

So I've configured a mail proxy based on Dovecot on Debian Buster with the following config:

ssl_cert = </etc/dovecot/ssl/default.pem
ssl_key = </etc/dovecot/ssl/default.key

# just an example for different domains via SNI
local_name mail.domain1.tld {
  ssl_cert = </etc/dovecot/ssl/mail.domain1.tld.pem
  ssl_key = </etc/dovecot/ssl/mail.domain1.tld.key
}

# just an example for different domains via SNI
local_name mail.domain2.tld {
  ssl_cert = </etc/dovecot/ssl/mail.domain2.tld.pem
  ssl_key = </etc/dovecot/ssl/mail.domain2.tld.key
}

auth_cache_size = 4 k
disable_plaintext_auth = no

passdb {
  args = /etc/dovecot/sql.conf
  driver = sql
}
protocols = "imap pop3 submission"
service auth {
  user = root
}
userdb {
  args = static uid=5000 gid=5000 home=/dev/null
  driver = static
}

And the sql.conf is

## SQL passdb configuration
driver = mysql

# Database options
connect = host=localhost dbname=dovecot user=dovecot password=dovecot

# Query
password_query = SELECT NULL AS password, NULL AS destuser, host, 'Y' AS nologin, 'Y' AS nodelay, 'Y' AS nopassword, 'Y' AS proxy, 'any-cert' AS `ssl` FROM proxy_domain WHERE domain = '%d'
# eof

The database contains:

CREATE TABLE `proxy_domain` (
  `domain` varchar(255) NOT NULL,
  `host` varchar(255) NOT NULL,
  PRIMARY KEY (`domain`)
);

insert into proxy_domain (domain, host) values ('domain1.tld','mailhost1');
insert into proxy_domain (domain, host) values ('domain2.tld','mailhost2');

This is more or less the example of

The IMAP and POP3 services are up and with

openssl s_client -connect ac-hcn0002.acoby.net:993

I'm able to login and also SNI is working fine. The backend is reachable via SSL. With starttls (110, 143, 587) only the first certificate is presented. That's ok and acceptable, because I would not recommend that to the customer.

But now submission (and later sieve).

Question #1:

Dovecot is able to open 587 for submission. That is only available via STARTTLS. But the proxy then tries to communicate for submission on the backend system direct with SSL on port 587 (which is not correct, I think – it should start plain and make STARTTLS).
I think, this happens, because the passdb returns global SSL=any-cert. Is this a bug? Can I override that behaviour for 587? And maybe is there a way to send the correct certificate with STARTTLS (instead of the default/first)?

Question #2:

Then port 465. Dovecot could also open the submission port 465/SSL in my case for forwarding all authenticated messages to the 465 submission port on backend. But how can I configure that? I couldn't find any example.

I know about Mail infrastructure with dovecot proxy and the solution with postfix – but I'm not really sure, if the answer with the dovecot-socket is working in this scenario and I don't want to install a postfix only for submission, when Dovecot can handle that out-of-the-box.

Best Answer

By returning 'any-cert' AS 'ssl' in your passdb, you force dovecot to use TLS for downstream connections. Unfortunatly there is no way that I know of to change the connection type between starttls or tls based on something that passdb returns (https://dovecot.org/pipermail/dovecot/2018-September/112928.html)

My Workaround is to force STARTTLS Connections downstream and always use that.

password_query = SELECT NULL as password, 'y' as nopassword, 'y' as proxy, NULL as destuser, 'y' as proxy_nopipelining, host, 'y' as nodelay, 'y' as nologin, 'any-cert' as 'starttls';

The "correct" query would be something like this:

password_query = SELECT NULL as password, 'y' as nopassword, 'y' as proxy, NULL as destuser, 'y' as proxy_nopipelining, host, 'y' as nodelay, 'y' as nologin, IF(%{real_lport}=587, 'any-cert', 'no') as 'starttls', IF(%{real_lport}<>587, 'any-cert', 'no') as 'ssl';

which would switch starttls/tls based on the port the connection came in. Unfortunatly thats currently not supported by dovecot.