mirror of
https://github.com/chillout2k/ExOTA-Milter.git
synced 2025-12-12 18:00:19 +00:00
Docs; more logging
This commit is contained in:
parent
da1b91b7e3
commit
04c440624b
24
README.md
24
README.md
@ -37,7 +37,7 @@ Microsoft provides an ACL as [JSON file (ID: 10)](https://endpoints.office.com/e
|
||||
[...]
|
||||
```
|
||||
|
||||
The problem of this IP based ACL is that many other Exchange-Online customers/tenants are sending from the same IP-ranges as well! **This means that nearly any Exchange-Online smarthost tends to be an open relay unless additional authentication mechanism on a higher layer than IP takes place! IP-ACLs are definitely not enough!**
|
||||
The problem of this IP based ACL is that many other Exchange-Online customers/tenants are sending from the same IP-ranges as well! **This means that many smarthost configured to relay mails comming from Exchange-Online tends to be an open relay (for Microsoft customers) unless additional authentication mechanism on a higher layer than IP takes place! IP-address based ACLs are definitely not the right way to achieve this!**
|
||||
|
||||
## x509 client certificate presented by Exchange-Online
|
||||
The Exchange-Online platform also *presents* a x509 client certificate to identitfy onself to the smarthost. Taking a closer look at the received header we´ll notice that the certificates common name (CN) *mail.protection.outlook.com* is not realy tenant specific. Although the certificate provides additional security regarding the identity of the client system, it does not provide identity regarding the tenant. **IMHO that´s stil not enough to permit relaying!**
|
||||
@ -70,14 +70,24 @@ Authentication-Results: trusted.dkim.validating.relay; dkim=pass header.d=tenan
|
||||
[...]
|
||||
```
|
||||
|
||||
## Microsoft tenant-ID
|
||||
Further each Microsoft Exchange-Online tenant has a unique tenant-ID in form of a UUID ([RFC 4122](https://tools.ietf.org/html/rfc4122)). **ExOTA-Milter** determines the tenant-ID from the *X-MS-Exchange-CrossTenant-Id* email header and uses it as an *mandatory* authentication factor.
|
||||
## X-MS-Exchange-CrossTenant-Id header
|
||||
Further each Microsoft Exchange-Online tenant has a unique tenant-ID in form of a UUID ([RFC 4122](https://tools.ietf.org/html/rfc4122)). **ExOTA-Milter** determines the tenant-ID from the *X-MS-Exchange-CrossTenant-Id* email header and uses it as a *mandatory* authentication factor.
|
||||
```
|
||||
[...]
|
||||
X-MS-Exchange-CrossTenant-Id: <UUID-of-tenant>
|
||||
[...]
|
||||
```
|
||||
|
||||
# The solution
|
||||
The answer to the question "*How can an Exchange-Online user/tenant be identified by a smarthost?*" can be answered as follows.
|
||||
So, *how can an Exchange-Online user/tenant be identified by a third party smarthost?*
|
||||
|
||||
Finally it´s the combination of all of the above discussed aspects which result in a robust-enough smarthost setup for the Exchange-Online platform:
|
||||
Finally it´s the combination of all of the above discussed aspects which may result in a robust-enough smarthost setup used by the Exchange-Online platform:
|
||||
* restriction of client IPs via ACL (MTA)
|
||||
* verification of Microsoft´s x509 client certificate + CN (MTA + ExOTA-Milter)
|
||||
* verification of Microsoft´s x509 client certificate (MTA)
|
||||
* matching for client certificate´s CN (ExOTA-Milter)
|
||||
* verification of DKIM signatures providing *Authentication-Results* header (another milter)
|
||||
* consideration of DKIM verification results per sender domain (ExOTA-Milter)
|
||||
* matching of tenant-id provided in email header (ExOTA-Milter)
|
||||
* matching for tenant-id provided in *X-MS-Exchange-CrossTenant-Id* header (ExOTA-Milter)
|
||||
|
||||
# How to start?
|
||||
First of all please take a look at how to set up the testing environment, which is described [here](tests/README.md)
|
||||
@ -249,12 +249,17 @@ class ExOTAMilter(Milter.Base):
|
||||
)
|
||||
self.setreply('550','5.7.1', g_milter_reject_message)
|
||||
return Milter.REJECT
|
||||
|
||||
logging.info(self.mconn_id + "/" + self.getsymval('i') +
|
||||
"/EOM: Tenant authentication successful (dkim_enabled={0})".format(
|
||||
str(policy.is_dkim_enabled())
|
||||
|
||||
if g_milter_dkim_enabled:
|
||||
logging.info(self.mconn_id + "/" + self.getsymval('i') +
|
||||
"/EOM: Tenant authentication successful (dkim_enabled={0})".format(
|
||||
str(policy.is_dkim_enabled())
|
||||
)
|
||||
)
|
||||
else:
|
||||
logging.info(self.mconn_id + "/" + self.getsymval('i') +
|
||||
"/EOM: Tenant successfully authenticated"
|
||||
)
|
||||
)
|
||||
return Milter.CONTINUE
|
||||
|
||||
def abort(self):
|
||||
@ -289,34 +294,32 @@ if __name__ == "__main__":
|
||||
g_milter_socket = os.environ['MILTER_SOCKET']
|
||||
if 'MILTER_REJECT_MESSAGE' in os.environ:
|
||||
g_milter_reject_message = os.environ['MILTER_REJECT_MESSAGE']
|
||||
logging.info("ENV[MILTER_REJECT_MESSAGE]: {0}".format(g_milter_reject_message))
|
||||
if 'MILTER_TMPFAIL_MESSAGE' in os.environ:
|
||||
g_milter_tmpfail_message = os.environ['MILTER_TMPFAIL_MESSAGE']
|
||||
logging.info("ENV[MILTER_TMPFAIL_MESSAGE]: {0}".format(g_milter_tmpfail_message))
|
||||
if 'MILTER_DKIM_ENABLED' in os.environ:
|
||||
g_milter_dkim_enabled = True
|
||||
logging.info("DKIM signature authorisation enabled")
|
||||
if 'MILTER_TRUSTED_AUTHSERVID' in os.environ:
|
||||
g_milter_trusted_authservid = os.environ['MILTER_TRUSTED_AUTHSERVID'].lower()
|
||||
logging.info("Trusted AuthServID: " + g_milter_trusted_authservid)
|
||||
logging.info("ENV[MILTER_TRUSTED_AUTHSERVID]: {0}".format(g_milter_trusted_authservid))
|
||||
else:
|
||||
logging.error("ENV[MILTER_TRUSTED_AUTHSERVID] is mandatory!")
|
||||
sys.exit(1)
|
||||
logging.info("ENV[MILTER_DKIM_ENABLED]: {0}".format(g_milter_dkim_enabled))
|
||||
if 'MILTER_X509_ENABLED' in os.environ:
|
||||
g_milter_x509_enabled = True
|
||||
logging.info("x509 client certificate CN validation enabled")
|
||||
if 'MILTER_X509_TRUSTED_CN' in os.environ:
|
||||
g_milter_x509_trusted_cn = os.environ['MILTER_X509_TRUSTED_CN']
|
||||
logging.info("Trusted x509 client CN: '{0}'".format(
|
||||
g_milter_x509_trusted_cn
|
||||
))
|
||||
else:
|
||||
logging.info("ENV[MILTER_X509_TRUSTED_CN]: using default '{0}'".format(
|
||||
g_milter_x509_trusted_cn
|
||||
))
|
||||
logging.info("ENV[MILTER_X509_TRUSTED_CN]: {0}".format(g_milter_x509_trusted_cn))
|
||||
logging.info("ENV[MILTER_X509_ENABLED]: {0}".format(g_milter_x509_enabled))
|
||||
if 'MILTER_POLICY_SOURCE' in os.environ:
|
||||
g_milter_policy_source = os.environ['MILTER_POLICY_SOURCE']
|
||||
logging.info("ENV[MILTER_POLICY_SOURCE]: {0}".format(g_milter_policy_source))
|
||||
if g_milter_policy_source == 'file':
|
||||
if 'MILTER_POLICY_FILE' in os.environ:
|
||||
g_milter_policy_file = os.environ['MILTER_POLICY_FILE']
|
||||
logging.info("ENV[MILTER_POLICY_FILE]: {0}".format(g_milter_policy_file))
|
||||
try:
|
||||
g_milter_policy_backend = ExOTAPolicyBackendJSON(g_milter_policy_file)
|
||||
logging.info("JSON policy backend initialized")
|
||||
|
||||
@ -1,4 +1,16 @@
|
||||
# prepare testing env
|
||||
# Prepare testing env
|
||||
First of all, please configure a python virtual environment and install all necessary python packages listed under `requirements.txt`. Go to the root-directory of this repo and
|
||||
1. `python3 -m venv venv`
|
||||
1. `. venv/bin/activate`
|
||||
1. `pip3 install -r requirements.txt`
|
||||
|
||||
It´s not realy neccessary to configure a fully functional milter-aware MTA to see **ExOTA-Milter** in action. All you need is
|
||||
* a binary called `miltertest`. Under debian based distros it´s located in the `opendkim-tools` package.
|
||||
* a lua-script for miltertest: `tests/miltertest.lue`
|
||||
* an **ExOTA-Milter** policy JSON-file: `tests/policy.json`
|
||||
|
||||
Except for the `miltertest` binary you´ll find all mandatory resources to run a test in this repo.
|
||||
|
||||
```
|
||||
export LOG_LEVEL=debug
|
||||
export MILTER_SOCKET=/tmp/exota-milter
|
||||
@ -9,11 +21,15 @@ export MILTER_X509_ENABLED=yepp
|
||||
export MILTER_X509_TRUSTED_CN=mail.protection.outlook.com
|
||||
```
|
||||
|
||||
# start milter
|
||||
`python3 app/exota-milter.py`
|
||||
# Shell-1: start ExOTA-Milter
|
||||
```
|
||||
. venv/bin/activate
|
||||
python3 app/exota-milter.py
|
||||
```
|
||||
|
||||
# execute `miltertest`
|
||||
First of all install the `miltertest` binary. Under debian based distros
|
||||
it´s located in the `opendkim-tools` package.
|
||||
# Shell-2: execute `miltertest`
|
||||
This must be done only once: `export MILTER_SOCKET=/tmp/exota-milter`
|
||||
|
||||
Execute miltertest pointing to the test script written in lua to feed the **ExOTA-Milter**:
|
||||
|
||||
`miltertest -v -D socket="${MILTER_SOCKET}" -s tests/miltertest.lua`
|
||||
Loading…
Reference in New Issue
Block a user