Windows Server 2019 RDS : CAL « par utilisateur » non délivrées via CyberArk PSM — corriger le blocage pare‑feu TCP 3389

Un cas réel de Windows Server 2019 RDS : limitation à deux connexions RDP malgré 20 CAL « par utilisateur ». Diagnostic, cause racine (pare‑feu), correctif et checklists prêtes à l’emploi pour éviter que cela ne se reproduise.

Sommaire

Contexte et symptômes

Dans un environnement composé de deux hôtes de sessions RDS (RDSH) et d’un serveur de licences RDS configuré en mode « Par utilisateur » (20 CAL activées), un comportement paradoxal survient : lorsqu’un troisième utilisateur tente d’ouvrir une session via l’un des flux, un message impose de déconnecter un des deux utilisateurs déjà connectés. Aucune CAL n’est émise, alors même que l’outil de diagnostic de licences affiche 20 CAL disponibles.

  • Hôtes RDSH : Windows Server 2019.
  • Serveur de licences : Windows Server 2019, CAL RDS « User » activées (20).
  • PAM : CyberArk PSM en redirection RDP (deux serveurs PSM agissant comme brokers).
  • Symptôme principal : blocage à 2 sessions lorsque la connexion transite par le deuxième PSM.

À retenir : quand RDP ne parvient pas à établir une session de bout en bout, la négociation de licence ne démarre pas ; le serveur de licences reste « muet », d’où l’absence d’attribution de CAL malgré la disponibilité.

Architecture en un clin d’œil

Utilisateur RDP
     │
     ├──► PSM#1  ──► RDSH#A / RDSH#B  ──► Serveur de licences RDS
     │
     └──► PSM#2  ──X (3389 bloqué vers RDSH) ──► ... (négociation de CAL jamais atteinte)
  

Le flux via PSM#1 fonctionne (les CAL sont délivrées), alors que le flux via PSM#2 échoue avant la phase de négociation RDS, ce qui explique le plafond observé de deux sessions.

Analyse structurée du problème

Paramétrage local (GPO & Registre)

  • Mode de licence « Par utilisateur » correctement défini par GPO.
  • Adresse du serveur de licences renseignée.

Compatibilité des versions

  • OS des RDSH, serveur de licences et version des CAL : Windows Server 2019 (conformes).

Piste PAM / Broker (CyberArk PSM)

  • Les sessions RDP sont initiées vers deux PSM jouant le rôle de relais.
  • Tests hors PAM avec comptes AD stand‑alone : CAL attribuées, aucune limite à 2.
  • Anomalie uniquement quand la session passe via PSM#2.

Tests réseau

  • Depuis PSM#2, la tentative d’ouverture TCP 3389 vers les RDSH échoue ; on observe un SYN sans réponse/ACK côté PSM.
  • Journaux réseau internes : pas de blocage explicitement consigné entre PSM et RDSH, mais des sous‑réseaux récents n’étaient pas couverts par les règles.

Note terrain : lorsque la redirection échoue, les utilisateurs restent en session locale sur le PSM. Si ce PSM n’exécute pas un rôle RDSH correctement licencié, il est soumis à la limite Windows par défaut de deux connexions administratives, ce qui produit un message trompeur « déconnectez un utilisateur ».

Ce qui se passe techniquement (RDP & licences)

  1. Handshake RDP/TLS/CredSSP entre le client et le PSM : création du canal sécurisé.
  2. Le PSM ouvre ensuite une nouvelle session RDP vers le RDSH cible (TCP 3389).
  3. Si le handshake PSM→RDSH échoue (pare‑feu, routage, NAT, inspection), la chaîne n’atteint jamais l’hôte RDSH.
  4. La négociation de licence (mode « User ») n’est déclenchée qu’une fois la session établie et l’authentification réalisée sur le RDSH. En l’absence de session, aucune CAL n’est délivrée.
  5. Résultat visuel : limite à deux connexions observée (sur le PSM ou perçue comme RDSH), alors que le serveur de licences affiche toujours 20 CAL disponibles.

