ADFS 3.0 for Office 365: lessons from multi-domain federation

Field notes on ADFS 3.0 federated authentication for Office 365: WAP proxies, certificate rollover, UPN suffix cleanup, and multi-domain federation.

Last month we walked through the assessment phase of a 15,000-mailbox Office 365 migration for a state government agency. The mailboxes are the visible part of that program. The part that actually determines whether anyone can log in on cutover morning is identity, and for this client that means ADFS 3.0 on Windows Server 2012 R2, federating seven verified domains into one Office 365 tenant.

Federated authentication for Office 365 gets described in most vendor decks as a checkbox: run the wizard, done. It is not a checkbox. It is a tier-0 dependency that you are inserting between every user and their mail, and it has more sharp edges than any other component in the migration. These are our field notes from standing it up, breaking it in the lab, and running it through two certificate rollovers.

One framing note before the details: everything below assumes you have already decided you need federation. A lot of organizations do not, and Azure AD Connect with password synchronization is a perfectly respectable answer for them. This client was not one of them.

Why "just use password sync" wasn't acceptable

We had this argument early, because password sync is genuinely simpler and we would rather run simple systems. Azure AD Connect has supported password hash synchronization since it shipped last year, and for a commercial mid-market client we will usually recommend it.

The agency's security office killed it in one meeting, for three reasons that we could not argue with. First, policy: no derivative of a domain credential leaves the state network, full stop, and no amount of explaining the double-hashing scheme moved them. Second, control: with federation, disabling an account in Active Directory takes effect at the ADFS farm within minutes; with password sync there is a window where the cloud session outlives the on-premises disable. Third, they wanted their existing logon-hours restrictions and smart card pilot to keep working, and those are claims-side conversations, not sync-side ones.

So: federation. We still deployed Azure AD Connect for directory synchronization — you need it regardless, federation only handles authentication — and we deliberately left password sync disabled rather than enabling it as a "backup." The security office's position was that a backup credential path is just a second credential path. We noted our disagreement in the design doc and moved on. Consultants advise; clients decide.

The farm: four servers, two tiers, no shortcuts

The topology is deliberately boring. Two ADFS 3.0 servers on Windows Server 2012 R2 in the internal network behind a load balancer VIP, and two Web Application Proxy servers in the DMZ, also load balanced. WID (the Windows Internal Database) for configuration, not SQL — at seven relying party trusts and one real workload, SQL buys you token replay detection and artifact resolution that this deployment does not need, and it adds a database team to your 3 a.m. call tree.

Things that bit us or nearly did:

  • The WAP trust is a certificate, and it expires. The proxy trust between WAP and the ADFS backend renews itself automatically — as long as the proxies can reach the backend on 443 continuously. Let a DMZ firewall rule lapse for a couple of weeks and you will be re-running Install-WebApplicationProxy on a Saturday.
  • Load balancer health probes must not terminate SSL. We probe /adfs/probe on port 80, which exists for exactly this purpose. The first draft from the network team probed the sign-in page over 443 and marked both nodes down every time the certificate changed.
  • Service Principal Name. The ADFS service account needs the host/sts.agency.example SPN, and if a previous pilot registered it against another account, Kerberos silently fails and everything falls back to forms in ways that confuse users and engineers equally. setspn -X before you deploy, not after.
  • Extended Protection. Older third-party SSL inspection between clients and the internal farm breaks Extended Protection TokenCheck. We kept the inspection appliance out of the ADFS path entirely rather than weakening the setting.

Capacity was a non-event. Two mid-sized VMs per tier handle 15,000 users' worth of token issuance without noticing; ADFS is not where the hardware money goes.

UPN suffix cleanup: the unglamorous prerequisite

Office 365 signs users in by UPN. The agency, like every organization assembled from twenty years of mergers and sub-agencies, signed users in by DOMAIN\samAccountName and had UPNs that were an archaeological record: .local suffixes, a defunct agency name from a 2004 reorg, and about 900 accounts where the UPN matched nothing routable at all.

The rule is simple: every user's UPN suffix must be a domain you have verified in the tenant, and ideally the UPN should equal the primary SMTP address, because users will type their email address at the sign-in page no matter what you tell them. Getting there took six weeks of the overall program:

