This How-To aims at bringing some help regarding the initial installation and configuration of Perdition. Instructions are tested on GNU/Linux Debian. They should work on any Debian-derived distribution, or with some tweaks here and there, to any GNU/Linux distribution.
The Perdition package from Debian 11 has a bug that prevents it from being successfully installed or removed if it isn’t present already (i.e. it’s fine if the system was upgraded from Debian 10 to Debian 11).
Perdition itself works fine.
A manual modification is required during package installation.
For more information, you can read this bug report from Debian’s BTS.
I’ll remove this warning once the package’s maintainer fixes this bug.
Perdition is an Open Source reverse proxy for IMAP and POP servers. In more complex setups, it can also be used to forward client requests to different servers based on the user’s domain.
Upon connection from a client, Perdition gets the LOGIN command and forwards it to the designated server. If the connection is successful, Perdition keeps it open and pipes the client’s commands through it. But if it isn’t, Perdition closes both connections, from the client and to the distant server.
In order to listen for connections from POP and IMAP clients, Perdition spawns several processes, one for each protocol.
In my use case, I have an IMAP server (Dovecot) running on a Debian VM in an internal network area.
My networking policy strictly forbids connections from the WAN area to any internal network area. There is a DMZ designed for that purpose, with a UTM and a second firewall solution securing and monitoring connections from and to it.
Perdition will be configured on a Debian VM sitting in the DMZ, with appropriate UTM rules allowing connections from this machine to the internal Dovecot instance.
Since I do not use POP, Perdition will be configured to listen for IMAPS connections only. Perdition will then forward to the internal Dovecot listening on plain IMAP. Doing so:
- Ensures that the LOGIN values used as credentials are encrypted while traveling to Perdition;
- Ensure that Perdition’s responses will be encrypted as well;
- Ensures that the SSL certificate and private key is only on the machine hosting Perdition, relieving the burden of SSL from Dovecot;
- Reduces the attack surface as Perdition will not listen to plain IMAP, plain POP or POPS connections;
- Allows the UTM to inspect the traffic from Perdition to Dovecot without having to decrypt anything and, if suspicious IMAP commands are issued, kill the connection and block the offender.
As Perdition is available in the main stable repository, it is only a
# apt install perdition
The overall behavior of Perdition is defined in the
/etc/default/perdition file. By modifying it, it will be possible to specify which processes get spawned and for which intended protocol. As I only want to use IMAPS, the following modifications are made:
And after issuing
# systemctl restart perdition
you should be able to verify that only one process is running, waiting for IMAPS connections:
# systemctl status perdition ● perdition.service - LSB: POP, IMAP and managesieve proxy Loaded: loaded (/etc/init.d/perdition; generated) Active: active (running) since Sat 2022-02-05 18:59:20 CET; 1 weeks 6 days ago Docs: man:systemd-sysv-generator(8) Tasks: 1 (limit: 2343) Memory: 2.0M CPU: 2min 3.229s CGroup: /system.slice/perdition.service └─617 perdition.imaps: daemon
If you want to further configure Perdition for handling multiple servers for different domains, you will also have to edit
/etc/perdition/popmap but this is out of this How-To’s scope.
We now have to configure the
perdition.imaps daemon. Each daemon gets its configuration from a corresponding file in
For IMAPS, the file will be
Here’s a (working) configuration snippet:
outgoing_server [IP OF DOVECOT SERVER] outgoing_port 143 lower_case all connection_limit 100 no_lookup timeout 30 #debug imap_capability "IMAP4rev1 LOGIN-REFERRALS ID ENABLE IDLE LITERAL+" ssl_mode ssl_listen ssl_cert_file /path/to/cert.pem ssl_key_file /path/to/key.pem ssl_dh_params_file /path/to/dhparm.pem
outgoing_server: the distant server, here my internal Dovecot instance;
outgoing_port: the port on which to forward to, here IMAP;
lower_case: normalize strings by lowering caps;
connection_limit: allow a certain amount of parallel connections;
no_lookup: do not resolve names, implies that IP addresses are used;
debug: allow extra debug output (including passwords) in the log file and the Journal. Commented out for privacy reasons when things run fine;
imap_capability: list of IMAP capabilities that Perdition will advertise when the client issues the CAPABILITY command;
ssl_mode: work in SSL or TLS mode;
ssl_*_file: path to cert and key.
And now, putting it all together:
# systemctl restart perdition # systemctl status perdition ● perdition.service - LSB: POP, IMAP and managesieve proxy Loaded: loaded (/etc/init.d/perdition; generated) Active: active (running) since Fri 2022-02-18 21:34:06 CET; 2s ago Docs: man:systemd-sysv-generator(8) Process: 180117 ExecStart=/etc/init.d/perdition start (code=exited, status=0/SUCCESS) Tasks: 1 (limit: 2343) Memory: 908.0K CPU: 121ms CGroup: /system.slice/perdition.service └─180125 perdition.imaps: daemon févr. 18 21:34:06 [REDACTED] systemd: Starting LSB: POP, IMAP and managesieve proxy... févr. 18 21:34:06 [REDACTED] perdition.imaps: Starting perdition version=2.2 protocol=IMAP4S févr. 18 21:34:06 [REDACTED] perdition.imaps: Loaded Diffie-Hellman parameters: "[REDACTED].pem" févr. 18 21:34:06 [REDACTED] systemd: Started LSB: POP, IMAP and managesieve proxy. # ss -a | grep imaps tcp LISTEN 0 0 0.0.0.0:imaps 0.0.0.0:*
Now, configure your firewall appliance, UTM, local firewall (iptables) so that the IMAPS port is reachable from the outside world.
Here’s the trace of a successful manual login to the distant Dovecot using Perdition from an external machine:
~ % openssl s_client -connect mx.pierreblazquez.com:imaps CONNECTED(00000005) depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1 verify return:1 depth=1 C = US, O = Let's Encrypt, CN = R3 verify return:1 depth=0 CN = mx.pierreblazquez.com verify return:1 --- Certificate chain 0 s:/CN=mx.pierreblazquez.com i:/C=US/O=Let's Encrypt/CN=R3 1 s:/C=US/O=Let's Encrypt/CN=R3 i:/C=US/O=Internet Security Research Group/CN=ISRG Root X1 2 s:/C=US/O=Internet Security Research Group/CN=ISRG Root X1 i:/O=Digital Signature Trust Co./CN=DST Root CA X3 --- [...] * OK [CAPABILITY IMAP4rev1 LOGIN-REFERRALS ID ENABLE IDLE LITERAL+] perdition ready on [REDACTED] [REDACTED] a login [USERNAME] [PASSWORD] * CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE SNIPPET=FUZZY PREVIEW=FUZZY STATUS=SIZE SAVEDATE LITERAL+ NOTIFY SPECIAL-USE a OK You are so in a logout * BYE Logging out a OK Logout completed (0.001 + 0.000 secs).
openssl s_client -connect: use OpenSSL as a telnet-like program to connect to a port that requires SSL handshakes;
a login [USERNAME] [PASSWORD]: LOGIN command of the IMAP protocol (username and password being encrypted in the SSL channel);
a logout: LOGOUT command of the IMAP protocol.
As you can see, OpenSSL successfully established a connection to the IMAPS port after checking the presented certificate. Perdition replied that it is ready to accept commands, and successful LOGIN and LOGOUT mean that Dovecot received those commands with their values and successfully authenticated the user.
You should now have a working Perdition acting as a reverse proxy, reachable from the outside world and sitting in front of an IMAP server that stays (as much as possible) out of reach. Perdition should only have one instance running, listing on the IMAPS port, and relaying commands to the server’s IMAP port, in a way that this strictly internal and unencrypted traffic can be monitored for signs of break-in attempts while ensuring that the connection between Perdition and the client stays encrypted.
The Fail2ban package shipping in Debian contains a filter for Perdition. It’s easy to define a new jail in order to ban bad actors after a logged attempt:
[perdition] enabled = true port = imap,imaps,pop3,pop3s filter = perdition logpath = %(syslog_mail)s action = %(action_mwl)s