Cause racine

Une règle entrante manquante sur le pare‑feu interne pour les nouveaux sous‑réseaux hébergeant les RDSH bloquait les connexions TCP 3389 provenant de PSM#2. Sans handshake TCP valide PSM→RDSH, la session ne basculait jamais sur l’hôte de destination et la délivrance des CAL ne pouvait pas se produire.

Solution mise en œuvre

  • Ajout d’une règle pare‑feu autorisant TCP 3389 depuis le sous‑réseau de PSM#2 vers les hôtes RDSH des nouveaux segments.
  • Re‑tests de bout en bout : les sessions transitent désormais via PSM#2, les CAL sont délivrées, plus de limitation à deux utilisateurs.
# Exemple (pare-feu Windows sur un RDSH)
netsh advfirewall firewall add rule name="RDP from PSM#2" dir=in action=allow protocol=TCP localport=3389 remoteip=10.20.30.0/24 profile=domain

# Exemple (vérifier la prise en compte)

netsh advfirewall firewall show rule name="RDP from PSM#2" verbose=enable </code></pre>

  <p>Si le contrôle est assuré par un pare‑feu réseau central, mettez à jour les objets d’adressage (groupes d’IP, balises) et <strong>documentez les nouveaux sous‑réseaux</strong> dans la matrice de flux.</p>
</section>

<section>
  <h2>Procédure de dépannage reproductible</h2>
  <h3>1) Vérifier les paramètres RDS (GPO &amp; Registre)</h3>
  <ul>
    <li>GPO&nbsp;: <code>Configuration ordinateur ▸ Modèles d'administration ▸ Services Bureau à distance ▸ Hôte de session ▸ Licences</code></li>
    <li>Vérifier&nbsp;: « Définir le mode de licences&nbsp;» et « Utiliser les serveurs de licences spécifiés ».</li>
  </ul>
  <pre><code># Lire les clés de stratégie sur un RDSH
Get-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" |
  Select-Object LicensingMode, LicenseServers

# (Rappel courant) LicensingMode : 2 = Par périphérique ; 4 = Par utilisateur

</code></pre>

  <pre><code># Vérifier l'application des GPO
gpresult /r /scope:computer
  </code></pre>

  <h3>2) Tester la connectivité RDP depuis chaque point intermédiaire</h3>
  <p>Testez explicitement depuis <strong>PSM#1</strong> <em>et</em> <strong>PSM#2</strong> vers chaque RDSH&nbsp;:</p>
  <pre><code># Depuis PSM#2, vers chaque RDSH
Test-NetConnection RDSH-A -Port 3389 -InformationLevel Detailed
Test-NetConnection RDSH-B -Port 3389 -InformationLevel Detailed
tnc RDSH-A -Port 3389 -TraceRoute
  </code></pre>
  <p><strong>Attendu</strong>&nbsp;: <em>TCPTestSucceeded: True</em>. Si échec, inspectez route, NAT, inspection SSL/TLS, règles <em>stateful</em> et profils de pare‑feu (Domaine/Privé/Public).</p>

  <h3>3) Examiner les journaux pertinents</h3>
  <table>
    <thead>
      <tr><th>Composant</th><th>Journal</th><th>Ce qu’il faut chercher</th></tr>
    </thead>
    <tbody>
      <tr>
        <td>RDSH</td>
        <td>Microsoft‑Windows‑RemoteDesktopServices‑RdpCoreTS/Operational</td>
        <td>Échecs de handshake, déconnexions précoces, NLA/TLS</td>
      </tr>
      <tr>
        <td>RDSH</td>
        <td>TerminalServices‑LocalSessionManager/Operational</td>
        <td>Créations/suppressions de sessions, limites atteintes</td>
      </tr>
      <tr>
        <td>Serveur de licences</td>
        <td>TerminalServices‑Licensing</td>
        <td>Événements d’attribution (4105/4106), pénuries éventuelles</td>
      </tr>
      <tr>
        <td>PSM</td>
        <td>Logs applicatifs PSM</td>
        <td>Erreurs de connexion sortante RDP vers les RDSH</td>
      </tr>
    </tbody>
  </table>
  <pre><code># Exemple de lecture rapide (PowerShell)
