Remoting Into Windows Instances — Securing RDP

Daniel Ilie
The Startup
Published in
6 min readJan 15, 2021

--

There are many ways of accessing a remote Windows instance ranging from taking a taxi to the site (just kidding…), to using native Windows solutions such as Remote Desktop Client and PowerShell (you can argue that this should read Terminal supporting PS), to using third-party solutions such as TeamViewer and AWS Systems Manager Sessions. Selecting one over the other depends on the ease of use (less experienced users prefer a GUI), requirements (parsing logs does not need a GUI — nowadays logs are actually shipped where you want them), and security/auditability (this is a SysOp Admin favorite). My personal favorite is something that is secure, auditable with a small footprint. I am not a big fan of GUI, when it comes to debugging or support, for the simple reason that it is way easier to audit a sequence of commands rather than a sequence of mouse events. All that being said…

My Use Case

Department X needs a server, on our own private subnet. Users remote desktop to the server. The organization decides to reduce the capital costs and take advantage of lower operational costs in the cloud. Using remote desktop in the same manner becomes a security issue.

Previously, the server and the client machines were located in the same subnet, protected by the organization’s firewall. However, placing a server in a public subnet in the cloud and opening port 3389 for RDP access is something to do if I wanted to fail miserably. The server can be the target to DDoS attacks, constantly probing for credentials. I could allow access to a range of IPs, but IPs are getting rotated and can be spoofed. Therefore, this would be still not secure and require continuous maintenance.

My Solution

Securing communication was solved long ago by HTTPS and certificates. More specifically, RDP can be made more secure by ensuring that all intended traffic is routed through a Remote Desktop Gateway (RDG).

I implemented this in AWS. I placed the servers that need to be remoted into in private subnets. I isolated these servers by placing them in a security group, allowing inbound traffic on Port 3389 (RDP) from the security group which protects the Remote Desktop Gateway. The RDG accepts inbound traffic from my users range of IPs on Port 443 (HTTPS) and temporarily, for configuration purposes, on Port 3389 from my own IP. I should make clear that I used only AWS security groups and have not changed any Windows firewall settings.

One would argue that the same result could have been achieved if the private subnets were instead public. I disagree. On the surface, it would appear that it does not matter that the servers may get a public IP. There are at least two reasons I can think not to do this:

  • Why expose the infrastructure if it is not necessary? (reduce footprint)
  • Should the RDG fail for any reason, someone may decide to allow direct access to the Windows instances from the internet on Port 3389. This compromises the entire security, even temporarily.

AWS Quick Starts

I decided to make this article as detailed as possible, but I discovered that AWS already done this very well by means of a Quick Start Article (CloudFormation code included) [1]. Instead of a “Me too!” article, I decided to try this for myself with the aim to discuss and annotate an otherwise good blueprint. A more step-by-step guide written by Ken Beer can also be found in this AWS Security Blog [2].

The Quick Start offers three deployment options (see Step 2 in [1]):

  1. Deploy RD Gateway into a new VPC on AWS
  2. Deploy RD Gateway into an existing VPC — standalone
  3. Deploy RD Gateway into an existing VPC — domain-joined

In my case, Option 2 was what I needed, because my project is small and already in place, when it was decided to offer this method of access. My VPC has both DNS hostnames and DNS resolution options enabled. Additionally, it has associated a DCHP Option Set with the default settings. There are a few CFN parameters that are warrant a discussion:

  1. AdminUser and AdminPassword: The stack creates a local user on the RDG, which is member of the Administrators Group.
  2. DomainDNSName: The stack specifies the fully qualified domain name which is going to be used with the RDG. This is necessary to get the security certificate issued on the RDG. The certificate can also be issued manually afterwards. In my case, I use AWS name resolution, which meant that the correct value isregion-name.compute.amazonaws.com.

Next, I RDP-ed into the RDG. I retrieved the certificate in the root drive (c:\) and created another one following these steps:

  1. Launched RD Gateway Manager
  2. Right clicked on the Server Name and select Properties
  3. In the SSL Certificate Tab, selected Create a self-signed certificate
  4. And Create and Import a Certificate
  5. Specified the IPv4 DNS name of the RDG (see EC2 instance properties)
  6. Confirmed the remaining dialogs and after the service had restarted, I reconfirmed that the certificate was installed correctly.

I retrieved this certificate and installed both certificated on the client machine using Certificate Manager. Finally, I used the following settings on the RD Connection Client:

Instance in private subnet
RD Gateway Settings

Depending on what version of Windows is running on the client machine these dialogs could differ. Note that the user account for the remote computer and the gateway may not be the same.

Ready (to RDP)? Steady (-ily connect)! Go (troubleshoot)!

I used the Administrator credentials that were created on the private server and the AdminUser credentials on the RDG.

I got the following error: “Your user account is not listed in the RD Gateway’s permission list”. This means that the Connection and/or Resource Authorization Policies (CAP & RAP) are configured incorrectly. The most common error is that there is no user group associated with them. If that is the case associate the Administrators Group. For more details read the article in [3]. Note, that the Administrator credentials of the RDG are used instead of the AdminUser that was created by CloudFormation, everything works as expected. This eliminates the possible mismatch among the RDG public DNS name, the certificate installed on the client machine and RDG Server name used in the Remote Desktop Connection Client.

However, in my scenario everything looked fine: the AdminUser was a member of the Administrators Group and the this group was listed in the CAP and RAP on the Remote Desktop Gateway. I decided to add the AdminUser to a newly created group AdminUsers. I have then added this group into the CAP and RAP. I restarted the Remote Gateway Service and I could connect without issue.

I hope you found this discussion useful. Balancing operational and security requirements does not have to be hard. In this particular case, this solution is better/faster than using a VPN. I leave you with some thoughts on security [4].

See you soon! Fell free to comment if you have any remarks.

Further Reading

[1] Remote Desktop Gateway on the AWS Cloud: Quick Start Reference Deployment

[2] Controlling Network Access to EC2 Instances Using a Bastion Server

[3] Understanding Authorization Policies for Remote Desktop Gateway

[4] Remote Desktop Gateway Security Considerations

--

--

Daniel Ilie
The Startup

Cloud solution architect at Wood PLC. Provided clarity, employed creativity and managed complexity of systems.