Guides / security
When a constraint improves the design: rebuilding a cloud filter
No tenant meant no cloud mail filtering. Rebuilding it locally taught more: activating a service shows where the switch is, rebuilding it shows what it does.
The plan called for configuring a cloud mail protection service as a smart host. The lab had no tenant and no public domain.
The obvious response is to skip that part and note it as untested. What happened instead produced the most useful architecture in the whole exercise, and it is worth reconstructing the sequence — not for Exchange, but because the shape of it recurs.
The sequence
- The path being followed configured a cloud mail protection service as a smart host.
- The available environment was entirely local: no tenant, no public domain.
- First finding: the service is not reproducible locally. It is a tenant feature, not a component you install. There is no package to download.
- Second finding: even routing through it was impractical. MX records on an internal DNS have no effect on how mail from the internet is routed — the record that matters is the public one, and there was no public domain to put it on.
- Rather than skip it, the decision was to rebuild locally the concepts that service implements in the cloud: first with Exchange’s native filtering engines, then with an open-source security gateway.
Why the substitute taught more than the original would have
The resulting architecture has every mechanism implemented, observed in the logs, and verified individually — rather than switched on from a cloud console.
Concretely, the substitution forced questions the managed version never poses:
- Which port does inbound mail arrive on, and which does outbound leave on? In the cloud that is decided for you. Locally it produced a
454 Relay access deniedand a real understanding of why port 25 refuses to relay for external domains. - What does the filter actually see? The Content Filter ignores authenticated internal mail. Nothing in a cloud console tells you that, because you never test from inside.
- Which connector wins? Routing picks the cheapest. A leftover connector with a lower cost silently took precedence over the correct path — a failure mode that only exists once you can create connectors yourself.
Declared gaps are worth more than hidden ones
Several things were genuinely not done. Listing them, with the reason, is more useful than quietly omitting them:
| Not done | Why | What it would take |
|---|---|---|
| Cloud mail protection configuration | Delivered only as a cloud service | A Microsoft 365 tenant, even a trial |
| Cutover migration | By definition moves mailboxes to the cloud | A tenant with Exchange Online |
| Hybrid configuration | Needs OAuth trust with the cloud identity service | A tenant and a verified public domain |
| Full MAPI over HTTP test | Needs integrated authentication from a domain-joined machine | An Outlook client on a domain member |
| Database availability group | Needs at least two mailbox servers | A seventh virtual machine |
| Load balancing | With one server there is no load to distribute | Two or more mailbox servers |
Three pieces of hygiene the lab left behind
Worth writing down, because a lab that is finished tends to stay in whatever state it ended in.
Symmetric filtering. The gateway currently filters only outbound mail. Placing it in front of the Edge server for inbound as well completes the model — and forces the gateway into the perimeter segment, which is where it architecturally belongs.
NOW Internet --> Edge --> Exchange
Exchange --> Edge --> gateway --> Internet
SYMMETRIC Internet --> gateway:25 --> Edge --> Exchange
Exchange --> Edge --> gateway:26 --> Internet
Reduced exposure. The firewall’s WAN interface was made genuinely reachable to test external access. Once that test is finished, it should go back behind NAT. An interface that is reachable is an exposure, and “we needed it for a test last month” is not a reason to keep one.
What the exercise was actually about
The value of a lab is not the list of components installed. It is the chain of reasoning it produced.
An apparently insurmountable constraint forced a design decision. That decision produced a more complex architecture. That complexity produced faults. And each fault, diagnosed down to its real cause, produced an understanding that a configuration working first time would never have given.