Network ACL Allows Ingress from 0.0.0.0/0 to RDP Port 3389
Overview
This check identifies Network Access Control Lists (NACLs) that have inbound rules allowing Remote Desktop Protocol (RDP) traffic on TCP port 3389 from 0.0.0.0/0 (the entire internet). NACLs act as stateless firewalls at the subnet boundary, controlling what traffic can enter or leave your subnets.
RDP is used to remotely access Windows servers. Exposing it to the entire internet is a common attack vector that puts your Windows instances at serious risk.
Risk
Allowing unrestricted RDP access from the internet creates severe security risks:
- Brute force attacks: Attackers constantly scan the internet for open RDP ports and attempt to guess passwords
- Password spraying: Automated tools try common passwords across many accounts simultaneously
- RDP vulnerability exploitation: Known vulnerabilities like BlueKeep (CVE-2019-0708) can allow attackers to take complete control without credentials
- Ransomware deployment: RDP is the most common entry point for ransomware attacks
- Data exfiltration: Once inside, attackers can steal sensitive data from your Windows servers
- Lateral movement: Compromised servers can be used to attack other resources in your network
This is a medium severity finding that should be addressed promptly.
Remediation Steps
Prerequisites
You need:
- AWS Console access with permissions to modify VPC Network ACLs
- Knowledge of which IP addresses legitimately need RDP access to your Windows servers
Required IAM permissions
Your IAM user or role needs these permissions:
ec2:DescribeNetworkAclsec2:ReplaceNetworkAclEntryec2:DeleteNetworkAclEntryec2:CreateNetworkAclEntry
AWS Console Method
-
Open the VPC Console
- Go to VPC Console in us-east-1
-
Navigate to Network ACLs
- In the left sidebar, click Network ACLs
-
Find the affected NACL
- Locate the Network ACL flagged in the Prowler finding
- Click on it to select it
-
Review the Inbound Rules
- Click the Inbound rules tab
- Look for rules with these characteristics:
- Source:
0.0.0.0/0 - Port range:
3389 - Protocol:
TCP (6) - Action:
Allow
- Source:
-
Delete or restrict the RDP rule
- Click Edit inbound rules
- Find the rule allowing port 3389 from
0.0.0.0/0 - Either:
- Delete: Click Remove next to the rule to remove RDP access entirely
- Restrict: Change the Source from
0.0.0.0/0to your specific trusted IP range (e.g.,10.0.0.0/8or your corporate VPN IP)
- Click Save changes
-
Consider better alternatives to direct RDP
- Use AWS Systems Manager Session Manager for secure remote access without opening ports
- Deploy a bastion host in a controlled subnet
- Use AWS Client VPN or Site-to-Site VPN to access private resources securely
Warning: If you have active RDP sessions, restricting access will disconnect users outside the allowed IP range. Coordinate with your team before making changes.
AWS CLI (optional)
Step 1: Identify the problematic rules
List all Network ACLs and find rules allowing RDP from anywhere:
aws ec2 describe-network-acls \
--region us-east-1 \
--query 'NetworkAcls[*].{ID:NetworkAclId,VpcId:VpcId,Entries:Entries}' \
--output json
Look for inbound entries where:
CidrBlockis0.0.0.0/0Protocolis6(TCP)PortRange.Fromis3389andPortRange.Tois3389RuleActionisallowEgressisfalse(indicating inbound)
Step 2: Option A - Delete the RDP rule entirely
If RDP access through this NACL is not needed:
aws ec2 delete-network-acl-entry \
--network-acl-id <nacl-id> \
--ingress \
--rule-number <rule-number> \
--region us-east-1
Replace <nacl-id> with your Network ACL ID (e.g., acl-0123456789abcdef0) and <rule-number> with the rule number from step 1.
Step 2: Option B - Restrict RDP to trusted IPs only
Replace the open rule with one restricted to your trusted network:
aws ec2 replace-network-acl-entry \
--network-acl-id <nacl-id> \
--ingress \
--rule-number <rule-number> \
--protocol 6 \
--port-range From=3389,To=3389 \
--cidr-block 10.0.0.0/8 \
--rule-action allow \
--region us-east-1
Replace 10.0.0.0/8 with your actual trusted CIDR block.
CloudFormation (optional)
This template creates a Network ACL with secure rules that restrict RDP to a trusted network:
AWSTemplateFormatVersion: '2010-09-09'
Description: Secure Network ACL with restricted RDP access
Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
Description: VPC ID where the Network ACL will be created
SubnetId:
Type: AWS::EC2::Subnet::Id
Description: Subnet ID to associate with this Network ACL
TrustedCidrBlock:
Type: String
Description: CIDR block for trusted RDP access (e.g., corporate VPN)
Default: 10.0.0.0/8
Resources:
SecureNetworkAcl:
Type: AWS::EC2::NetworkAcl
Properties:
VpcId: !Ref VpcId
Tags:
- Key: Name
Value: secure-nacl-no-public-rdp
# Allow HTTPS inbound from anywhere (for web servers)
InboundHttpsRule:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref SecureNetworkAcl
RuleNumber: 100
Protocol: 6
RuleAction: allow
CidrBlock: 0.0.0.0/0
PortRange:
From: 443
To: 443
# Allow RDP from trusted network ONLY
InboundRdpRule:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref SecureNetworkAcl
RuleNumber: 120
Protocol: 6
RuleAction: allow
CidrBlock: !Ref TrustedCidrBlock
PortRange:
From: 3389
To: 3389
# Allow ephemeral ports for return traffic
InboundEphemeralRule:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref SecureNetworkAcl
RuleNumber: 140
Protocol: 6
RuleAction: allow
CidrBlock: 0.0.0.0/0
PortRange:
From: 1024
To: 65535
# Deny all other inbound traffic (explicit deny)
InboundDenyAllRule:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref SecureNetworkAcl
RuleNumber: 200
Protocol: -1
RuleAction: deny
CidrBlock: 0.0.0.0/0
# Allow all outbound traffic
OutboundAllRule:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref SecureNetworkAcl
RuleNumber: 100
Protocol: -1
Egress: true
RuleAction: allow
CidrBlock: 0.0.0.0/0
# Associate NACL with subnet
SubnetNetworkAclAssociation:
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: !Ref SubnetId
NetworkAclId: !Ref SecureNetworkAcl
Outputs:
NetworkAclId:
Description: ID of the secure Network ACL
Value: !Ref SecureNetworkAcl
Deploy with:
aws cloudformation deploy \
--template-file secure-nacl-rdp.yaml \
--stack-name secure-network-acl-rdp \
--parameter-overrides \
VpcId=vpc-12345678 \
SubnetId=subnet-12345678 \
TrustedCidrBlock=10.0.0.0/8 \
--region us-east-1
Terraform (optional)
variable "vpc_id" {
description = "VPC ID where the Network ACL will be created"
type = string
}
variable "subnet_ids" {
description = "List of subnet IDs to associate with this Network ACL"
type = list(string)
}
variable "trusted_cidr_block" {
description = "CIDR block for trusted RDP access (e.g., corporate VPN)"
type = string
default = "10.0.0.0/8"
}
resource "aws_network_acl" "secure" {
vpc_id = var.vpc_id
subnet_ids = var.subnet_ids
tags = {
Name = "secure-nacl-no-public-rdp"
}
}
# Allow HTTPS inbound from anywhere
resource "aws_network_acl_rule" "inbound_https" {
network_acl_id = aws_network_acl.secure.id
rule_number = 100
egress = false
protocol = "tcp"
rule_action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 443
to_port = 443
}
# Allow RDP from trusted network ONLY - NOT from 0.0.0.0/0
resource "aws_network_acl_rule" "inbound_rdp" {
network_acl_id = aws_network_acl.secure.id
rule_number = 120
egress = false
protocol = "tcp"
rule_action = "allow"
cidr_block = var.trusted_cidr_block
from_port = 3389
to_port = 3389
}
# Allow ephemeral ports for return traffic
resource "aws_network_acl_rule" "inbound_ephemeral" {
network_acl_id = aws_network_acl.secure.id
rule_number = 140
egress = false
protocol = "tcp"
rule_action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 1024
to_port = 65535
}
# Explicit deny all other inbound traffic
resource "aws_network_acl_rule" "inbound_deny_all" {
network_acl_id = aws_network_acl.secure.id
rule_number = 200
egress = false
protocol = "-1"
rule_action = "deny"
cidr_block = "0.0.0.0/0"
}
# Allow all outbound traffic
resource "aws_network_acl_rule" "outbound_all" {
network_acl_id = aws_network_acl.secure.id
rule_number = 100
egress = true
protocol = "-1"
rule_action = "allow"
cidr_block = "0.0.0.0/0"
}
output "network_acl_id" {
description = "ID of the secure Network ACL"
value = aws_network_acl.secure.id
}
Deploy with:
terraform init
terraform plan -var="vpc_id=vpc-12345678" -var='subnet_ids=["subnet-12345678"]' -var="trusted_cidr_block=10.0.0.0/8"
terraform apply -var="vpc_id=vpc-12345678" -var='subnet_ids=["subnet-12345678"]' -var="trusted_cidr_block=10.0.0.0/8"
Verification
After remediation, verify the RDP rule has been corrected:
-
In the AWS Console:
- Go to VPC > Network ACLs
- Select the remediated NACL
- Click the Inbound rules tab
- Confirm there are no rules allowing port 3389 from
0.0.0.0/0
-
Test access:
- Verify RDP still works from your trusted network (if you restricted rather than removed)
- Confirm RDP is blocked from outside your trusted IP range
CLI verification commands
Check the NACL rules for RDP exposure:
aws ec2 describe-network-acls \
--network-acl-ids <nacl-id> \
--region us-east-1 \
--query 'NetworkAcls[0].Entries[?Egress==`false` && PortRange.From==`3389`]'
The output should either be empty (RDP rule deleted) or show a rule with a restricted CIDR block (not 0.0.0.0/0).
Re-run the Prowler check to confirm:
prowler aws -c ec2_networkacl_allow_ingress_tcp_port_3389 --region us-east-1
Additional Resources
- AWS Documentation: Network ACLs
- AWS Documentation: AWS Systems Manager Session Manager
- AWS Security Blog: Replacing a Bastion Host with Amazon EC2 Systems Manager
- CISA Alert: BlueKeep RDP Vulnerability
- AWS Well-Architected: Network Protection
Notes
- Use Session Manager instead: AWS Systems Manager Session Manager provides secure remote access to Windows instances without opening any inbound ports. This is the recommended approach for most use cases.
- Defense in depth: NACLs are just one layer. Also configure security groups to restrict RDP access, and consider Windows Firewall rules on the instances themselves.
- Stateless nature: NACLs are stateless. If you allow RDP inbound, you also need to allow ephemeral ports (1024-65535) for return traffic.
- Rule evaluation order: NACL rules are evaluated in order by rule number (lowest first). The first matching rule is applied.
- Service disruption: Modifying NACL rules takes effect immediately. Active RDP sessions from blocked IPs will be disconnected.
- IPv6 consideration: If your VPC uses IPv6, also check for rules allowing
::/0on port 3389 and apply the same restrictions. - Logging: Consider enabling VPC Flow Logs to monitor connection attempts to RDP ports for security analysis.