A security group rule that allows 0.0.0.0/0 on SSH, RDP or a database port is the most common way AWS workloads get exposed. Here is how to find every such rule across regions, see what uses it, and close it without breaking anything.
Most AWS exposure doesn't come from sophisticated attacks. It comes from one inbound rule that says "allow from anywhere" on a port that should never face the internet: SSH (22), RDP (3389), or a database port such as 3306, 5432, 1433 or 27017. Automated scanners find these within minutes of an address going live, and they try every leaked or weak password they have.
This guide shows how to list every security group rule open to the internet, how to see what the group is attached to before you change it, and how to replace the open rule with something safer.
1. List the groups with open rules
Console: EC2 › Security Groups, then search the Inbound rules for 0.0.0.0/0 and ::/0. The console makes this slow across many groups and regions, so the CLI is the better tool here.
CLI (repeat in each region you use):
# groups with any inbound rule open to all IPv4 addresses
aws ec2 describe-security-groups --filters Name=ip-permission.cidr,Values=0.0.0.0/0 \
--query 'SecurityGroups[].[GroupId,GroupName,VpcId]' --output table
# the same for IPv6
aws ec2 describe-security-groups --filters Name=ip-permission.ipv6-cidr,Values=::/0 \
--query 'SecurityGroups[].[GroupId,GroupName,VpcId]' --output table
Then look at the rules of each group the commands return:
aws ec2 describe-security-group-rules --filters Name=group-id,Values=sg-0123456789abcdef0 \
--query 'SecurityGroupRules[?!IsEgress].[SecurityGroupRuleId,IpProtocol,FromPort,ToPort,CidrIpv4,CidrIpv6]' --output table
Not every open rule is a problem. Ports 80 and 443 on a public load balancer are meant to be open. Focus on these, in this order:
| Port | What it is | Why it matters |
|---|---|---|
| 22 | SSH | brute-forced constantly; one weak key or password is enough |
| 3389 | RDP | the classic ransomware entry point |
| 3306, 5432, 1433, 1521, 27017, 6379, 9200 | MySQL, PostgreSQL, SQL Server, Oracle, MongoDB, Redis, Elasticsearch | databases should never be reachable from the internet |
| a range such as 0-65535, or protocol -1 (all traffic) | everything | a rule that allows every port is almost always a mistake left over from testing |
2. See what the group protects before you change it
A rule only matters if the group is attached to something with a public address. Find what uses each group:
aws ec2 describe-network-interfaces --filters Name=group-id,Values=sg-0123456789abcdef0 \
--query 'NetworkInterfaces[].[NetworkInterfaceId,InterfaceType,Description,Association.PublicIp]' --output table
- A public IP in the last column means the open port is reachable from the internet right now. Fix these first.
- No public IP, such as an instance in a private subnet or an internal load balancer, means the rule is not exploitable today. It is still one subnet change away from being exposed, so tighten it too.
- No network interfaces at all means the group is unused. Delete it; unused groups are where open rules hide.
3. Replace the open rule
The fix is not "delete the rule". It is "give the people and systems that need the port a narrower way in". Pick the narrowest option that works:
- Administrators (SSH and RDP): use AWS Systems Manager Session Manager. It opens a shell or an RDP session through the SSM agent, with no inbound port at all, and logs every session. Once it works, remove the 22 and 3389 rules entirely.
- A known office or VPN: replace
0.0.0.0/0with that network's CIDR, or with a managed prefix list that holds your office ranges, so the list is maintained in one place. - Other AWS resources (application servers reaching a database): use the application servers' security group as the source instead of an IP range. The rule then follows the servers wherever they run.
Change the rule rather than deleting and re-creating it, so there is no gap:
# add the narrow rule first
aws ec2 authorize-security-group-ingress --group-id sg-0123456789abcdef0 \
--protocol tcp --port 5432 --source-group sg-0aaaabbbbccccdddd
# then remove the open one
aws ec2 revoke-security-group-ingress --group-id sg-0123456789abcdef0 \
--protocol tcp --port 5432 --cidr 0.0.0.0/0
If you are unsure whether something legitimate uses the open port, turn on VPC Flow Logs for the subnet for a few days before you close it. They show which source addresses actually connect.
4. Keep it from coming back
Open rules come back through the console during an incident ("just open it for a minute"), through copy-pasted infrastructure code, and through default groups created by wizards. Three habits stop that:
- Detect: AWS Config has managed rules for this (
restricted-sshfor port 22,restricted-common-portsfor a list you choose), and AWS Security Hub reports open administrative ports in its foundational security checks. - Prevent: in AWS Organizations, Firewall Manager can enforce security-group policies across accounts, and code review should flag
0.0.0.0/0on anything but 80 and 443. - Review: run the commands above on a schedule. An open rule found in a week is a finding; one found in a year is often an incident.
Cloud Health Check checks every security group in every region of each connected AWS account, and every network security group in Azure, for rules open to the internet on administrative and database ports, and shows which resources are actually exposed. You can see a sample report on demo data, no cloud access needed.
Questions about your own account? Email contact@parlak.us or try Cloud Health Check on sample data.