Get-WinEvent -LogName "Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational" -MaxEvents 50 |
  Format-Table TimeCreated, Id, Message -Wrap
  </code></pre>

  <h3>4) Valider que l’on n’est pas «&nbsp;resté&nbsp;» sur le PSM</h3>
  <p>Si la redirection échoue, les utilisateurs consomment des sessions locales PSM. Si le PSM n’est pas configuré comme RDSH licencié&nbsp;: <strong>plafond à 2</strong>. C’est un indicateur fort d’un problème <em>amont</em> (PSM→RDSH).</p>

  <h3>5) Contrôler les flux réseau minimaux</h3>
  <table>
    <thead>
      <tr><th>De</th><th>Vers</th><th>Ports</th><th>Remarque</th></tr>
    </thead>
    <tbody>
      <tr>
        <td>Utilisateur</td>
        <td>PSM</td>
        <td>TCP&nbsp;3389</td>
        <td>Session RDP initiale</td>
      </tr>
      <tr>
        <td>PSM</td>
        <td>RDSH</td>
        <td>TCP&nbsp;3389</td>
        <td><strong>Critique</strong>&nbsp;: c’est ici que le blocage a été observé</td>
      </tr>
      <tr>
        <td>RDSH</td>
        <td>Serveur de licences</td>
        <td>TCP&nbsp;135 + ports dynamiques RPC</td>
        <td>Négo/émission des CAL (mode « User »)</td>
      </tr>
      <tr>
        <td>RDSH</td>
        <td>Contrôleurs de domaine</td>
        <td>88/389/445/53, etc.</td>
        <td>Auth Kerberos/LDAP, DNS, SMB</td>
      </tr>
    </tbody>
  </table>

  <h3>6) Appliquer et tester la règle pare‑feu</h3>
  <p>Autoriser <strong>TCP&nbsp;3389</strong> du sous‑réseau de <strong>PSM#2</strong> vers les RDSH (et uniquement cela). Vérifiez aussi la <em>règle de retour</em> si votre pare‑feu est asymétrique ou si une inspection applicative est active.</p>

  <h3>7) Re‑tester la délivrance des CAL</h3>
  <ul>
    <li>Reconnecter via <strong>PSM#2</strong> → ouvrir une session sur un RDSH.</li>
    <li>Vérifier sur le serveur de licences que la <strong>CAL « User »</strong> est bien consignée (délai possible côté enregistrement).</li>
  </ul>

  <h3>8) Documenter et prévenir la régression</h3>
  <ul>
    <li>Mettre à jour la <strong>matrice de flux</strong> (PSM↔RDSH) en incluant les <em>nouveaux sous‑réseaux</em>.</li>
    <li>Ajouter un <strong>test de santé</strong> périodique (script <code>Test-NetConnection</code> multi‑cibles) et une alerte sur les journaux RDS.</li>
  </ul>
</section>

<section>
  <h2>Validations post‑correctif (checklist)</h2>
  <ul>
    <li>Ouverture de session via <strong>PSM#2</strong>&nbsp;: ok et rapide (&lt; 3–5 s de handshake RDP).</li>
    <li>Sur RDSH&nbsp;: la session de l’utilisateur apparaît (<code>qwinsta /server:RDSH-A</code>).</li>
    <li>Sur le serveur de licences&nbsp;: trace d’attribution/validation de CAL pour l’utilisateur.</li>
    <li>Plus de message « déconnecter un utilisateur ».</li>
    <li>Monitoring&nbsp;: absence d’événements d’échec dans <em>RdpCoreTS/Operational</em>.</li>
  </ul>
