Securely Accessing EC2 Windows Instances via SSH Port Forwarding

Securely Accessing EC2 Windows Instances via SSH Port Forwarding

Reaching an EC2 Windows instance in a private subnet through an SSH bastion host, keeping RDP off the public internet entirely.

Takahiro Iwasa
3 min read

Placing an EC2 Windows instance in a private subnet and accessing it through a bastion host in a public subnet is a common pattern for securing remote desktop access without exposing the instance directly to the internet.

Important

This method secures only the connection between the client and the bastion host. No encryption is applied between the bastion host and the EC2 Windows instance.

The overall architecture is illustrated below. The client opens an SSH session to the bastion host in the public subnet, and that session carries the RDP traffic to the Windows instance in the private subnet, which has no route to the internet gateway. Because the SSH encryption terminates at the bastion host, the forwarded segment inside the VPC travels as ordinary RDP traffic.

Connection path from the client through the SSH bastion host to an EC2 Windows instance in a private subnet

Setting Up the AWS Environment

VPC

Create a private subnet within the target VPC. This step can be skipped if a suitable subnet already exists.

Private Subnet

Create a route table and associate it with the private subnet.

Route Table Configuration

🔥 Caution

Ensure the internet gateway is removed from this route table; its presence would render the subnet effectively public.

If the EC2 Windows instance requires internet access, create a NAT gateway in a public subnet and attach it to the route table.

🔥 Caution

Running a NAT gateway incurs additional costs.

NAT Gateway

SSH Bastion Host

  1. Launch an EC2 instance in the public subnet to serve as the bastion host.
  2. Configure the security group to allow inbound traffic on ports 22 (SSH) and 3389 (RDP).
💡 Tip

Assigning an Elastic IP (EIP) makes access to the bastion host easy.

EC2 Windows Instance

  1. Launch an EC2 Windows instance in the private subnet.
  2. Retrieve the remote desktop credentials using the Get Windows Password option in the EC2 dashboard.
  3. Restrict security group access to allow inbound traffic on ports 22 and 3389 only from the bastion host.

EC2 Windows Security Group

Testing the Connection

To establish a secure connection to the EC2 Windows instance, execute the following command from a local terminal:

Terminal window
ssh -i <YOUR_PRIVATE_KEY> -L 13389:<YOUR_EC2_WINDOWS_IP>:3389 ec2-user@<YOUR_SSH_BASTION_IP>

This command forwards traffic from local port 13389 to the EC2 Windows instance in the private subnet via the bastion host. A remote desktop session can then be initiated by connecting to localhost:13389.

Remote Desktop Connection

Conclusion

Placing the EC2 Windows instance in a private subnet without a route to an internet gateway, then accessing it through an SSH bastion host in a public subnet, keeps RDP off the public internet. The security group on the private instance is essential: restricting traffic on ports 22 and 3389 to the bastion host, rather than allowing a broader CIDR range, enforces this isolation.

The ssh -L 13389:<EC2_WINDOWS_IP>:3389 option tunnels the RDP session through the bastion host, allowing localhost:13389 on the client machine to reach an instance that cannot be accessed directly from outside the VPC.

Because the SSH tunnel covers only the connection between the client and the bastion host, the bastion must be carefully secured. Restrict its security group to known administrative source addresses and, if necessary, assign an EIP to give the bastion a stable address.

About the author

Takahiro Iwasa

Takahiro Iwasa

Software Developer

This blog shares technical notes from hands-on projects—architecture, implementation, and AWS service integrations.