rzlbrnft
Goto Top

Domänenverwaltung auf Admin VM als Remoteapp bereitstellen

Hallo zusammen,

Ich würde gerne folgendes erreichen.

Wir haben eine Remotedesktop Server Farm im Einsatz mit zwei RD Broker Servern und Hochverfügbarkeit.
Ich hab mir zwei neue VMs installiert, auf denen nur Tools für die Serververwaltung installiert sind.
Dann hab ich eine neue Bereitstellung auf dem RD Broker eingerichtet, in der die neuen Admin Kisten sind, und die Verwaltungstools als Remoteapp bereitgestellt. So weit so gut.

Die restlichen Remoteapps werden mit delegierten Anmeldeinformationen aufgerufen, um Single Sign On zu ermöglichen.

Allerdings würde ich gerne erreichen, das dann bei diesen Tools die aktuellen Anmeldeinformationen nicht delegiert werden, sondern ein Anmeldefenster kommt.
Mein Problem ist, es kommt auch bei diesen Tools kein Anmeldefenster, die Anmeldung wird sofort durchgeführt, und schlägt dann fehl, weil mein normaler User sich natürlich nicht an der Admin Kiste anmelden darf.
Ich finde dazu keine Konfigurationsoption. Im Prinzip müsste bei den bereitgestellten RDP Dateien eigentlich nur der Haken aktiv sein, das immer Anmeldeinformationen angefordert werden.
Ziel wäre, das dann eine Abfrage nach Credentials kommt, bei der ich mich dann mittels des Zertifikats auf meinem Yubikey anmelde, das ganze aber trotzdem über den bestehenden hochverfügbaren RD Broker bereitgestellt wird. Die Kiste soll quasi Tier 3 der Administrationebene mit Domänenrechten darstellen.

Habt ihr eine Idee wie ich das anstellen könnte?

Content-ID: 63021983772

Url: https://administrator.de/forum/domaenenverwaltung-auf-admin-vm-als-remoteapp-bereitstellen-63021983772.html

Ausgedruckt am: 23.12.2024 um 01:12 Uhr

DerWoWusste
Lösung DerWoWusste 30.08.2023 um 15:33:36 Uhr
Goto Top
Starte mstsc.exe auf deinem PC als anderer Nutzer per Skript, welches schon den Yubikey-PIN-Dialog triggert.

