imPC@ndo IT

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

  1. The path being followed configured a cloud mail protection service as a smart host.
  2. The available environment was entirely local: no tenant, no public domain.
  3. First finding: the service is not reproducible locally. It is a tenant feature, not a component you install. There is no package to download.
  4. 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.
  5. 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 denied and 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 doneWhyWhat it would take
Cloud mail protection configurationDelivered only as a cloud serviceA Microsoft 365 tenant, even a trial
Cutover migrationBy definition moves mailboxes to the cloudA tenant with Exchange Online
Hybrid configurationNeeds OAuth trust with the cloud identity serviceA tenant and a verified public domain
Full MAPI over HTTP testNeeds integrated authentication from a domain-joined machineAn Outlook client on a domain member
Database availability groupNeeds at least two mailbox serversA seventh virtual machine
Load balancingWith one server there is no load to distributeTwo 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.