In un ambiente Windows Server 2019 con RDS per‑utente, gli utenti via CyberArk PSM non ricevevano le CAL e il Session Host sembrava limitato a due connessioni. La causa? Un blocco firewall in ingresso sulle nuove subnet RDSH: sbloccata la TCP 3389 dai PSM, le sessioni si sono stabilite e le User CAL sono state emesse subito.
Panoramica del problema
- Infrastruttura Windows Server 2019 con licenze RDS per‑utente (User CAL) disponibili (20), ma il Session Host consente apparentemente solo due connessioni simultanee.
- Gli utenti si connettono tramite due CyberArk PSM (Privileged Session Manager) che fungono da broker RDP. Da un PSM le sessioni funzionano, dall’altro no; gli utenti diretti (non‑PSM) ricevono regolarmente la CAL.
- GPO, registro e versioni (Session Host, Licensing Server e CAL) sono correttamente configurati e allineati (tutti 2019 Datacenter).
Schema logico dell’ambiente
[Utente] ──RDP──> [CyberArk PSM #1] ──RDP:3389──> [RDSH A/B]
└──> [CyberArk PSM #2] ──RDP:3389──> [RDSH A/B]
│
└──RPC (135 + porte dinamiche)──> [RDS License Server]
Il tranello: “due connessioni” non significa per forza un problema di licenza
Nel mondo RDS è frequente confondere il limite di due connessioni (tipico dell’accesso amministrativo) con un errore di licensing. In realtà, la negoziazione delle licenze entra in gioco dopo che la sessione RDP è stata instaurata a livello di rete e di protocollo. Se il percorso RDP è bloccato, la richiesta di licenza non parte nemmeno. Nel caso in esame, un PSM non completava il three‑way handshake TCP verso i RDSH: da qui il “sintomo” ingannevole.
Soluzione confermata e passi risolutivi
| Fase | Verifica / Azione | Esito |
|---|---|---|
| Controllo policy e registry | Confermato ✔️: percorso GPO Remote Desktop Services → Licensing e chiavi LicensingMode impostate su per‑user; server di licenza specificato correttamente. | Non risolve il sintomo. |
| Test di connettività | Dal PSM “non funzionante” fallisce la connessione TCP 3389 verso i server RDSH. | Identifica un problema di rete. |
| Analisi dei log di rete | I pacchetti SYN partono dal PSM, ma i pacchetti di ACK di ritorno non arrivano. | Conferma un blocco inbound. |
| Audit del firewall interno | Manca una regola in ingresso per le nuove subnet che ospitano i RDSH. | Root‑cause individuata. |
| Correzione | Aggiunta la regola firewall per permettere TCP 3389 dai PSM verso i RDSH. | ✔️ Connessioni RDP stabilite, le User CAL vengono rilasciate regolarmente da subito. |
Riepilogo tecnico
La negoziazione delle licenze RDS avviene solo dopo l’instaurazione completa della sessione RDP. Il secondo PSM non riusciva a completare il three‑way handshake TCP con i Remote Desktop Session Host, quindi la richiesta di licenza non raggiungeva mai il server CAL. Una volta aperta la porta 3389/TCP sulle subnet interessate, la catena di comunicazione (PSM → RDSH ↔ License Server) è tornata stabile e il limite apparente di due sessioni è scomparso.
Procedura di troubleshooting completa (passo‑passo)
Verifiche di base su GPO e registro
Assicurati che i RDSH siano configurati per l’uso di licenze per‑utente e che conoscano il Licensing Server. I controlli tipici includono:
- GPO: Computer Configuration → Policies → Administrative Templates → Windows Components → Remote Desktop Services → Remote Desktop Session Host → Licensing.
- Abilita “Use the specified Remote Desktop license servers” con l’FQDN del Licensing Server.
- Imposta “Set the Remote Desktop licensing mode” su Per User.
- Registro (valori più comuni, possono variare in base alle policy):
HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services\LicensingMode→DWORD(valore tipico 4 = Per‑User; 2 = Per‑Device).HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services\LicenseServers<FQDN_LS>→ presenza del Licensing Server.
Controlli PowerShell utili
# Su un RDSH
1) Stato porta RDP in ascolto
Get-NetTCPConnection -LocalPort 3389 -State Listen
2) Lettura rapida del valore LicensingMode (se esiste in Path Policies)
Get-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' `
-Name LicensingMode -ErrorAction SilentlyContinue
3) Elenco dei License Servers definiti via Policy (se presenti)
Get-ChildItem 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services\LicenseServers' `
-ErrorAction SilentlyContinue | Select-Object PSChildName
Suggerimento: il Diagnostico Remote Desktop Licensing Diagnoser (sui RDSH) individua velocemente mismatch di versione o insufficienza CAL. Trattandosi di User CAL, il sistema può non “bloccare” attivamente le connessioni, ma segnala l’errore: non fermarti al Diagnoser, integra sempre con test di rete.
Test di connettività end‑to‑end
La priorità è validare che il PSM “problematico” raggiunga i RDSH sulla 3389/TCP. Esegui test mirati dal PSM interessato:
# Dal PSM: test TCP puro verso ciascun RDSH
Test-NetConnection -ComputerName RDSH-A.contoso.local -Port 3389 -InformationLevel Detailed
Test-NetConnection -ComputerName RDSH-B.contoso.local -Port 3389 -InformationLevel Detailed
In alternativa con PsPing (Sysinternals) se disponibile
psping RDSH-A.contoso.local:3389
Se tnc fallisce dal PSM ma funziona da un altro host, il problema è sulla path del PSM.
Se i test falliscono, esegui un packet capture leggero per capire dove si ferma il flusso:
# Sul PSM o sul RDSH (a seconda di dove hai accesso)
Traccia di base con netsh (non invasiva)
netsh trace start capture=yes scenario=NetConnection tracefile=C:\Temp\rdp_trace.etl
Riproduci il problema, poi:
netsh trace stop
Nei casi di blocco inbound vedrai SYN → senza il corrispondente ← SYN/ACK di ritorno.
Audit del firewall e delle ACL
Il caso reale è stato risolto scoprendo che mancava una regola in ingresso per le nuove subnet RDSH. Due strategie efficaci:
- Regola mirata per sorgenti PSM: consenti TCP 3389 dai due PSM verso i RDSH.
- Regola per subnet autorizzate: consenti TCP 3389 dalle VLAN di salto/broker verso i RDSH. Più scalabile se aggiungi in futuro altri broker.
Esempi con Windows Defender Firewall (RDSH)
# Visualizza le regole RDP esistenti
netsh advfirewall firewall show rule name="Remote Desktop*" verbose
Crea una regola specifica per i PSM (sostituisci IP/Subnet)
netsh advfirewall firewall add rule name="ALLOWRDPFROM_PSM" dir=in action=allow protocol=TCP `
localport=3389 remoteip=10.50.20.15,10.50.20.16 profile=domain
Variante per intere subnet PSM
netsh advfirewall firewall add rule name="ALLOWRDPFROMPSMSUBNET" dir=in action=allow protocol=TCP `
localport=3389 remoteip=10.50.20.0/24 profile=domain
Nota su UDP 3389: l’RDP moderno usa anche UDP 3389 per ottimizzare la qualità, ma non è necessario per la negoziazione delle licenze. Aprilo se desideri prestazioni migliori.
Validazioni post‑fix
- Gli utenti via PSM stabiliscono la sessione senza errori e ricevono User CAL secondo il Diagnoser.
- Sui RDSH non compaiono più errori critici; monitora gli ID 4105/4106 (TermService) e il log RemoteDesktopServices‑Licensing.
- Il contatore delle licenze disponibili/assegnate riflette l’attività degli utenti.
Matrice rete e porte da conoscere
| Sorgente | Destinazione | Porte/Protocolli | Motivo |
|---|---|---|---|
| CyberArk PSM | RDSH | TCP 3389 (necessaria), UDP 3389 (opzionale) | Canale RDP principale. Senza 3389/TCP la sessione non nasce e la CAL non può essere emessa. |
| RDSH | RDS License Server | TCP 135 + porte RPC dinamiche (in genere 49152‑65535) | Comunicazione per la gestione delle licenze (richiesta/assegnazione/aggiornamento). |
| RDS License Server | AD DS (se in uso) | LDAP/LDAPS, Kerberos, DNS | Risoluzione e pubblicazione attributi di licenza nel dominio. |
Pratica consigliata: se segmenti le reti, documenta le ACL in una tabella come questa e versionale in un repo interno. Gli errori “una porta dimenticata” sono la causa n.1 dei falsi problemi di licensing.
Runbook operativo (riutilizzabile)
- Conferma la modalità di licenza (Per‑User) su GPO/Registro e l’elenco dei License Server.
- Testa RDP 3389 dal PSM “non funzionante” verso tutti i RDSH (usa
Test-NetConnectionopsping). - Se fallisce, cattura pacchetti o una netsh trace per verificare l’assenza di SYN/ACK.
- Correggi le ACL (firewall locale, firewall perimetrale, NGFW). Applica regole inbound dai PSM alle subnet RDSH su TCP 3389.
- Ritesta: apri sessioni multiple via entrambi i PSM e verifica l’emissione delle User CAL.
- Monitora eventi 4105/4106 e il log TerminalServices‑Licensing. Imposta alert su variazioni anomale.
Buone pratiche aggiuntive
- Verifiche di base: prima di concentrarti su RDS, assicurati che il traffico RDP sia consentito su tutta la path di rete e che non vi siano dispositivi NAT/firewall che alterano le porte.
- Licensing Diagnoser: usa lo strumento integrato per rilevare rapidamente mismatch di versione o CAL esaurite, ma integra sempre con test di rete (Telnet/PortQry/PsPing).
- CyberArk / PAM: quando si interpongono dispositivi di session brokering, testa sia la connettività broker → RDSH sia (se pertinente alla tua architettura) broker → License Server. Bastano poche porte bloccate per inibire l’emissione delle licenze.
- Monitoraggio continuo: registra gli eventi ID 4105/4106 (TermService) e gli errori nel log RemoteDesktopServices‑Licensing per rilevare tempestivamente problemi futuri.
Approfondimenti pratici
Per‑User vs Per‑Device: cosa cambia nel troubleshooting
| Aspetto | Per‑User CAL | Per‑Device CAL |
|---|---|---|
| Enforcement sul RDSH | Spesso non “bloccante” in tempo reale; il Diagnoser avvisa. | Più rigoroso: i device possono trovarsi senza CAL valide. |
| Segnali tipici | Avvisi nel Diagnoser, ma la sessione nasce se la rete è ok. | Rifiuto di nuove connessioni quando le CAL sono esaurite o non aggiornate. |
| Impatto del problema di rete | Blocca la sessione prima della licenza → falso positivo licensing. | Idem: la sessione non nasce, indipendentemente dalle CAL. |
Eventi e log da tenere d’occhio
- Applications and Services Logs → Microsoft → Windows → TerminalServices‑LocalSessionManager/Operational: creazione/chiusura sessioni.
- … → TerminalServices‑RemoteConnectionManager/Operational: negoziazione connessione.
- … → RemoteDesktopServices‑Licensing: esito delle richieste di licenza, errori di contatto con il Licensing Server.
- System: eventuali drop del firewall, problemi di rete, driver.
Verifiche rapide lato RDSH
# 1) Porta RDP locale effettivamente in ascolto
(Get-NetTCPConnection -LocalPort 3389 -State Listen) -ne $null
2) Connettività verso il Licensing Server (RPC 135)
Test-NetConnection -ComputerName RDLS.contoso.local -Port 135
3) Health di base dei servizi RDS
Get-Service -Name TermService, UmRdpService | Format-Table -Auto
Come evitare che il problema si ripresenti
- Modello di regole “a gruppi”: crea un gruppo firewall “RDP‑Brokers” con gli IP dei PSM e referenzialo in un’unica regola. Quando aggiungi un nuovo PSM, aggiorni solo il gruppo.
- Change management: ogni introduzione di nuove subnet RDSH deve prevedere uno step di apertura porte con check‑list firmata.
- Test sintetici schedulati: uno script che ogni 5 minuti lancia
Test-NetConnectiondai PSM verso i RDSH e invia alert se fallisce (integra con il tuo sistema di monitoring).
FAQ
Perché vedevo solo due connessioni contemporanee?
Perché le sessioni via PSM non nascevano (blocco 3389/TCP) e le uniche connessioni operative erano quelle di amministrazione diretta, che per design sono limitate. Sbloccato il percorso PSM → RDSH, la capacità utente è tornata normale.
È obbligatorio che il PSM raggiunga il Licensing Server?
No: la catena standard è RDSH ↔ Licensing Server. Tuttavia, in architetture complesse o con controlli proxy/L7 tra PSM e RDSH, testare anche il percorso PSM → Licensing Server può aiutare a scovare regole errate o scenari non standard.
Devo aprire anche le porte RPC dinamiche dal PSM?
No. Le porte RPC dinamiche servono tra RDSH e Licensing Server. Dal PSM verso i RDSH basta la 3389/TCP (e facoltativamente 3389/UDP).
Come capisco se il problema è davvero di licensing e non di rete?
Se Test-NetConnection su 3389 fallisce dal PSM verso i RDSH, è prima di tutto un problema di rete. Se invece la 3389 è aperta ma i log RemoteDesktopServices‑Licensing mostrano errori di contatto con il Licensing Server o esaurimento CAL, allora indaga il licensing.
Checklist finale (da stampare)
- ✔️ GPO/Registro coerenti: modalità Per‑User e License Server specificato.
- ✔️ PSM → RDSH 3389/TCP raggiungibile da entrambi i PSM.
- ✔️ RDSH → Licensing Server su 135/TCP + porte dinamiche abilitato (o range ristretto documentato).
- ✔️ Log puliti: nessun 4105/4106 ricorrente; Diagnoser senza errori bloccanti.
- ✔️ Monitor attivo con alert su latenza/porte chiuse e sugli eventi RDS.
Conclusioni
Quando le User CAL non “si rilasciano” e il Session Host “sembra” limitato a due sessioni, la tentazione è di scavare solo nel licensing. Questo caso dimostra l’opposto: se la porta RDP 3389/TCP è bloccata lungo la path (qui tra un CyberArk PSM e i RDSH), la negoziazione della licenza non parte e si cade in un falso allarme di CAL. La correzione è stata semplice e strutturale: una regola firewall inbound per consentire il traffico dai PSM alle nuove subnet RDSH. Da quel momento, le sessioni RDP si sono instaurate regolarmente e le licenze per‑utente sono state emesse senza ritardi.
Porta con te due messaggi: 1) rete prima di licensing; 2) standardizza le ACL e monitora costantemente. Ridurrai drasticamente i tempi di fermo e i falsi positivi.
Appendice: snippet utili
Script PowerShell di verifica con report
# Imposta host e License Server
$rdsh = @("RDSH-A.contoso.local","RDSH-B.contoso.local")
$psm = @("PSM-01.contoso.local","PSM-02.contoso.local")
$ls = "RDLS.contoso.local"
Test 3389 dai PSM ai RDSH (richiede WinRM e credenziali adeguate)
$results = foreach($p in $psm){
foreach($h in $rdsh){
try{
Invoke-Command -ComputerName $p -ScriptBlock {
param($target)
$r = Test-NetConnection -ComputerName $target -Port 3389 -WarningAction SilentlyContinue
[pscustomobject]@{
From = $env:COMPUTERNAME
To = $r.ComputerName
Reach = $r.TcpTestSucceeded
Latency = if($r.TcpTestSucceeded){$r.PingReplyDetails.RoundtripTime}else{$null}
}
} -ArgumentList $h -ErrorAction Stop
} catch {
[pscustomobject]@{ From=$p; To=$h; Reach=$false; Latency=$null }
}
}
}
$results | Sort-Object From,To | Format-Table -Auto
Test RPC 135 dal RDSH al License Server
$rdsh | ForEach-Object {
Test-NetConnection -ComputerName $ls -Port 135 |
Select-Object ComputerName, RemotePort, TcpTestSucceeded
}
Regole firewall “modellate” per subnet
# Regola unica che consente RDP da più subnet PSM
netsh advfirewall firewall add rule name="ALLOWRDPFROMPSMVLANS" dir=in action=allow protocol=TCP `
localport=3389 remoteip=10.50.20.0/24,10.60.30.0/24 profile=domain
Abilitare rapidamente i log RDP
# LocalSessionManager e RemoteConnectionManager (su RDSH)
wevtutil sl "Microsoft-Windows-TerminalServices-LocalSessionManager/Operational" /e:true
wevtutil sl "Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational" /e:true
Caso reale in una riga
Root‑cause: mancava una regola firewall in ingresso per le nuove subnet RDSH. Fix: sblocco TCP 3389 dai CyberArk PSM verso i RDSH. Effetto: sessioni ripristinate e User CAL rilasciate immediatamente.