Beispiel:
Function Get-SmartCardCred{
<#
.SYNOPSIS
Get certificate credentials from the user's certificate store.  

.DESCRIPTION
Returns a PSCredential object of the user's selected certificate.  

.EXAMPLE
Get-SmartCardCred
UserName                                           Password
--------                                           --------
@@BVkEYkWiqJgd2d9xz3-5BiHs1cAN System.Security.SecureString

.EXAMPLE
$Cred = Get-SmartCardCred

.OUTPUTS
[System.Management.Automation.PSCredential]

.NOTES
Author: Joshua Chase
Last Modified: 01 August 2018
C# code used from https://github.com/bongiovimatthew-microsoft/pscredentialWithCert
#>
[cmdletbinding()]
param()

    $SmartCardCode = @"  
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Management.Automation;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography.X509Certificates;


namespace SmartCardLogon{

    static class NativeMethods
    {

        public enum CRED_MARSHAL_TYPE
        {
            CertCredential = 1,
            UsernameTargetCredential
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct CERT_CREDENTIAL_INFO
        {
            public uint cbSize;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            public byte[] rgbHashOfCert;
        }

        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]  
        public static extern bool CredMarshalCredential(
            CRED_MARSHAL_TYPE CredType,
            IntPtr Credential,
            out IntPtr MarshaledCredential
        );

        [DllImport("advapi32.dll", SetLastError = true)]  
        public static extern bool CredFree([In] IntPtr buffer);

    }

    public class Certificate
    {

        public static PSCredential MarshalFlow(string thumbprint, SecureString pin)
        {
            //
            // Set up the data struct
            //
            NativeMethods.CERT_CREDENTIAL_INFO certInfo = new NativeMethods.CERT_CREDENTIAL_INFO();
            certInfo.cbSize = (uint)Marshal.SizeOf(typeof(NativeMethods.CERT_CREDENTIAL_INFO));

            //
            // Locate the certificate in the certificate store 
            //
            X509Certificate2 certCredential = new X509Certificate2();
            X509Store userMyStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
            userMyStore.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection certsReturned = userMyStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
            userMyStore.Close();

            if (certsReturned.Count == 0)
            {
                throw new Exception("Unable to find the specified certificate.");  
            }

            //
            // Marshal the certificate 
            //
            certCredential = certsReturned[0];
            certInfo.rgbHashOfCert = certCredential.GetCertHash();
            int size = Marshal.SizeOf(certInfo);
            IntPtr pCertInfo = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(certInfo, pCertInfo, false);
            IntPtr marshaledCredential = IntPtr.Zero;
            bool result = NativeMethods.CredMarshalCredential(NativeMethods.CRED_MARSHAL_TYPE.CertCredential, pCertInfo, out marshaledCredential);

            string certBlobForUsername = null;
            PSCredential psCreds = null;

            if (result)
            {
                certBlobForUsername = Marshal.PtrToStringUni(marshaledCredential);
                psCreds = new PSCredential(certBlobForUsername, pin);
            }

            Marshal.FreeHGlobal(pCertInfo);
            if (marshaledCredential != IntPtr.Zero)
            {
                NativeMethods.CredFree(marshaledCredential);
            }
        
            return psCreds;
        }
    }
}
"@  

    Add-Type -TypeDefinition $SmartCardCode -Language CSharp
    Add-Type -AssemblyName System.Security

    $ValidCerts = [System.Security.Cryptography.X509Certificates.X509Certificate2[]](Get-ChildItem 'Cert:\CurrentUser\My')  
    $Cert = [System.Security.Cryptography.X509Certificates.X509Certificate2UI]::SelectFromCollection($ValidCerts, 'Choose a certificate', 'Choose a certificate', 0)  

    $Pin = Read-Host "Enter your PIN: " -AsSecureString  

    Write-Output ([SmartCardLogon.Certificate]::MarshalFlow($Cert.Thumbprint, $Pin))
}
$cred=Get-SmartCardCred
$StartInfo = New-Object System.Diagnostics.ProcessStartInfo
$StartInfo.FileName = 'mstsc'  
$StartInfo.UseShellExecute = $false
$StartInfo.Arguments = "v c:\temp\dein.rdp"  
$StartInfo.UserName = $Cred.Username
$StartInfo.Password = $Cred.Password
$StartInfo.WorkingDirectory = $env:windir
$StartInfo.LoadUserProfile = $true
$Process = New-Object System.Diagnostics.Process
$Process.StartInfo = $StartInfo
$Process.Start()
$Cred = $null

Ja, das seiht kompliziert aus, geht aber nicht einfacher.
rzlbrnft
rzlbrnft 30.08.2023 aktualisiert um 16:18:21 Uhr
Goto Top
Nur eine Verbindung per RDP mit Smartcard bereitstellen geht einfacher, da brauche ich nur den Haken setzen, der die Anmeldemaske immer triggert. Im Moment nutze ich kein Fido2 und kein OpenPGP, die Smartcard Funktion ist relativ überschaubar. Sobald eine Smartcard steckt, wird die auch für die Anmeldung angezeigt.

Ich würde das ganze aber gerne über die "Work Resources" automatisch verteilen, und da scheitert es leider noch.
DerWoWusste
DerWoWusste 30.08.2023 um 16:20:17 Uhr
Goto Top
Nur eine Verbindung per RDP mit Smartcard bereitstellen geht einfacher, da brauche ich nur den Haken setzen, der die Anmeldemaske immer triggert.
Das stimmt nur, sofern man die Sicherheits-Best-practice remote Credentialguard weglässt. Sonst ist der Haken nämlich ausgegraut.

Da die RemoteApps (Work resources) auch RDP-Dateien sind, könntest Du meinen Weg gehen. Die Verteilung müsstest Du selbst bauen.
rzlbrnft
Lösung rzlbrnft 31.08.2023 um 10:42:46 Uhr
Goto Top
Ok, hab es jetzt gelöst bekommen, einfach eine komplett neue Bereitstellung erstellt. Eine der Admin Kisten ist jetzt halt auch RD Broker. Man muss die zweite Work Resources URL dann zwar von Hand eingeben, aber das sollte ein Admin hinkriegen, so viele sind es ja nicht.

