Three years ago this month, I described how you can use the Remote Desktop Gateway (RDG) as a Windows bastion, or jump, server to provide secure access to Windows hosts inside a private subnet in either AWS and/or Azure. Here’s a picture of how this works.
[Update 2017-08-22: see this post for a soup-to-nuts PowerShell script to configure an Azure Windows jump host. It includes the code below to configure RDG in an Azure Vnet.]
Note that it’s possible for the RDG host to connect to itself. Simply specify the internal address or DNS of the RDG host as the RDP connection destination. I do this all the time as a test — of the configuration as well as my own mind as it’s a bit of a mental twister.
But there’s always been a fly in the ointment of this otherwise standard process: configuring the RDG server itself had to be done via the UI.
This major disadvantage meant that you could use DevOps tools like Chef or Azure DSC to install the Remote Desktop role on the server — but you had to log into the machine to configure RDG itself.
Recently, I decided to see if there was a way to use PowerShell to configure a basic RDG server. You’d expect that by now, given the importance of Windows jump servers to Azure and AWS IaaS deployments, Microsoft would have shipped PowerShell cmdlets to make configuration a snap.
But all I could find was a single blog post (from 2011!) describing in very general terms a PowerShell provider for Remote Desktop Services. (If you find better doc, please leave a comment.)
PowerShell providers (see about_Providers) make everything look like a filesystem. That works well for resources like the registry (HKLM:)
and certificates (Cert:
). But I think it’s less successful for RDG.
But the main issue is that there doesn’t appear to be any documentation of what all the options are. So, you are left to issuing
Get-ChildItem RDS:\GatewayServer -Recurse | Format-List > $HOME\Desktop\RDG.txt
to discover what can be done.
The script below creates a basic RDG. It requires that the Remote Desktop Services role has already been installed. That’s a snap with almost any DevOps tool — it’s a simple Install-WindowsFeature
cmdlet. (I’ll be posting Here is an Azure DSC configuration soon showing how to do this in an Azure IaaS VM.) Here’s what it does:
- Creates a self-signed certificate and stores it on the administrator’s desktop. This cert must be installed on client machines before RDP will connect to the RDG server
- Creates a Connection Authorization Policy (RD-CAP) that authorizes local users in the
Administrators
andRemote Desktop Users
groups to access the RDG - Creates an Resource Access Policy (RD-RAP) that allows all types of redirection (file, printer, clipboard, etc.) and permits the same two groups as in the RD-CAP to access all reachable Windows hosts on TCP 3389
You will still need to open TCP 3389 on the public interface to this RDG long enough to retrieve the cert to download and install it on your client. As soon as you do that, you can eliminate TCP 3389 from the network security group in your AWS VPC or Azure VNet. Just connect to the RDG on TCP 443 via the public interface and tell your RDP client to connect you to the RDG’s private interface. This test confirms that everything is working correctly.
<# .SYNOPSIS Configure a Remote Desktop Gateway jump (bastion) server .DESCRIPTION Uses the Remote Desktop Services PowerShell provider to create/install an RD-CAP and an RD-RAP. Also creates and exports a self-signed certificate for use on connecting clients .PARAMETER dnsName FQDN of the to-be-generated self-signed certificate .OUTPUTS Self-signed cert at $HOME/desktop/$dnsName.cert .NOTES Remote Desktop Service role must exist on server before this script is run. This script adds non-AD local groups to RD-CAP and permits all accesses to back-end resources Alex Neihaus 2017-07-25 (c) 2017 Air11 Technology LLC -- licensed under the Apache OpenSource 2.0 license, https://opensource.org/licenses/Apache-2.0 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Author's blog: https://yobyot.com #> Import-Module RemoteDesktopServices # Create a self-signed certificate. This MUST be installed in the client's Trusted Root store for RDP clients to be able to use it $dnsName = "yourvmname.eastus.cloudapp.azure.com" $x509Obj = New-SelfSignedCertificate -CertStoreLocation Cert:\LocalMachine\My -DnsName $dnsName # Export the cert to the administrator's desktop for use on clients $x509Obj | Export-Certificate -FilePath "$HOME\$dnsName.cer" -Force -Type CERT # See https://blogs.technet.microsoft.com/ptsblog/2011/12/09/extending-remote-desktop-services-using-powershell-part-5/ # for details of using the RDS provider. It's very poorly documented. If you need to find additional items, sl to the GatewayServer location you are interested in # and gci . -recurse | fl # Create RD-CAP with two user groups; defaults permit all device redirection. Might be worth tightening up in terms of security. $capName = "RD-CAP-$(Get-Date -Format FileDateTimeUniversal)" Set-Location RDS:\GatewayServer\SSLCertificate #Change to location where self-signed certificate is specified Set-Item .\Thumbprint -Value $x509obj.Thumbprint # Update RDG with the thumprint of the self-signed cert. # Create a new Connection Authorization Profile New-Item -Path RDS:\GatewayServer\CAP -Name $capName -UserGroups @("administrators@BUILTIN"; "Remote Desktop Users@BUILTIN") -AuthMethod 1 # Create a new Resouce Authorization Profile with "ComputerGroupType" set to 2 to permit connections to any device $rapName = "RD-RAP-$(Get-Date -Format FileDateTimeUniversal)" New-Item -Path RDS:\GatewayServer\RAP -Name $rapName -UserGroups @("administrators@BUILTIN"; "Remote Desktop Users@BUILTIN") -ComputerGroupType 2 Restart-Service TSGateway # We're done; let's put everything into effect
Leave a Reply