The Cisco Email Security Appliance (ESA) is well-known for its very good Anti-Spam features. But it completely lacks a usable implementation for mail encryption with S/MIME or OpenPGP. That is: We are using other appliances for that such as Zertificon, SEPPmail, or totemo.
However, the Cisco ESA still remains the main MTA for incoming and outgoing mails, hence mails must be routed to the encryption appliance of your choice for signing/encrypting (outgoing) or verifying/decrypting (incoming) mails. Such mail routings should be done with CLI-only message filters, rather than content filters. Here we go:
Why Message Filter?
Message filters are processed before the email security manager with all of its components such as Anti-Spam, Anti-Virus, AMP, and so on. Using message filters here gives the chance to alter the mail flow even before Anti-Spam kicks in. This results in a good mail flow design since checking a fully encrypted mail for Spam is ridiculous. ;) That’s why you should not use content filters that are executed after that Anti-xyz stuff for these scenarios.
Mail Flow Design
There are many different possible mail flow designs. My goal was to unambiguously receive mails from the encryption appliance. I wanted to have different firewall policies between the appliances matching the SMTP sessions exactly along the path. You can either use
- own IP Interfaces (that is: Layer 3 addresses on Ethernet ports),
- own Listeners (that is: using an already available IP Interface but with a different listening port), or
- nothing of those two methods, but filter only for the sending remote-ip.
I personally prefer the second one: own listeners for the encryption appliance. That is: I am using two more listeners on port 2525 of the original Incoming/Outgoing interfaces aka IP addresses. Here’s a sketch:
Cisco ESA Configuration
So here we go: 1) The new “L_Securemail_Incoming” listener of type public on the If_Incoming IP address but with listening port 2525. The RAT default action is “Accept” (since it will only receive already accepted mails) and the HAT WHITELIST has a single sender of the IP address of the encryption appliance. Spam detection and virus protection is enabled since this is the first point at which the ESA sees the mail in plaintext.
2) The new “L_Securemail_Outgoing” listener of type private on the If_Outgoing IP address but with TCP port 2525 again. This time, the HAT RELAYLIST gets a single sender with the IP address of the encryption appliance again. Spam detection and virus protection is turned off (!) since this listener receives already checked mails (in the first place) while they are likely encrypted.
3) The message filter for incoming mail. In fact, I am using three distinct message filters for it with different kinds of conditions. All are forwarding the mail to the encryption appliance from the If_Incoming interface, adding a log-entry, and skipping all checks:
EncryptionAppliance-decrypt-filename-20210803: if (recv-listener == "L_Mail_Incoming") AND (attachment-filename == "(?i)\\.(asc|pgp|gpg|p7(c|m|s){0,1})$") { alt-mailhost ("[198.51.100.25]"); alt-src-host ("If_Incoming"); log-entry("Forwarded to securemail due to message filter EncryptionAppliance-decrypt-filename"); skip-spamcheck(); skip-marketingcheck(); skip-socialcheck(); skip-bulkcheck(); skip-viruscheck(); skip-ampcheck(); skip-outbreakcheck(); skip-filters(); } EncryptionAppliance-decrypt-body-20210803: if (recv-listener == "L_Mail_Incoming") AND ((body-contains("[-][-][-][-][-]BEGIN PGP", 1)) OR ((body-contains("[-][-][-][-][-]BEGIN\\=20PGP", 1)) OR ((body-contains("LS0tLS1CRUdJTiBQR1Ag", 1)) OR ((body-contains("LS0tQkVHSU4gUEdQI", 1)) OR ((body-contains("LS0tLUJFR0lOIFBHUC", 1)) OR (body-contains("\\*PGP", 1))))))) { alt-mailhost ("[198.51.100.25]"); alt-src-host ("If_Incoming"); log-entry("Forwarded to securemail due to message filter EncryptionAppliance-decrypt-body"); skip-spamcheck(); skip-marketingcheck(); skip-socialcheck(); skip-bulkcheck(); skip-viruscheck(); skip-ampcheck(); skip-outbreakcheck(); skip-filters(); } EncryptionAppliance-decrypt-apptype-20210803: if (recv-listener == "L_Mail_Incoming") AND ((encrypted) OR ((attachment-type == "application/pgp-keys") OR ((attachment-type == "application/pgp-encrypted") OR ((attachment-type == "application/pkcs10") OR ((attachment-type == "application/pkcs7-signature") OR ((attachment-type == "application/x-pkcs7-signature") OR ((attachment-type == "application/x-pkcs7-mime") OR ((attachment-type == "multipart/encrypted") OR ((attachment-type == "multipart/signed") OR (attachment-type == "application/pkcs7-mime")))))))))) { alt-mailhost ("[198.51.100.25]"); alt-src-host ("If_Incoming"); log-entry("Forwarded to securemail due to message filter EncryptionAppliance-decrypt-apptype"); skip-spamcheck(); skip-marketingcheck(); skip-socialcheck(); skip-bulkcheck(); skip-viruscheck(); skip-ampcheck(); skip-outbreakcheck(); skip-filters(); }
4) The message filter for outgoing mail. A little easier:
EncryptionAppliance-encrypt-out-20210803: if (recv-listener == "L_Mail_Outgoing") { alt-mailhost ("[198.51.100.25]"); alt-src-host ("If_Outgoing"); log-entry("Forwarded to securemail due to message filter EncryptionAppliance-encrypt-out"); }
If you want to limit the mail flow for certain Active Directory groups, you can use the filter condition (mail-from-group == "NameOfTheGroup").
Reminder: To add the message filter, you have to log into the ESA via SSH. The CLI commands are as follows:
filters 1 (to enter Clustermode, only if you're running a cluster) NEW <paste-message-filter-here> .
To view the message filters, type LIST or DETAIL, followed by the number of the filters. And don’t forget to commit at the end.
That’s it. ;) Happy mail flowing. God’s blessing!
Photo by Maksym Tymchyk on Unsplash.