Documentazione di laboratorio
Laboratorio Exchange ibridoCom'è costruito, e perché così
Come leggere questo manuale
Questo non è un tutorial per costruire un laboratorio Exchange. È la documentazione di uno laboratorio: cosa contiene, perché ogni pezzo è fatto in quel modo, e cosa si è rotto durante la costruzione.
Se quello che cerchi sono i passi — dall'hypervisor vuoto all'ibrido funzionante, in ordine — sta nel manuale gemello: Costruire il laboratorio.
La parte che vale non sono i comandi — quelli stanno anche altrove — ma le motivazioni. Perché i segmenti sono /29 e non una rete piatta. Perché il bilanciatore lavora a livello 4 e non 7. Perché la sincronizzazione guarda una sola unità organizzativa. Ognuna di queste scelte esiste per riprodurre una condizione precisa di un ambiente di produzione, e senza quella condizione il laboratorio proverebbe qualcosa di diverso da quello che serve.
#Cosa contiene, e cosa no
Il documento originale copre anche l'accesso amministrativo al laboratorio, le credenziali e gli impegni verso il tenant su cui è appoggiato. Quella parte non è qui, e non ci sarà: è la mappa di come si entra in un ambiente che esiste davvero.
Restano fuori anche i riferimenti all'infrastruttura di produzione che il laboratorio riproduce. Il laboratorio nasce da un ambiente reale di un'organizzazione reale, e le sue caratteristiche — dominio, certificati, dimensionamento — non sono cose da pubblicare.
Tutti i nomi interni sono sostituiti: il dominio Active Directory è contoso.lab, gli indirizzi appartengono a intervalli generici, le persone si chiamano Mario Rossi. Le sostituzioni sono coerenti fra tutte le sezioni: se due pezzi parlano dello stesso oggetto, lo chiamano allo stesso modo.
#I tre livelli
Le sezioni portano un'etichetta che dice a chi servono. Il filtro in alto le usa.
| Livello | A chi serve | Cosa copre |
|---|---|---|
| L1 | Chiunque debba capire l'insieme | Concetti, verifiche di sola lettura, diagnosi di base |
| L2 | Chi costruisce o mantiene | Configurazione dei servizi, manutenzione ordinaria |
| L3 | Chi ricostruisce da zero | Installazioni, sottoscrizioni, regole di sincronizzazione |
Parte 1 — Perché un laboratorio
Un laboratorio costa tempo e memoria. Vale la pena solo se risponde a domande che l'ambiente vero non permette di porre.
#L'origine: tre cose che non si potevano studiare altrove
Il laboratorio nasce da tre situazioni concrete, tutte con la stessa forma: una domanda a cui non si poteva rispondere senza rischiare.
- Un incidente di fallimenti TLS/SMTP su cui erano state formulate ipotesi che nessuno poteva verificare. Le ipotesi restavano ipotesi perché provarle voleva dire toccare la posta di tutti.
- Un ripristino della password dell'amministratore locale su un server perimetrale, eseguito in emergenza. Una procedura che nessuno aveva mai provato prima di doverla eseguire.
- La necessità di provare gli script di provisioning prima di eseguirli dove ogni errore ha conseguenze.
In generale: l'assenza di un posto dove poter sbagliare.
#Il criterio: fedeltà architetturale
L'obiettivo dichiarato non era «un Exchange funzionante». Era una replica il più possibile aderente all'architettura reale, perché solo così i comportamenti osservati sono trasferibili.
La differenza è concreta. Un Exchange su rete piatta funziona benissimo e non riproduce il fenomeno per cui il server non vede l'indirizzo del vero mittente. Se l'incidente da studiare riguarda proprio quello, il laboratorio non serve a niente.
Ogni scelta successiva discende da questo criterio: quando una semplificazione avrebbe cancellato un fenomeno osservabile, la semplificazione è stata scartata.
#Cosa si riproduce, e cosa no
Riprodotto fedelmente:
| Elemento | Nel laboratorio |
|---|---|
| Exchange Server 2019 CU15 | Stessa versione, stessa build |
| Due server cassette in DAG | LAB-MBX01 e LAB-MBX02 |
Reti a micro-segmenti /29 instradati | Cinque segmenti dietro firewall |
| Bilanciatore che nasconde l'indirizzo sorgente | HAProxy L4 con SNAT |
| Due server perimetrali in workgroup | LAB-EDG01 e LAB-EDG02 con EdgeSync |
| Connettori applicativi | Coppia anonimo/autenticato |
| Ibrido con Entra Connect | Sincronizzazione verso un tenant vero |
| Regole di sincronizzazione personalizzate | Filtro su attributi |
| Struttura di OU per ciclo di vita | Nove unità organizzative |
Non riprodotto, e ogni volta per un motivo:
| Elemento | Perché no |
|---|---|
| Dieci database | L'edizione Standard limita a cinque database per server. Con quattro database e copie incrociate si ottiene comunque un DAG bilanciato. |
| Hybrid Configuration Wizard | Scrive connettori a livello di organizzazione in un tenant che ospita posta reale. Scelta consapevole di non eseguirlo. |
| PKI interna a più livelli | In produzione il certificato di servizio viene da una CA pubblica commerciale, non da una CA aziendale. Una PKI interna riprodurrebbe qualcosa che non esiste. |
| Bilanciatore commerciale | Sostituito da HAProxy in L4 con SNAT: comportamento di rete equivalente ai fini dell'indagine, costo e complessità molto inferiori. |
| Certificato pubblico di servizio | Non ottenibile per un dominio di laboratorio. I certificati restano auto-firmati. |
#I nomi di fantasia sono un meccanismo di sicurezza
Tutti i nomi del laboratorio sono inventati e non hanno alcuna corrispondenza con nomi reali. Non è pudore: è una difesa.
Un comando destinato al laboratorio che nomina contoso.lab non può, per distrazione, colpire l'ambiente di produzione. Se i due ambienti condividessero i nomi, l'unica cosa che separerebbe un Remove-Mailbox di prova da un disastro sarebbe l'attenzione di chi lo digita — e l'attenzione, alle otto di sera, è una difesa debole.
Lo stesso principio vale per il prefisso LAB- in ogni nome macchina: nell'elenco dell'hypervisor, il laboratorio si riconosce a colpo d'occhio.
Parte 2 — Convivere con quello che c'è già
Il laboratorio gira su un host che ospita anche altro. La progettazione parte da lì: non deve poter danneggiare quello che c'era prima.
#I quattro recinti
La protezione poggia su quattro meccanismi indipendenti. Indipendenti è la parola che conta: se uno cede, gli altri reggono.
- Rete. Tutte le macchine stanno su bridge Linux senza porte fisiche.
- Memoria e CPU. Memoria fissa, limiti espliciti, peso di scheduling ridotto.
- Storage. Provisioning sottile con
discard, e una soglia oltre la quale ci si ferma. - Convenzioni. Pool dedicato, tag, intervallo di identificativi riservato, prefisso nel nome.
#Bridge senza porte fisiche
Un bridge Linux senza porte agganciate non ha alcun percorso verso le schede di rete dell'host. È isolato per costruzione, non per configurazione — che è una differenza sostanziale: una regola di firewall si può disattivare per errore, un cavo che non esiste no.
L'unico punto di contatto con la rete esterna è l'interfaccia WAN del firewall virtuale, che opera in NAT: il traffico esce mascherato dietro un solo indirizzo, e nessun servizio del laboratorio è raggiungibile dall'esterno se non attraverso inoltri di porta espliciti.
Verifica dell'isolamento:
ip -br a | grep vmbr # i bridge del lab non devono avere IPv4
bridge link show | grep vmbr9 # nessuna riga = nessuna porta agganciata#Memoria e CPU: perché 50 e non 512
Ogni macchina del laboratorio ha memoria fissa — niente ballooning sui server Exchange — e due limiti espliciti:
qm set <vmid> --cpulimit 2 # tetto di 2 core effettivi
qm set <vmid> --cpuunits 50 # metà del peso predefinitoIl valore 50 è deliberato. Su cgroup v2 il peso predefinito è 100: mettendo 50, in caso di contesa lo scheduler favorisce le macchine preesistenti.
Sulla memoria non c'è margine da giocare: a pieno regime le macchine chiedono più RAM di quanta ne abbia l'host. Il laboratorio si usa quindi a gruppi di accensione, mai tutto insieme.
#La regola del datacenter
Nessuna operazione a livello di datacenter o di nodo senza accordo esplicito. Riavvii dell'host, modifiche alla rete globale, interventi sullo storage condiviso: sono azioni che toccano tutti, e in un ambiente condiviso l'unica difesa è la regola sociale.
Parte 3 — La rete
Questa è la parte che si è deciso di non semplificare, e il resto del laboratorio poggia su questa scelta.
#I segmenti, e perché i /29
Cinque segmenti dietro un firewall virtuale, ciascuno su un bridge senza porte fisiche.
| Segmento | Rete | Ospita |
|---|---|---|
| Gestione | 10.20.10.0/24 | Domain controller, server di sincronizzazione |
| Exchange | 10.20.20.8/29 | I due server cassette |
| Bilanciatore | 10.20.20.32/29 | HAProxy e il VIP |
| Client | 10.20.30.0/24 | Il client applicativo |
| DMZ | 10.20.40.0/29 | I due server perimetrali |
La scelta dei /29 non è estetica. In produzione il bilanciatore e i server Exchange stanno su reti diverse e instradate, ed è questa la condizione che rende obbligatorio il SNAT.
Un laboratorio su rete piatta non riprodurrebbe il fenomeno. Con i /29 instradati sì, ed è verificabile nei log di protocollo.
#Il SNAT: perché Exchange non vede il vero mittente
Il bilanciatore riceve le connessioni su un indirizzo virtuale e le inoltra ai server Exchange cambiando l'indirizzo sorgente con il proprio.
Non è una scelta di configurazione: è una necessità. Il bilanciatore non può presentarsi con l'indirizzo del client, perché il traffico di ritorno non tornerebbe da lui — tornerebbe direttamente al client, che non riconoscerebbe la connessione. Il prezzo è che Exchange perde la visibilità del vero mittente.
Il percorso completo di un messaggio in uscita:
Client applicativo (10.20.30.10)
→ VIP del bilanciatore (10.20.20.38)
→ HAProxy con SNAT (la sorgente diventa 10.20.20.34)
→ Exchange cassette (10.20.20.10 / .11)
→ EdgeSync → perimetro (10.20.40.2 / .3)
→ InternetLa prova che il laboratorio è fedele sta in una riga del log di protocollo, dopo aver generato traffico attraverso il VIP:
2026-08-19T00:23:03.808Z,LAB-MBX02\Default Frontend LAB-MBX02,...,
10.20.20.11:25,10.20.20.34:37058,+,,L'indirizzo remoto registrato è quello del bilanciatore, non del client. Gli Exchange accettano connessioni da un /29 diverso e non direttamente connesso: la condizione esatta della produzione.
#Il TTL come strumento di diagnosi
Un dettaglio che vale più di molti strumenti. Nelle risposte al ping, il valore TTL distingue i percorsi:
| TTL da un host Windows | Significato |
|---|---|
128 | Percorso diretto, nessun salto |
127 | Un salto — cioè il passaggio dal firewall |
Confrontare i TTL è il modo più rapido per capire se due macchine si parlano direttamente o attraverso l'instradamento. In un ambiente segmentato, questa è la prima domanda da porsi e l'ultima a cui si pensa.
#pfSense: le tre caselle che si sbagliano
Tre impostazioni producono guasti che sembrano avere altre cause.
Block private networks e Block bogon networks sulla WAN. Quei filtri hanno senso su un'interfaccia affacciata a internet vero, dove traffico da indirizzi privati o riservati è per definizione anomalo. Quando la «WAN» è in realtà una LAN privata, il traffico amministrativo arriva da indirizzi privati o da intervalli classificati come bogon, e viene scartato prima di qualsiasi regola. I port forward risultano configurati e inerti.
Il campo DNS Hostname in System → General Setup. Serve alla verifica TLS del resolver e va lasciato vuoto. Inserirvi un indirizzo IP — errore facile, perché il campo è adiacente a quello degli indirizzi — impedisce la risoluzione pur essendo l'instradamento corretto.
Filter rule association su un inoltro di porta. Deve restare su Add associated filter rule. Con None, pfSense esegue il NAT ma blocca il traffico, e si passa mezz'ora a cercare la causa altrove.
#Aggiungere una scheda: non a caldo
Le schede di rete non si agganciano a caldo su FreeBSD. La sequenza corretta parte da uno snapshot:
qm snapshot 1310 pre-modifica
qm set 1310 -net<N> virtio,bridge=vmbr9X,firewall=1
qm shutdown 1310 && qm start 1310Poi, nell'interfaccia: Interfaces → Assignments → Add sulla nuova scheda, aprirla, Enable, descrizione, indirizzo statico, Save e Apply.
#Il firewall che riavvii, il testimone che cade
Ogni riavvio del firewall manda offline il File Share Witness del DAG, perché la condivisione risiede sul domain controller, che sta oltre il firewall.
Non torna online da solo. È il punto in cui una manutenzione di rete apparentemente innocua lascia il cluster in uno stato degradato senza che nessuno se ne accorga. Il rimedio sta in Il quorum e il testimone.
Parte 4 — Active Directory e Exchange
#La foresta, e perché il dominio interno non basta
Un solo domain controller, dominio contoso.lab, cestino di Active Directory attivo.
Il cestino non è un dettaglio: consente di ripristinare un oggetto cancellato per errore con tutti i suoi attributi. Senza, la cancellazione si propaga nel cloud e il recupero diventa laborioso.
Get-ADOptionalFeature -Filter * | ft Name,EnabledScopes -AutoRipristino di un oggetto eliminato:
Get-ADObject -Filter 'isDeleted -eq $true' -IncludeDeletedObjects -Properties * |
ft Name,SamAccountName,LastKnownParent,whenChanged -Auto
Get-ADObject -Filter 'SamAccountName -eq "<utente>"' -IncludeDeletedObjects |
Restore-ADObjectAlla foresta è stato aggiunto un suffisso UPN aggiuntivo su un dominio pubblico verificato:
Get-ADForest | Set-ADForest -UPNSuffixes @{add="lab.impicciando.it"}È indispensabile: contoso.lab non è instradabile su internet, ed Entra Connect rifiuta di sincronizzare UPN non instradabili. Gli utenti destinati al cloud hanno quindi UPN sul dominio pubblico, mentre il samAccountName e l'accesso a Windows restano invariati.
#Le unità organizzative come recinto
Nove unità organizzative che riflettono un ciclo di vita completo dell'utenza: operativi, sede, supporto, esterni, caselle di funzione, dismessi, disabilitati, in attesa di eliminazione — e SYNC.
SYNC ha una funzione diversa dalle altre: è il recinto della sincronizzazione. Entra Connect è configurato per considerare esclusivamente quella unità, quindi qualunque oggetto fuori da essa, per il tenant, non esiste.
La scelta è protettiva. Finché l'ambito resta ristretto, un errore nella configurazione della sincronizzazione può interessare al massimo gli oggetti di prova.
#Il CN deve coincidere col samAccountName
Non è una preferenza estetica, ed è la trappola più costosa dell'intera struttura.
| Comando | Risolve l'identità per |
|---|---|
Add-MailboxPermission | samAccountName |
Add-ADPermission | nome dell'oggetto (CN) |
Un utente creato con -Name "Ufficio Acquisti" e -SamAccountName "ufficio.acquisti" fa fallire il secondo comando con un laconico wasn't found, mentre il primo funziona regolarmente. Il risultato è uno script che assegna metà dei permessi e fallisce sull'altra metà — senza fermarsi.
Creazione corretta: il nome leggibile va nel DisplayName, che è quanto compare in rubrica.
New-ADUser -Name "mario.rossi" -DisplayName "Mario Rossi" -SamAccountName "mario.rossi"Verifica e correzione degli oggetti non conformi:
Get-ADUser -SearchBase "OU=SYNC,DC=contoso,DC=lab" -Filter * -Properties Name,DisplayName |
Where-Object { $_.Name -ne $_.SamAccountName } |
ForEach-Object {
Write-Host ("{0} -> {1}" -f $_.Name, $_.SamAccountName)
Rename-ADObject -Identity $_.DistinguishedName -NewName $_.SamAccountName
}#La gerarchia oraria
L'orario è il punto più delicato dell'intero laboratorio, e la ragione è raccontata per esteso in Nove ore di scarto.
Internet (time.windows.com, pool.ntp.org)
│
LAB-DC01 → radice della gerarchia, marcato /reliable:yes
│
├── membri del dominio → modalità domhier (automatica)
└── macchine in workgroup → puntamento manuale al domain controllerSul domain controller:
w32tm /config /manualpeerlist:"time.windows.com,0x8 pool.ntp.org,0x8" /syncfromflags:manual /reliable:yes /update
Set-Service w32time -StartupType Automatic
Restart-Service w32time
w32tm /resync /rediscoverSui membri del dominio:
w32tm /config /syncfromflags:domhier /update
Restart-Service w32time
w32tm /query /source # deve rispondere col nome del domain controllerTutte le macchine devono avere lo stesso fuso orario dell'host che le ospita. Il motivo non riguarda la comodità di leggere l'ora, ma la correttezza dell'UTC dopo ogni riavvio.
#Il vincolo dell'edizione: cinque database
L'edizione Standard consente un massimo di cinque database di cassette postali per server. L'installazione in modalità valutazione si comporta come Standard.
Il tentativo di andare oltre produce:
RcrExceedDbLimitException: ... maximum databases limit of 5Due dettagli che si scoprono solo sbattendoci contro:
- Il limite riguarda i database presenti sul server, copie comprese, non i database attivi. Quattro database con copia incrociata occupano quattro posti su ciascun nodo, non due.
- L'installazione del secondo server cassette crea automaticamente un proprio database predefinito con nome generato, che consuma uno dei cinque posti. Va rimosso o rinominato prima di creare i database del progetto.
L'architettura risultante — due database attivi per nodo, con copia sull'altro — sta nel limite e dà un DAG pienamente funzionante e bilanciato.
| Database | Attivo su | Copia passiva su |
|---|---|---|
DB01 | LAB-MBX01 | LAB-MBX02 |
DB02 | LAB-MBX02 | LAB-MBX01 |
DB03 | LAB-MBX01 | LAB-MBX02 |
DB04 | LAB-MBX02 | LAB-MBX01 |
Verifica dello stato:
Get-MailboxDatabaseCopyStatus * |
ft Name,Status,ActiveCopy,CopyQueueLength,ReplayQueueLength,ContentIndexState -AutoMounted indica la copia attiva, Healthy una copia passiva allineata. CopyQueueLength è il numero di log ancora da copiare, ReplayQueueLength quelli copiati ma non ancora applicati: entrambi a zero significa replica in pari.
#Il DAG senza indirizzo IP
Il DAG è configurato senza punto di accesso amministrativo — il modello consigliato da Exchange 2013 in poi. Il cluster sottostante non ha un nome di rete né un indirizzo IP propri.
La conseguenza pratica va conosciuta, perché sembra un guasto e non lo è: i comandi cluster non accettano -Cluster. Un tentativo produce un errore di RPC non disponibile.
Get-ClusterNode | ft Name,State -Auto # corretto: si esegue su un nodo
Get-ClusterNode -Cluster DAG1 # errore, ed è atteso#Il quorum e il testimone oltre il firewall
Con due nodi e un testimone i voti sono tre e la maggioranza è due: il laboratorio sopravvive alla perdita di un nodo o del testimone, non di entrambi.
Il testimone risiede sul domain controller, che sta in un segmento diverso da quello dei nodi Exchange, oltre il firewall. Questa è una fragilità reale e si manifesta a ogni manutenzione del firewall.
Sintomo: QuorumGroup fallisce dicendo che il File Share Witness è offline, mentre FileShareQuorum risulta Passed.
La distinzione fra i due controlli è informativa: FileShareQuorum verifica che la configurazione del testimone sia corretta, QuorumGroup che la risorsa sia online. Durante un riavvio del firewall i nodi perdono l'accesso alla condivisione, la risorsa va in Failed e non torna su da sola.
Get-ClusterResource | ft Name,State -Auto
Start-ClusterGroup "Cluster Group"Salute della replica:
Test-ReplicationHealth -Identity LAB-MBX01 | Where-Object Result -ne 'Passed'Test-ReplicationHealth esegue diciannove controlli per server. Se il comando filtrato non stampa nulla, il DAG è integro.
#Manutenzione di un nodo
La sequenza va eseguita dal nodo che resta attivo.
Set-ServerComponentState LAB-MBX01 -Component HubTransport -State Draining -Requester Maintenance
Invoke-Command -ComputerName LAB-MBX01 -ScriptBlock { Restart-Service MSExchangeTransport }
Redirect-Message -Server LAB-MBX01 -Target LAB-MBX02.contoso.lab
Suspend-ClusterNode -Name LAB-MBX01
Set-MailboxServer LAB-MBX01 -DatabaseCopyActivationDisabledAndMoveNow $true
Set-MailboxServer LAB-MBX01 -DatabaseCopyAutoActivationPolicy Blocked
Set-ServerComponentState LAB-MBX01 -Component ServerWideOffline -State Inactive -Requester MaintenanceDue passaggi che quella sequenza non completa da sola, e che vanno verificati.
I database attivi non sempre si spostano: il flag può incontrare il limite di quattro spostamenti all'ora per database imposto da Active Manager. Vanno allora spostati a mano.
Move-ActiveMailboxDatabase DB01 -ActivateOnServer LAB-MBX02 -Confirm:$falseE Suspend-ClusterNode mette il nodo in Paused ma non sposta il gruppo di cluster già presente: il Primary Active Manager resta dov'è finché non lo si sposta.
Move-ClusterGroup -Name "Cluster Group" -Node LAB-MBX02Verifica di nodo vuoto: nessun Mounted sul nodo in manutenzione, PrimaryActiveManager sull'altro, nodo in Paused.
Dopo la manutenzione i database restano concentrati su un nodo. Riequilibrarli non è estetica: le preferenze di attivazione riflettono scelte di capacità, e si torna alla configurazione progettata.
#I connettori applicativi: due errori distinti
Due connettori di ricezione riproducono la coppia che si trova in produzione, e la differenza fra i due spiega due errori che si incontrano nei log reali.
| Connettore anonimo | Connettore autenticato | |
|---|---|---|
| Chi si connette | Applicativi che non sanno autenticarsi | Applicativi con account di servizio |
| Porta | 25 | 587 |
| Permessi | AnonymousUsers + diritto di relay esplicito | ExchangeUsers |
| Controllo d'accesso | Solo l'indirizzo sorgente | Indirizzo e credenziali |
| Errore tipico | 550 se l'indirizzo non è in elenco | 530 5.7.57 se non ci si autentica |
Creazione del connettore anonimo, in due passi — il secondo è quello che si dimentica:
New-ReceiveConnector -Name "smtp-app-lab" -TransportRole FrontendTransport -Server LAB-MBX01 `
-Bindings 0.0.0.0:25 `
-RemoteIPRanges 10.20.20.10,10.20.20.11,10.20.20.34,10.20.30.10 `
-PermissionGroups AnonymousUsers -AuthMechanism Tls -Enabled $true
Get-ReceiveConnector "LAB-MBX01\smtp-app-lab" |
Add-ADPermission -User "NT AUTHORITY\ANONYMOUS LOGON" `
-ExtendedRights "Ms-Exch-SMTP-Accept-Any-Recipient"Il diritto Ms-Exch-SMTP-Accept-Any-Recipient è ciò che autorizza il relay verso domini esterni; RemoteIPRanges lo limita agli indirizzi elencati. Senza quel diritto, un invio verso l'esterno riceve 550 5.7.54.
Come Exchange sceglie il connettore. Più connettori possono condividere lo stesso binding; Exchange sceglie quello con l'intervallo di indirizzi sorgente più specifico. Ma la specificità vale solo entro la stessa famiglia di indirizzi: un connettore in ascolto su 0.0.0.0:25 con intervalli IPv4 non viene mai selezionato per una connessione IPv6. La storia per esteso sta in 550 5.7.54 con il connettore giusto.
I log di protocollo sono l'unico posto dove Exchange dichiara quale connettore ha accettato una sessione e da dove:
Get-ReceiveConnector -Server LAB-MBX01 | Set-ReceiveConnector -ProtocolLoggingLevel VerboseIl secondo campo di ogni riga è il connettore che ha accettato la sessione, il quinto è l'indirizzo sorgente. Confrontarli è il modo più rapido per capire cosa è successo.
#Il trasporto perimetrale e EdgeSync
Due server Windows fuori dal dominio, in DMZ, con il solo ruolo di trasporto perimetrale. Non contattano mai Active Directory: conservano una copia dei dati di configurazione in AD LDS, popolata da EdgeSync.
È questo isolamento a renderli adatti al perimetro — ed è anche la ragione per cui, se si perde la password dell'amministratore locale, non esiste un amministratore di dominio che possa entrare.
I tre punti dove questa fase fallisce.
Il suffisso DNS primario. Una macchina in workgroup non lo eredita dal dominio e va impostato a mano nel registro. Senza, il nome completo resta il solo nome NetBIOS e la sottoscrizione fallisce.
[System.Net.Dns]::GetHostEntry($env:COMPUTERNAME).HostNameL'orologio. EdgeSync usa certificati auto-firmati valutati rispetto all'ora corrente. Uno scarto di pochi minuti li rende non validi, e l'errore che ne risulta parla di connessione, non di tempo: The LDAP server is unavailable.
I servizi dopo la sottoscrizione. Anche con orario corretto e porta aperta, EdgeSync può non partire finché non si riavviano i servizi che valutano i certificati.
Restart-Service ADAM_MSExchange -Force
Restart-Service MSExchangeEdgeCredential
Restart-Service MSExchangeTransportCome si legge l'esito della sottoscrizione:
| Stato | Significato |
|---|---|
SyncStatus : Normal, CookieRecords > 0 | Funzionante |
SyncStatus : Inconclusive, tutti NotStarted | Atteso subito dopo la creazione: il primo ciclo non è ancora avvenuto |
CouldNotConnect, The LDAP server is unavailable | Orario, oppure servizi da riavviare |
Stati Skipped | Normale: nulla di nuovo da sincronizzare |
Un messaggio verso un dominio esterno inesistente che resta in coda in stato Retry è il risultato atteso: dimostra che il percorso interno → perimetro funziona.
#Il Direct Trust: perché una CA non serve
I certificati che i server cassette e quelli perimetrali si scambiano sono auto-firmati, generati da Exchange. La fiducia non nasce dalla catena di certificazione: nasce dal fatto che il certificato è pubblicato nella directory — in Active Directory da un lato, in AD LDS dall'altro — e distribuito da EdgeSync.
La conseguenza pratica è che una CA non serve. Un certificato emesso da un'autorità non aggiungerebbe nulla alla verifica.
Il rinnovo, alla scadenza, si effettua rifacendo la sottoscrizione.
Get-ExchangeCertificate | ft Thumbprint,Subject,Issuer,NotAfter,Services -AutoDove Subject e Issuer coincidono, il certificato è auto-firmato.
#HAProxy in modalità L4
Ventinove righe di configurazione, di cui due contano davvero.
frontend ft_smtp
bind 10.20.20.38:25
default_backend bk_smtp
backend bk_smtp
balance roundrobin
source 10.20.20.34
server mbx01 10.20.20.10:25 check
server mbx02 10.20.20.11:25 checkmode tcp — livello 4, nessuna terminazione TLS. L'handshake attraversa il bilanciatore intatto e arriva a Exchange, esattamente come fa il bilanciatore commerciale che riproduce. In modalità HTTP il bilanciatore terminerebbe la connessione, e il fenomeno TLS da studiare non sarebbe più osservabile.
source 10.20.20.34 — forza l'indirizzo sorgente verso i server. È il SNAT.
Verifica prima di riavviare — nessun output significa configurazione valida:
haproxy -c -f /etc/haproxy/haproxy.cfgProva del percorso completo, che deve rispondere col banner di uno dei due Exchange:
telnet 10.20.20.38 25#Certificati: le lacune dichiarate
Nel laboratorio esistono due tipi di certificato, e ne manca un terzo.
| Tipo | Emittente | Scopo | Rinnovo |
|---|---|---|---|
| Auto-firmato SMTP | Sé stesso | Direct Trust cassette ↔ perimetro | Nuova sottoscrizione |
| Certificato di autenticazione | Sé stesso | Autenticazione OAuth fra server | Cinque anni, silenzioso |
| Certificato di servizio | — | Client e connessioni esterne | Assente nel laboratorio |
Il certificato di autenticazione merita attenzione perché scade in silenzio, e la sua scadenza rompe funzioni ibride come la condivisione della disponibilità senza messaggi evidenti. È un controllo che vale la pena inserire fra le verifiche periodiche, anche in produzione.
Get-ExchangeCertificate -Thumbprint (Get-AuthConfig).CurrentCertificateThumbprint |
fl NotBefore,NotAfter,SubjectIl certificato di servizio non è ottenibile per un dominio di laboratorio, quindi i certificati restano auto-firmati. Va dichiarato quando si leggono i risultati: le prove di accesso client dall'esterno operano con un certificato che il client non considera attendibile. Questo non impedisce di verificare il percorso di rete — la connessione si stabilisce, il traffico passa — ma «il browser ha protestato» e «non ha funzionato» sono esiti diversi, e solo uno dei due è un guasto.
Per verificare se una catena è realmente verificabile e non solo formalmente corretta:
certutil -verify -urlfetch <file.cer>-urlfetch scarica davvero CRL e certificati intermedi dagli indirizzi contenuti nel certificato.
Parte 5 — L'ibrido
#Il tenant, e la scelta di non eseguire l'HCW
Il laboratorio si sincronizza verso un tenant Microsoft 365 vero, non di prova. È una scelta che aumenta la fedeltà e impone cautele.
La più importante: l'Hybrid Configuration Wizard non è stato eseguito. Scrive connettori a livello di organizzazione nel tenant, e quel tenant ospita posta reale. Rinunciarvi significa rinunciare a una parte del comportamento ibrido; eseguirlo avrebbe significato modificare la configurazione di posta di un ambiente in uso.
Il sottodominio di laboratorio è stato verificato automaticamente, senza record TXT: Microsoft eredita la prova di proprietà dal dominio padre, già verificato nello stesso tenant. In fase di aggiunta è stato deliberatamente saltato il passo dei servizi — nessun record MX, CNAME o SPF — perché al laboratorio serve solo che il dominio sia verificato, non che instradi posta.
#Entra Connect: il filtro per unità organizzativa
È la protezione principale del tenant. Entra Connect considera esclusivamente una unità organizzativa: qualunque oggetto fuori da quella, per il tenant, non esiste.
| Voce | Valore |
|---|---|
| Metodo di accesso | Password Hash Synchronization |
| Single sign-on | Disattivato |
| Filtro | Una sola OU |
| Ancoraggio | mS-DS-ConsistencyGuid |
| Funzioni opzionali | Password Hash Sync, Exchange hybrid deployment |
| Ciclo automatico | Attivo, ogni 30 minuti |
Il filtro va verificato a ogni riesecuzione della procedura guidata, che ripropone le impostazioni correnti ma non impedisce di modificarle per distrazione.
Set-ADSyncScheduler -SyncCycleEnabled $true#Exchange hybrid deployment e la scrittura all'indietro
Attivata dopo la configurazione iniziale, e la differenza è stata sostanziale.
Prima dell'attivazione, Exchange Online non riconosceva gli oggetti locali come destinatari validi. Dopo, gli stessi oggetti compaiono correttamente come MailUser, che è il modo in cui un ibrido rappresenta una casella che vive dall'altra parte.
La funzione abilita anche la scrittura all'indietro di alcuni attributi dal cloud verso Active Directory: stato dell'archivio, elenchi mittenti attendibili e bloccati, deleghe pubbliche, e indirizzi creati nel cloud.
L'effetto è osservabile: su un oggetto sincronizzato, in Active Directory, compare un indirizzo X500 con prefisso /o=ExchangeLabs — l'organizzazione di Exchange Online, non quella locale. Quell'indirizzo è nato nel cloud ed è tornato indietro. Serve a preservare la possibilità di rispondere a messaggi inviati quando la casella viveva altrove, e non va rimosso.
Dopo l'attivazione serve obbligatoriamente un ciclo completo:
Start-ADSyncSyncCycle -PolicyType Initial#La regola di sincronizzazione personalizzata
Sincronizza solo chi ha un certo valore di employeeType, oppure chi porta un attributo di estensione con un valore concordato. Scrive cloudFiltered, che è l'attributo con cui Entra Connect decide se un oggetto esiste per il tenant.
| Voce | Valore |
|---|---|
| Direzione | Inbound |
| Tipo oggetto | user → person |
| Precedenza | 50 |
| Attributo di destinazione | cloudFiltered |
| Tipo di flusso | Expression |
IIF(IsPresent([employeeType]),
IIF([employeeType]="Interno", False,
IIF(IsPresent([extensionAttribute1]),
IIF([extensionAttribute1]="SYNC365", False, True), True)),
IIF(IsPresent([extensionAttribute1]),
IIF([extensionAttribute1]="SYNC365", False, True), True))Tabella di verità:
employeeType | extensionAttribute1 | cloudFiltered | Esito |
|---|---|---|---|
Interno | qualsiasi | False | sincronizza |
| altro | SYNC365 | False | sincronizza |
| altro | altro o assente | True | escluso |
| assente | SYNC365 | False | sincronizza |
| assente | assente | True | escluso |
Quattro cose da sapere prima di scriverla.
L'espressione va nel campo Source. Non esiste un campo separato: quando si imposta FlowType = Expression, la colonna Source diventa una casella di testo libera. È il punto in cui ci si blocca cercando un campo che non c'è.
La precedenza deve stare sotto 100. Da 100 in su ci sono le regole predefinite di Microsoft; una regola con precedenza superiore verrebbe sopravanzata e cloudFiltered non verrebbe mai scritto.
Niente operatori booleani. Il linguaggio delle espressioni è limitato: la struttura a IIF annidati è più prolissa ma sicura. IsPresent va sempre verificato prima di confrontare un attributo che potrebbe essere assente, altrimenti l'espressione fallisce a runtime proprio su quegli oggetti.
Dopo ogni modifica serve un ciclo completo. Un ciclo Delta valuta solo gli oggetti cambiati di recente; le regole nuove si applicano a quelli esistenti solo con Initial.
#La modalità staging
È il modo corretto di sviluppare o modificare regole. In staging il motore importa, applica le regole e calcola tutte le differenze, ma non esporta nulla: si può sbagliare quante volte serve senza che un solo oggetto nel tenant se ne accorga.
Perché è indispensabile, e non è ovvio: un oggetto che esce dall'ambito di sincronizzazione è indistinguibile, per Entra Connect, da un oggetto sparito. Genera un'operazione di eliminazione nel cloud.
Durante la costruzione questo è stato verificato deliberatamente: togliendo l'attributo di ammissione a un utente già sincronizzato, in staging è comparsa un'operazione di Delete in attesa. Nessuna cancellazione è avvenuta.
La procedura, e il passo che protegge davvero:
- Attivare la modalità staging
- Modificare o creare la regola nell'editor
- Eseguire un ciclo
Initial - Ispezionare le operazioni in attesa (Pending Export)
- Correggere finché non compaiono eliminazioni indesiderate
- Solo allora disattivare lo staging
- Eseguire un altro ciclo
Initial - Verificare gli oggetti nel tenant
Il passo 5 è la regola: non si esce mai dallo staging con un'eliminazione in sospeso che non si vuole davvero.
#Il connector space: perché questo utente non si sincronizza
Lo strumento che risponde in trenta secondi alla domanda più frequente.
Vista d'insieme — cosa verrebbe esportato: scheda Connectors → connettore del tenant → Search Connector Space → Scope: Pending Export → spuntare Add, Modify, Delete → Search.
Vista di dettaglio — perché un oggetto è escluso: scheda Connectors → connettore della foresta → Search Connector Space → Scope: DN → il nome distinto dell'oggetto → selezionarlo → Preview → Generate Preview → Import Attribute Flow.
Lì si vede ogni regola applicata all'oggetto, in ordine di precedenza, e il valore finale di ogni attributo.
Parte 6 — Metodo e diagnosi
#Tre principi
Emersi dalla costruzione, in ordine di utilità.
Leggere il log, non il messaggio a schermo. Il messaggio della finestra è quasi sempre generico. La causa vera sta nel registro eventi o nel file di log dello strumento. L'errore più istruttivo dell'intero progetto — could not configure application based authentication — non aveva nulla a che vedere con l'autenticazione: nel registro eventi si leggeva un certificato con date incoerenti, e la causa era un orologio.
Confrontare due misure indipendenti. Un solo dato non dice se è giusto. Due dati che dovrebbero coincidere e non coincidono individuano il problema. È così che si è trovato lo sfasamento orario: due marche temporali nello stesso evento, a nove ore esatte di distanza.
Distinguere il livello che fallisce. TCP che connette ma LDAP che non risponde significa che il problema è sopra il trasporto, non nella rete. Continuare a controllare firewall e instradamenti, in quel caso, è tempo perso.
#Comandi di sola lettura
Rete:
Test-NetConnection <ip> -Port <porta> -InformationLevel Quiet
Resolve-DnsName <nome>
Get-NetConnectionProfileIdentità e Kerberos:
nltest /sc_query:contoso.lab
Test-ComputerSecureChannel -Verbose
klist
w32tm /query /status
(Get-Date).ToUniversalTime()Exchange e DAG:
Get-ClusterNode | ft Name,State,StatusInformation,DrainStatus -Auto
Get-MailboxDatabaseCopyStatus * | ft Name,Status,ActiveCopy,CopyQueueLength -Auto
Get-Queue -Server <server> | ft Identity,Status,MessageCount,NextHopDomain -Auto
Get-MessageTrackingLog -Server <server> -Sender <indirizzo> -Start (Get-Date).AddMinutes(-30) |
fl Timestamp,EventId,Source,RecipientStatus,RecipientsEntra Connect, dove sta la causa vera dei fallimenti:
Get-WinEvent -LogName Application -MaxEvents 100 |
Where-Object { $_.ProviderName -match "ADSync|Directory Synchronization|Entra" } |
Select-Object TimeCreated,ProviderName,LevelDisplayName,Message | fl#La ridondanza shadow non è un'anomalia
Nei log di tracciamento compaiono eventi HARECEIVE, HAREDIRECT e code Shadow. Non sono guasti: sono il meccanismo con cui Exchange conserva una copia di ogni messaggio sull'altro nodo finché il primario non conferma la consegna.
Una coda Shadow con messaggi dentro è normale. Una coda Shadow che cresce e non si svuota indica un nodo che non conferma più le consegne, ed è un sintomo da indagare.
#Errori minori ma ricorrenti
| Sintomo | Causa | Rimedio |
|---|---|---|
Cannot convert ArrayList passando più identità | -Identity non accetta elenchi | Usare la pipeline o ForEach-Object |
Cannot convert ADPropertyValueCollection | Get-ADDomainController -Discover restituisce una collezione | string.HostName |
too many moves | Limite di quattro spostamenti orari per database | Attendere |
w32tm /resync /force: arguments were unexpected | /force non è un parametro valido | /rediscover |
Restart-Service ADAM_MSExchange: dependent services | Ha servizi dipendenti | -Force |
Get-ADSyncScheduler: Synchronization Service is not running | Il servizio è fermo | Atteso se lo si è appena arrestato |
| Lo scheduler è spento dopo la procedura guidata | La procedura lo disattiva | Set-ADSyncScheduler -SyncCycleEnabled $true |
Where-Object Result -ne Passed mostra tutto | Senza virgolette vale $null -ne 'Passed' | Mettere le virgolette |
| Entra Connect: schermata di accesso vuota | IE Enhanced Security | Disattivarla per gli amministratori |
#Le quattro storie lunghe
Quattro guasti hanno richiesto una diagnosi vera, e ognuno è raccontato per esteso altrove.
- Nove ore di scarto: l'errore sui certificati era l'orologio — l'hypervisor, il fuso delle macchine, e il danno collaterale su Kerberos e sul DAG.
- 550 5.7.54 con il connettore giusto: arrivava in IPv6 — perché un connettore configurato bene non veniva mai selezionato.
- Tre presupposti che uno script Exchange non dichiara — la sessione sbagliata, il nome dell'oggetto, i prerequisiti muti.
- Chi decide l'indirizzo primario di una casella ibrida — la politica, il comando e Entra che si contendono lo stesso campo.
Il filo comune fra tutti e quattro: il messaggio d'errore indicava una direzione sbagliata. Non per cattiva progettazione — un componente può segnalare solo quello che vede — ma perché la causa stava sempre uno strato più sotto di dove il sintomo si manifestava.
Nessun risultato. Prova con il nome di un componente (DAG), un cmdlet (Set-Mailbox) o un concetto (quorum, SNAT, staging).