EC2 Security Group Allows Ingress from Internet to Any Port
Overview
This check identifies EC2 security groups that allow inbound traffic from the entire internet (0.0.0.0/0 or ::/0) to all ports. Security groups act as virtual firewalls for your EC2 instances, and overly permissive rules expose your resources to anyone on the internet.
Risk
When a security group allows unrestricted inbound access from the internet to all ports:
- Attackers can scan all services: Every running service on your instances becomes visible and reachable
- Brute force attacks become easy: SSH, RDP, databases, and admin panels are all exposed
- Data can be stolen: Unprotected databases or applications may leak sensitive information
- Lateral movement is enabled: Once compromised, attackers can pivot to other resources in your VPC
- Compliance violations: Most security frameworks (PCI DSS, HIPAA, SOC 2) prohibit unrestricted internet access
This is a High severity finding because it represents one of the most dangerous misconfigurations in AWS.
Remediation Steps
Prerequisites
- AWS Console access with permissions to modify EC2 security groups
- Knowledge of which ports your application actually needs to be accessible from the internet (if any)
Before you start: Understanding the impact
Removing security group rules can disrupt running applications. Before making changes:
- Identify what's using the security group: Check which EC2 instances, load balancers, or other resources have this security group attached
- Document required access: Determine the minimum ports needed (e.g., 443 for HTTPS, 22 for SSH from specific IPs)
- Plan for maintenance access: Consider using AWS Systems Manager Session Manager for SSH-free access, or restrict SSH to your office IP ranges
- Test in non-production first: If possible, make changes to development/staging environments before production
AWS Console Method
- Sign in to the AWS Console
- Navigate to EC2 (search for it in the search bar)
- In the left sidebar, click Security Groups (under "Network & Security")
- Find and select the security group flagged by Prowler
- Click the Inbound rules tab at the bottom of the page
- Look for rules with:
- Source:
0.0.0.0/0or::/0 - Port range:
All(or0-65535)
- Source:
- Click Edit inbound rules
- For each overly permissive rule, either:
- Delete it by clicking the X button on the right, OR
- Restrict it by changing the source to specific IP addresses or security groups
- Click Save rules
Recommended replacement rules (instead of "all ports from anywhere"):
| Purpose | Port | Source |
|---|---|---|
| HTTPS web traffic | 443 | 0.0.0.0/0 (if public-facing) |
| HTTP (redirect to HTTPS) | 80 | 0.0.0.0/0 (if needed) |
| SSH access | 22 | Your office IP or VPN CIDR |
| RDP access | 3389 | Your office IP or VPN CIDR |
| Application load balancer | App port | Security group of the ALB |
AWS CLI (optional)
Find Security Groups with Unrestricted Access
Find security groups that allow all traffic from the internet:
aws ec2 describe-security-groups \
--region us-east-1 \
--filters Name=ip-permission.cidr,Values='0.0.0.0/0' \
--query "SecurityGroups[?IpPermissions[?IpProtocol=='-1']].[GroupId,GroupName]" \
--output table
This finds groups where the protocol is -1 (all protocols/ports) with source 0.0.0.0/0.
Revoke the Overly Permissive Rule
To remove a rule that allows all traffic from anywhere:
aws ec2 revoke-security-group-ingress \
--group-id <SECURITY_GROUP_ID> \
--protocol all \
--port all \
--cidr 0.0.0.0/0 \
--region us-east-1
For IPv6 (::0/0):
aws ec2 revoke-security-group-ingress \
--group-id <SECURITY_GROUP_ID> \
--ip-permissions IpProtocol=-1,Ipv6Ranges='[{CidrIpv6=::/0}]' \
--region us-east-1
Add Specific Replacement Rules
After removing the permissive rule, add specific rules for what you need:
Allow HTTPS from anywhere (for public web servers):
aws ec2 revoke-security-group-ingress \
--group-id <SECURITY_GROUP_ID> \
--protocol tcp \
--port 443 \
--cidr 0.0.0.0/0 \
--region us-east-1
Allow SSH from a specific IP range:
aws ec2 authorize-security-group-ingress \
--group-id <SECURITY_GROUP_ID> \
--protocol tcp \
--port 22 \
--cidr 203.0.113.0/24 \
--region us-east-1
Replace:
<SECURITY_GROUP_ID>with your security group ID (e.g.,sg-0123456789abcdef0)203.0.113.0/24with your office or VPN IP range
CloudFormation (optional)
Secure Security Group Template
This template creates a security group with least-privilege rules instead of open access:
AWSTemplateFormatVersion: '2010-09-09'
Description: Secure EC2 security group with restricted ingress rules
Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
Description: VPC where the security group will be created
AllowedSshCidr:
Type: String
Description: CIDR block allowed for SSH access (e.g., your office IP)
Default: 10.0.0.0/8
EnablePublicHttps:
Type: String
Description: Allow HTTPS from the internet
AllowedValues:
- 'true'
- 'false'
Default: 'false'
Conditions:
AllowPublicHttps: !Equals [!Ref EnablePublicHttps, 'true']
Resources:
SecureSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: secure-web-server-sg
GroupDescription: Security group with restricted access - no open ingress
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: !Ref AllowedSshCidr
Description: SSH access from trusted network only
- !If
- AllowPublicHttps
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: HTTPS from internet
- !Ref AWS::NoValue
Tags:
- Key: Name
Value: secure-web-server-sg
- Key: Environment
Value: production
Outputs:
SecurityGroupId:
Description: ID of the secure security group
Value: !Ref SecureSecurityGroup
Export:
Name: !Sub ${AWS::StackName}-SecurityGroupId
Deploy the stack:
aws cloudformation create-stack \
--stack-name secure-security-group \
--template-body file://secure-sg.yaml \
--parameters ParameterKey=VpcId,ParameterValue=vpc-0123456789abcdef0 \
ParameterKey=AllowedSshCidr,ParameterValue=203.0.113.0/24 \
ParameterKey=EnablePublicHttps,ParameterValue=true \
--region us-east-1
Fixing an Existing Insecure Security Group
If you have an existing CloudFormation-managed security group with open access, update it:
Before (insecure):
SecurityGroupIngress:
- IpProtocol: -1
CidrIp: 0.0.0.0/0
After (secure):
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: HTTPS only
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 10.0.0.0/8
Description: SSH from internal network
Terraform (optional)
Secure Security Group Configuration
provider "aws" {
region = "us-east-1"
}
variable "vpc_id" {
description = "VPC ID where the security group will be created"
type = string
}
variable "allowed_ssh_cidr" {
description = "CIDR block allowed for SSH access"
type = string
default = "10.0.0.0/8"
}
variable "enable_public_https" {
description = "Allow HTTPS from the internet"
type = bool
default = false
}
# Secure security group with least-privilege rules
resource "aws_security_group" "secure_web_server" {
name = "secure-web-server-sg"
description = "Security group with restricted access - no open ingress"
vpc_id = var.vpc_id
# SSH from trusted network only
ingress {
description = "SSH access from trusted network"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.allowed_ssh_cidr]
}
# HTTPS from internet (conditional)
dynamic "ingress" {
for_each = var.enable_public_https ? [1] : []
content {
description = "HTTPS from internet"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
# Allow all outbound traffic
egress {
description = "Allow all outbound traffic"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "secure-web-server-sg"
Environment = "production"
ManagedBy = "terraform"
}
}
output "security_group_id" {
description = "ID of the secure security group"
value = aws_security_group.secure_web_server.id
}
Fixing an Existing Insecure Security Group
If you have Terraform code with open access, replace it:
Before (insecure):
ingress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
After (secure):
ingress {
description = "HTTPS only"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "SSH from internal network"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["10.0.0.0/8"]
}
Apply the changes:
terraform init
terraform plan
terraform apply
Verification
After updating the security group rules:
- Go to EC2 > Security Groups in the AWS Console
- Select the security group you modified
- Review the Inbound rules tab
- Confirm there are no rules with:
- Source
0.0.0.0/0or::/0AND - Port range
Allor protocolAll traffic
- Source
CLI verification commands
Check if any security groups still have unrestricted access:
aws ec2 describe-security-groups \
--region us-east-1 \
--filters Name=ip-permission.cidr,Values='0.0.0.0/0' \
--query "SecurityGroups[?IpPermissions[?IpProtocol=='-1']].[GroupId,GroupName]" \
--output table
Expected output when remediated (no results):
-----------------------
|DescribeSecurityGroups|
+-----------------------+
Verify a specific security group's rules:
aws ec2 describe-security-groups \
--group-ids <SECURITY_GROUP_ID> \
--region us-east-1 \
--query "SecurityGroups[0].IpPermissions"
Re-run Prowler to confirm the check passes:
prowler aws --check ec2_securitygroup_allow_ingress_from_internet_to_any_port
Additional Resources
- Security groups for your VPC - Amazon VPC User Guide
- Security group rules - Amazon EC2 User Guide
- AWS Well-Architected Framework - Security Pillar
- AWS Systems Manager Session Manager - SSH-free access to EC2 instances
Notes
-
Don't just delete rules: Before removing permissive rules, understand what legitimate traffic needs access. Removing rules without replacement can break applications.
-
Use security groups for internal traffic: For communication between EC2 instances, reference security groups as sources instead of IP ranges. This way, rules stay valid even when instance IPs change.
-
Consider Session Manager for SSH: Instead of opening port 22 to the internet, use AWS Systems Manager Session Manager. It provides shell access without any inbound ports open.
-
Load balancers help: Place EC2 instances behind Application Load Balancers (ALB). Only the ALB needs public access; instances can remain in private subnets with no direct internet exposure.
-
VPC Flow Logs can help: Enable VPC Flow Logs to understand what traffic is actually reaching your instances before making changes.
-
Default security groups: The default security group in each VPC allows all inbound traffic from itself. While this check may flag it, be cautious about modifying the default security group if resources depend on it.
-
IPv6 rules: Remember to check for both IPv4 (
0.0.0.0/0) and IPv6 (::/0) overly permissive rules.