Remote Credential Guard hab ich mir angeschaut, ich find aber keine Option, das in die Work Resources automatisch zu integrieren, ohne das ich es auf dem Client für alle RDP Verbindungen aktiviere.

Eventuell würd ich das dann auf gesondert auf allen Admin PCs aktivieren, die für die Verbindung zu den Verwaltungs VMs freigeschalten sind in der Windows Firewall, ich würd aber gerne alles in Gruppenrichtlinien festlegen, ohne bei neuen Maschinen manuell Hand anlegen zu müssen.
Dani
Dani 31.08.2023 um 19:09:06 Uhr
Goto Top
Moin,
Ok, hab es jetzt gelöst bekommen, einfach eine komplett neue Bereitstellung erstellt. Eine der Admin Kisten ist jetzt halt auch RD Broker. Man muss die zweite Work Resources URL dann zwar von Hand eingeben, aber das sollte ein Admin hinkriegen, so viele sind es ja nicht.
sowas würde ich grundsätzlich separat laufen und verwalten wollen. Keinerlei direkten Abhängigkeiten wie RDCB und RDGW, etc.


Gruß,
Dani
rzlbrnft
rzlbrnft 06.09.2023 aktualisiert um 16:22:56 Uhr
Goto Top
Werd es jetzt doch anders regeln, es gibt dann halt nur eine Admin Maschine an der sich nur Domadmins mit Smartcard anmelden können. Die gleichzeitige Anzeige zweier Deployments im Servermanager hat dann leider eine Fehlermeldung erzeugt.

Falls das noch jemand so machen möchte, um die ServerManager App direkt zu starten braucht man noch einen Registry Eintrag. Die erzeugte Remote App konnte ich mittels des obigen Scripts nicht ausführen und ohne den Broker hat meine Bereitstellung nicht funktioniert.
https://admx.help/?Category=Windows_10_2016&Policy=Microsoft.Policie ...

In der RDP Datei trägt man dann die Anwendung ein, die gestartet werden soll, in meinem Fall den Servermanager.
Das ist hier beschrieben.
https://talk-about-it.ca/creating-remoteapp-rdp-sessions/

Die Textdateien kann man dann auch per GPO verteilen, lediglich die Smartcards muss man einmal manuell erzeugen.

Danke für die Tipps.
rzlbrnft
rzlbrnft 07.09.2023 aktualisiert um 13:21:00 Uhr
Goto Top
Eine Frage noch zur Logik hinter Remote Credential Guard. Ist es nicht eigentlich unsicherer, auf dem unsicheren Client die Login Daten per Runas an Single Sign On zu übergeben, als auf dem gehärteten Host ohne jegliche 3rd Party Software die Smartcard Daten abzufragen?
Da könnte doch auch die Möglichkeit bestehen, diese Daten während des Login Vorgangs zu kapern.

Meines Erachtens wäre ja dann der richtige Weg, sich per Smartcard auf dem gehärteten Admin Server OHNE Credential Guard und mit Smartcard anzumelden und bei Bedarf von dort aus eine RDP Verbindung MIT Credential Guard auf den DC direkt zu machen, oder hab ich da einen Denkfehler?
DerWoWusste
DerWoWusste 07.09.2023 um 13:25:34 Uhr
Goto Top
Das ist schwer zu beantworten. Wann immer man Systeme in der Gleichung drin hat, die unsicher sind, ist es ingesamt nicht maximal sicher. Wenn Du eine privileged access Workstation hast, dann macht man die so sicher wie möglich und es ist kein Alltagscomputer mit ansonsten normalen Regeln. An dieser PAW kann man davon ausgehen, dass man auch Credentials eingeben kann - jedoch kommt schon die nächste Frage: wogegen sichert man ab? Gegen Credentials im Speicher der PAW oder gegen Abgreifen der Eingaben auf der PAW (z.B. Keyboard oder Zwischenablage)?

Ich gehe davon aus, dass auf Windowsdomänen es sowohl legitim ist, sich an der PAW mit den stärksten Konten anzumelden, als auch von der PAW per RDP oder RSAT zum DC und dort die credentials einzugeben. In beiden Fällen würde eine verseuchte PAW nahezu gleichen Schaden anrichten können.