</section>

<section>
  <h2>Bonnes pratiques et contrôles de cohérence</h2>
  <table>
    <thead>
      <tr>
        <th>Axe</th>
        <th>Points de contrôle utiles</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><strong>Licences</strong></td>
        <td>
          • Vérifier la cohérence « Par utilisateur »/« Par périphérique » entre GPO et registre.<br>
          • S’assurer que la version du serveur de licences ≥ version des CAL ≥ version des RDSH.<br>
          • Aligner <em>tous</em> les PSM si l’un d’eux joue aussi le rôle RDSH (sinon 2&nbsp;sessions max).
        </td>
      </tr>
      <tr>
        <td><strong>Réseau</strong></td>
        <td>
          • Tester la connectivité TCP&nbsp;3389 depuis chaque point intermédiaire (PSM, jump, VPN).<br>
          • Maintenir une matrice de flux à jour et une procédure de mise à jour lors de l’ajout de sous‑réseaux.<br>
          • Sur pare‑feu <em>stateful</em>, auditer aussi le chemin de retour et l’éventuelle inspection TLS.
        </td>
      </tr>
      <tr>
        <td><strong>Diagnostics</strong></td>
        <td>
          • Utiliser <em>RD Licensing Diagnoser</em>&nbsp;: onglet « Problems detected », événements 4105/4106.<br>
          • Surveiller <em>TerminalServices‑Licensing</em> et <em>RemoteDesktopServices‑RdpCoreTS</em>.<br>
          • En cas de doute, capturer un <em>netsh trace</em> sur PSM et RDSH au moment du handshake.
        </td>
      </tr>
      <tr>
        <td><strong>Intégrations PAM</strong></td>
        <td>
          • Pour CyberArk PSM&nbsp;: valider la configuration des connexions (cibles, certificats, résolution DNS).<br>
          • Documenter les dépendances réseau entre PSM, RDSH et serveur de licences (RPC inclus).
        </td>
      </tr>
      <tr>
        <td><strong>Sécurité &amp; supervision</strong></td>
        <td>
          • Mettre en place des alertes sur erreurs de licence et refus de session RDP.<br>
          • Tester l’émission de CAL après tout changement réseau ou GPO.<br>
          • Restreindre les règles 3389 aux seuls sous‑réseaux sources légitimes (principe du moindre privilège).
        </td>
      </tr>
    </tbody>
  </table>
</section>

<section>
  <h2>Commandes et extraits utiles</h2>
  <div>
    <h3>Session et état RDS</h3>
    <pre><code># Sur un RDSH
qwinsta /server:RDSH-A
query user /server:RDSH-A

# Journaux clefs

Get-WinEvent -LogName "Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational" -MaxEvents 30 |
Format-Table TimeCreated,Id,Message -Wrap
Get-WinEvent -LogName "Microsoft-Windows-TerminalServices-LocalSessionManager/Operational" -MaxEvents 30 |
Format-Table TimeCreated,Id,Message -Wrap </code></pre>

  </div>

  <div>
    <h3>Licences (lecture registre)</h3>
    <pre><code># Vérifier le mode de licence et les serveurs déclarés via stratégie
$ts = "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services"
Get-ItemProperty $ts | Format-List LicensingMode,LicenseServers

# (Rappel) Valeurs usuelles : 2 = Per Device ; 4 = Per User

```

« `

Connectivité RDP

# Tests depuis chaque PSM
Test-NetConnection RDSH-A -Port 3389 -InformationLevel Detailed
Test-NetConnection RDSH-B -Port 3389 -InformationLevel Detailed

# Trace réseau pour corréler le handshake

netsh trace start scenario=NetConnection capture=yes

# ... reproduire le problème ...

netsh trace stop 

Pare‑feu Windows (RDSH)

# Ouvrir 3389 depuis le sous-réseau PSM#2 uniquement
netsh advfirewall firewall add rule name="RDP-In from PSM#2" dir=in action=allow protocol=TCP localport=3389 remoteip=10.20.30.0/24 profile=domain
    