Get-ADUser -Filter * -Properties userPrincipalName, mail |
  Where-Object ($_.userPrincipalName -notlike "*@agency.example") |
  Export-Csv .\upn-remediation.csv -NoTypeInformation

The export is the easy part. The hard part is the exceptions: service accounts that applications authenticate with using the UPN (we found two — one document management system, one aging fax integration), and a SQL Reporting Services install that had a UPN string in a connection config. Change those UPNs blind and you have created an outage in a system nobody remembers owning. We changed UPNs in batches of 500, department by department, with a two-week soak per batch, and we still caught one LOB application by surprise. Budget for that.

Federating the second through seventh domain

One domain federates with the wizardry Microsoft gives you. Multiple domains against one ADFS farm require the SupportMultipleDomain switch, and this is where most of the multi-domain pain lives.

Set-MsolADFSContext -Computer adfs01.agency.example
Convert-MsolDomainToFederated -DomainName subagency.example -SupportMultipleDomain

What SupportMultipleDomain actually does is change the token issuance rules so that the issuer ID in the token is derived from the user's UPN suffix rather than being a single static URI. Two consequences follow. First, if your original domain was federated without the switch, converting the second domain reconfigures the claim rules, and you should plan that as a change window, not a lunchtime tweak — we did it at 6 a.m. with the service desk pre-briefed and it was a non-event, but only because we had rehearsed the rollback (Convert-MsolDomainToStandard) in the lab.

Second, the issuance transform rule that generates the issuer ID from the UPN suffix is now load-bearing, and any admin who "cleans up" claim rules on the Office 365 relying party trust can break sign-in for six of your seven domains while the first one keeps working. We documented the rules, exported them with Get-AdfsRelyingPartyTrust, and put a standing change-control freeze on that trust.

One more multi-domain subtlety: subdomains. If you federate agency.example, child domains like mail.agency.example inherit its federation configuration when added, whether that is what you wanted or not. Map the whole domain tree before you start converting.

Certificate rollover: the outage you schedule for yourself

ADFS involves three certificates and they fail differently. The SSL certificate on the farm and the WAPs is ordinary operational work — although remember it lives in four places plus the load balancers, and the WAP binding is updated with netsh http bindings, not IIS, because there is no IIS on a WAP.

The token-signing and token-decrypting certificates are the interesting ones. By default ADFS self-manages them with AutoCertificateRollover: twenty days before expiry it generates new certificates, publishes them as secondary, and later promotes them. Elegant — except Office 365 does not automatically learn about the new token-signing certificate unless something tells it. That something is:

Update-MSOLFederatedDomain -DomainName agency.example -SupportMultipleDomain

run once per federated domain. Miss it, and on promotion day Azure AD starts rejecting tokens signed by a certificate it has never seen, and 15,000 people cannot open Outlook. We have now seen this failure mode at two organizations that inherited ADFS from a departed contractor and had no idea a clock was ticking.

Our standing operational answer: a monitored scheduled task that checks Get-AdfsCertificate daily and alerts at 45 days out, a runbook that pairs the certificate promotion with the Update-MSOLFederatedDomain loop across all seven domains, and a calendar entry with a named owner. It is not sophisticated. It merely has to exist.

What we'd change next time

Honest ledger. We would do the UPN remediation even earlier — it gated pilot mailbox moves we could otherwise have started. We would push harder for a third ADFS node across town; two nodes in one datacenter is a fine SLA until the datacenter has a bad day, and federation means authentication is down when ADFS is down. That conversation is easier to have before go-live than after.

And we would set expectations about what federation costs in operational maturity. Password sync fails soft — sync breaks, passwords go stale, users keep working. Federation fails hard and all at once. If an organization does not have monitoring, change control, and an on-call rotation that can own a tier-0 service, that — not security philosophy — should drive the decision.

If you're facing this

We have built and operated ADFS farms behind Office 365 tenants from a few hundred seats to fifteen thousand, in environments where "just sync the passwords" was never going to clear security review. If you are staring down a multi-domain federation design, a UPN cleanup, or an inherited farm with certificates of unknown age, get in touch — we have probably already made the mistake you are about to.

// related notes
// still relevant?

Facing a migration, platform, or AI build like this one?

This note is part of an archive spanning a decade of infrastructure work. The playbook evolved; the discipline didn't. Tell us what you're trying to ship — we reply within one business day.

Start a project →

← Back to notes