Description
Ensure that no VPC network ACL allows inbound traffic from the Internet (0.0.0.0/0 or ::/0) to Microsoft Remote Desktop Protocol (RDP, TCP port 3389). Network ACLs control traffic at the subnet boundary, and their inbound rules are evaluated in order of rule number, starting with the lowest.
Rationale
Network ACLs are a subnet-level layer of defense in depth in front of security groups. If a network ACL allows RDP from the whole Internet, a single misconfigured security group or route can expose Windows instances to password spraying, brute-force attacks and RDP exploits, leading to data theft and ransomware. Denying RDP from 0.0.0.0/0 and ::/0 at the subnet boundary, and using a VPN, bastion host or AWS Systems Manager Session Manager, keeps this layer effective.
Impact
Blocks RDP from the Internet at the subnet level, in addition to security groups
Reduces the impact of a misconfigured security group
Administrators currently connecting to RDP over the Internet will lose access and must use Session Manager, a VPN or a bastion host in an allowed range
Because network ACLs are stateless, a rule that is too broad can block legitimate traffic, so changes should be tested on a non-critical subnet first
Default Value
The default network ACL of a VPC allows all inbound traffic from 0.0.0.0/0 (rule 100), and also from ::/0 if the VPC has an IPv6 CIDR block, so it allows RDP from the Internet unless a deny rule is added. A newly created custom network ACL denies all inbound traffic until rules are added.
Pre-Requisites
IAM permissions: ec2:DescribeNetworkAcls, ec2:CreateNetworkAclEntry, ec2:ReplaceNetworkAclEntry and ec2:DeleteNetworkAclEntry
The subnets associated with the network ACL and any trusted ranges that legitimately need RDP access
A free rule number lower than the rule that currently allows the traffic
Remediation
Test Plan
Console:
Sign in to the AWS Management Console at https://console.aws.amazon.com.
Open the Amazon VPC console and select Network ACLs.
Select a network ACL and open the Inbound rules tab.
Read the rules in order of rule number. For each source 0.0.0.0/0 and ::/0, find the first rule that matches port 3389, meaning:
type All traffic, or
protocol TCP with a port range that includes 3389.
Repeat for each network ACL in each region in use.
If that first matching rule is Allow for either source, follow the implementation steps.
CLI:
List the network ACLs:
aws ec2 describe-network-acls --region <REGION> --query "NetworkAcls[].[NetworkAclId,VpcId,IsDefault]" --output table
List the inbound rules of a network ACL:
aws ec2 describe-network-acls --region <REGION> --network-acl-ids <NETWORK_ACL_ID> --query "NetworkAcls[].Entries[?Egress==\`false\`].[RuleNumber,Protocol,RuleAction,CidrBlock,Ipv6CidrBlock,PortRange.From,PortRange.To]" --output table
The network ACL fails if, for source 0.0.0.0/0 or ::/0, the lowest-numbered rule with protocol -1 (all traffic), or protocol 6 (TCP) with a port range that includes 3389, has the action allow.
Implementation Steps
Console:
Sign in to the AWS Management Console at https://console.aws.amazon.com.
Open the Amazon VPC console and select Network ACLs.
Select the network ACL found in the Test Plan and open the Inbound rules tab.
Choose Edit inbound rules.
If the matching allow rule is a rule only for port 3389, delete it.
If the matching allow rule is broader (for example All traffic), choose Add new rule and create a deny rule with a lower rule number:
Type: Custom TCP, Port range: 3389,
Source: 0.0.0.0/0,
Allow/Deny: Deny.
If the network ACL has an IPv6 allow rule, add the same deny rule with source ::/0.
If RDP is needed from trusted ranges, add allow rules for those ranges with rule numbers lower than the deny rules.
Choose Save changes.
Repeat for each affected network ACL in each region in use.
CLI:
The provided command deletes an existing rule; use it only when that rule number is a rule specifically for port 3389, because deleting a broad allow rule (such as rule 100 of the default network ACL) blocks all traffic it allowed.
aws ec2 delete-network-acl-entry --network-acl-id <NETWORK_ACL_ID> --ingress --rule-number <RULE_NUMBER>
In most cases, add deny rules for port 3389 with a rule number lower than the allow rule instead (one for IPv4 and one for IPv6):
aws
ec2 create-network-acl-entry --network-acl-id <NETWORK_ACL_ID>
--ingress --rule-number <RULE_NUMBER> --protocol 6 --port-range
From=3389,To=3389 --cidr-block 0.0.0.0/0 --rule-action deny
aws
ec2 create-network-acl-entry --network-acl-id <NETWORK_ACL_ID>
--ingress --rule-number <IPV6_RULE_NUMBER> --protocol 6
--port-range From=3389,To=3389 --ipv6-cidr-block ::/0 --rule-action
deny
Backout Plan
Before making changes, save the current network ACL rules:
aws ec2 describe-network-acls --network-acl-ids <NETWORK_ACL_ID> > <NETWORK_ACL_ID>-backup.json
To roll back:
Sign in to the AWS Management Console at https://console.aws.amazon.com.
Open the Amazon VPC console, select Network ACLs and select the network ACL.
On the Inbound rules tab, choose Edit inbound rules.
Remove the deny rules that were added, and re-add any removed rules using the saved backup (rule number, type, port range, source and action).
Choose Save changes.
CLI:
aws ec2 delete-network-acl-entry --network-acl-id <NETWORK_ACL_ID> --ingress --rule-number <RULE_NUMBER>
Note: rolling back allows RDP from the Internet at the subnet level again. Use it only as a temporary measure.
Reference