Variantes et pièges fréquents

  • Message « limité à 2 » trompeur : il peut provenir du serveur intermédiaire (PSM) si la redirection a échoué, pas nécessairement du RDSH cible.
  • Ports RPC pour le serveur de licences : même en mode « User », le RDSH peut contacter le serveur de licences via RPC (TCP 135 + ports dynamiques). Un blocage à ce niveau empêche l’enregistrement des CAL.
  • Noms DNS vs adresses IP : les PSM peuvent être configurés sur des noms logiques. Un split‑DNS ou un enregistrement obsolète peut aiguiller vers une IP hors périmètre des règles.
  • Inspection TLS/SSL : certaines sondes provoquent des délais ou des resets sur 3389. Désactiver l’inspection sur le flux RDP peut être nécessaire.
  • Profils de pare‑feu Windows : si un RDSH bascule en profil « Public », des règles « Domaine » ne s’appliquent plus (événements réseau, changement d’interface).

Procédure de changement (MOP) minimaliste

  1. Pré‑change : relever les sous‑réseaux PSM et RDSH, capturer l’état (Test-NetConnection, 3 tests par cible).
  2. Change : créer/ajuster la règle 3389 (source = PSM#2, destination = RDSH‑net, sens = entrées côté RDSH).
  3. Validation : rejouer les tests, ouvrir 1 session via PSM#2 sur chaque RDSH, vérifier journaux et attribution de CAL.
  4. Post‑change : mettre à jour la matrice de flux et annexer les captures d’écran/commandes exécutées.

Résumé opérationnel

Symptôme : limite à deux connexions RDS malgré 20 CAL « User ».

RCA : handshake RDP bloqué (TCP 3389) entre PSM#2 et RDSH à cause d’une règle pare‑feu manquante pour de nouveaux sous‑réseaux.

Correctif : ouverture ciblée de 3389 (source = PSM#2, destination = RDSH‑net) → sessions établies → CAL délivrées.

Checklist imprimable

  • [ ] GPO « mode de licences » = Par utilisateur, appliquée (gpresult, registre).
  • [ ] Serveur de licences déclaré (nom/DNS) et joignable (RPC si requis).
  • [ ] PSM#1→RDSH 3389 : OK — PSM#2→RDSH 3389 : OK.
  • [ ] Journaux RDP sur RDSH sans échecs de handshake.
  • [ ] Après connexion via PSM#2 : session visible sur RDSH, CAL enregistrée.
  • [ ] Matrice de flux mise à jour, alerte de supervision ajoutée.

FAQ rapide

« Pourquoi le serveur de licences affiche‑t‑il 20 CAL disponibles alors qu’aucune n’est délivrée ? »
Parce que la négociation n’a jamais été atteinte : le blocage réseau entre PSM#2 et RDSH empêche la session de se créer sur l’hôte cible. Sans session, pas de demande de CAL.

« Pourquoi exactement deux sessions ? »
En cas d’échec de redirection, la session reste localisée sur le PSM. Un PSM non configuré en RDSH licencié est limité aux deux connexions administratives natives de Windows, d’où le message.

« Quelles règles deux‑sens sont nécessaires ? »
En général, une règle entrante sur les RDSH (3389) autorisant les seuls sous‑réseaux PSM suffit, plus les flux nécessaires RDSH→Licensing (RPC) et RDSH→AD/DNS. Les flux retour sont gérés par l’état (stateful), sauf politique particulière.

Conclusion

Le cas étudié illustre un écueil courant : un symptôme « licence » peut masquer une cause réseau. En sécurisant et en documentant les flux (TCP 3389, RPC, AD), en validant les paramètres RDS par GPO/registre, et en automatisant des tests simples (Test-NetConnection), on restaure la disponibilité des sessions et on fiabilise l’émission des CAL « User » sur Windows Server 2019.

Sommaire