Ensure No Security Groups Allow Ingress from Internet to All Ports
Overview
This check identifies EC2 security groups that have inbound rules allowing traffic from anywhere on the internet (0.0.0.0/0 or ::/0) to all ports. This is one of the most dangerous misconfigurations in AWS because it completely exposes your resources to the public internet.
Severity: Critical
Risk
Opening all ports to the internet creates a massive attack surface. Attackers can:
- Scan every port on your instances looking for vulnerabilities
- Exploit any running service, even ones you forgot were installed
- Gain unauthorized access and potentially execute malicious code
- Move laterally within your VPC once they gain a foothold
- Exfiltrate sensitive data
This misconfiguration puts confidentiality, integrity, and availability all at risk.
Remediation Steps
Prerequisites
You need permission to modify EC2 security groups in your AWS account. Specifically, you need the ec2:RevokeSecurityGroupIngress and ec2:AuthorizeSecurityGroupIngress permissions.
AWS Console Method
- Open the EC2 Console and select Security Groups from the left navigation
- Find the flagged security group (you can search by ID or name)
- Select the security group and click the Inbound rules tab
- Click Edit inbound rules
- Look for any rule where:
- Type is "All traffic" (or port range shows "All")
- Source is
0.0.0.0/0or::/0
- Delete these dangerous rules by clicking the X next to each one
- Add specific rules for only the traffic you actually need:
- Choose a specific port (e.g., 443 for HTTPS)
- Restrict the source to specific IP ranges, security groups, or prefix lists
- Click Save rules
Important: Before deleting rules, make sure you understand what traffic your application needs. Deleting rules without adding appropriate replacements may break your application.
AWS CLI Method
Step 1: Find security groups with overly permissive rules
aws ec2 describe-security-groups \
--region us-east-1 \
--query "SecurityGroups[?IpPermissions[?IpProtocol=='-1' && (IpRanges[?CidrIp=='0.0.0.0/0'] || Ipv6Ranges[?CidrIpv6=='::/0'])]].[GroupId,GroupName]" \
--output table
Step 2: Review the current rules for a specific security group
aws ec2 describe-security-groups \
--region us-east-1 \
--group-ids <your-security-group-id> \
--query "SecurityGroups[*].IpPermissions"
Step 3: Remove the dangerous "all traffic from internet" rule
For IPv4 (0.0.0.0/0):
aws ec2 revoke-security-group-ingress \
--region us-east-1 \
--group-id <your-security-group-id> \
--ip-permissions '[{"IpProtocol": "-1", "IpRanges": [{"CidrIp": "0.0.0.0/0"}]}]'
For IPv6 (::/0):
aws ec2 revoke-security-group-ingress \
--region us-east-1 \
--group-id <your-security-group-id> \
--ip-permissions '[{"IpProtocol": "-1", "Ipv6Ranges": [{"CidrIpv6": "::/0"}]}]'
Step 4: Add specific rules for required traffic
Example - Allow HTTPS (port 443) from a specific CIDR:
aws ec2 authorize-security-group-ingress \
--region us-east-1 \
--group-id <your-security-group-id> \
--protocol tcp \
--port 443 \
--cidr 10.0.0.0/8
Example - Allow SSH (port 22) from another security group:
aws ec2 authorize-security-group-ingress \
--region us-east-1 \
--group-id <your-security-group-id> \
--protocol tcp \
--port 22 \
--source-group <bastion-security-group-id>
CloudFormation Template
This template creates a secure security group pattern with restricted ingress rules.
AWSTemplateFormatVersion: '2010-09-09'
Description: Secure Security Group - No Internet Ingress to All Ports
Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
Description: VPC ID where the security group will be created
Resources:
SecureSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Secure security group with restricted ingress
VpcId: !Ref VpcId
SecurityGroupIngress:
# Allow HTTPS from specific CIDR (example: corporate network)
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 10.0.0.0/8
Description: HTTPS from internal network
# Allow SSH from bastion security group only
- IpProtocol: tcp
FromPort: 22
ToPort: 22
SourceSecurityGroupId: !Ref BastionSecurityGroup
Description: SSH from bastion hosts only
SecurityGroupEgress:
- IpProtocol: '-1'
CidrIp: 0.0.0.0/0
Description: Allow all outbound traffic
Tags:
- Key: Name
Value: secure-sg
BastionSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Bastion host security group
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 203.0.113.0/24
Description: SSH from trusted IP range only
Tags:
- Key: Name
Value: bastion-sg
Outputs:
SecurityGroupId:
Description: ID of the secure security group
Value: !Ref SecureSecurityGroup
BastionSecurityGroupId:
Description: ID of the bastion security group
Value: !Ref BastionSecurityGroup
Key security patterns in this template:
- No
0.0.0.0/0or::/0in any ingress rules - Specific ports defined (443, 22) instead of all traffic
- Security group references used for internal traffic (SSH from bastion)
- Descriptions on all rules for audit purposes
Terraform Configuration
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
variable "vpc_id" {
description = "VPC ID where the security group will be created"
type = string
}
variable "allowed_cidr_blocks" {
description = "List of CIDR blocks allowed for HTTPS access"
type = list(string)
default = ["10.0.0.0/8"]
}
variable "bastion_allowed_cidr" {
description = "CIDR block allowed for SSH to bastion"
type = string
default = "203.0.113.0/24"
}
# Bastion security group
resource "aws_security_group" "bastion" {
name = "bastion-sg"
description = "Bastion host security group"
vpc_id = var.vpc_id
ingress {
description = "SSH from trusted IP range only"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.bastion_allowed_cidr]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "bastion-sg"
}
}
# Application security group with restricted access
resource "aws_security_group" "application" {
name = "secure-application-sg"
description = "Secure security group with restricted ingress"
vpc_id = var.vpc_id
# HTTPS from internal network only
ingress {
description = "HTTPS from internal network"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = var.allowed_cidr_blocks
}
# SSH from bastion security group only
ingress {
description = "SSH from bastion hosts only"
from_port = 22
to_port = 22
protocol = "tcp"
security_groups = [aws_security_group.bastion.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "secure-application-sg"
}
}
output "security_group_id" {
description = "ID of the secure application security group"
value = aws_security_group.application.id
}
output "bastion_security_group_id" {
description = "ID of the bastion security group"
value = aws_security_group.bastion.id
}
Key security patterns:
- Uses variables to define allowed CIDRs (no hardcoded
0.0.0.0/0in ingress) - Specific ports only (443, 22)
- Security group references for internal traffic
- Descriptions on all rules
Verification
After making changes, verify the security group no longer has dangerous rules:
- In the AWS Console, open the security group and review the Inbound rules tab
- Confirm there are no rules with:
- Type: "All traffic"
- Source:
0.0.0.0/0or::/0
CLI Verification
Run Prowler to verify the fix:
prowler aws --checks ec2_securitygroup_allow_ingress_from_internet_to_all_ports
Or use the AWS CLI to check for remaining violations:
aws ec2 describe-security-groups \
--region us-east-1 \
--query "SecurityGroups[?IpPermissions[?IpProtocol=='-1' && (IpRanges[?CidrIp=='0.0.0.0/0'] || Ipv6Ranges[?CidrIpv6=='::/0'])]].[GroupId,GroupName]" \
--output table
The output should be empty if all violations are resolved.
Additional Resources
- AWS Security Group Documentation
- AWS Security Group Rules Reference
- AWS Well-Architected Security Pillar
- Zero Trust Architecture on AWS
Notes
- Default security groups: The default security group in each VPC cannot be deleted. If it has dangerous rules, you must modify it to remove them.
- Attached resources: Before modifying rules, identify what resources (EC2 instances, RDS databases, Lambda functions, etc.) use this security group to avoid service disruption.
- Rule evaluation: Security group rules are evaluated together. Removing overly permissive rules and adding specific ones is the correct approach.
- Alternatives to public access: Consider using AWS Systems Manager Session Manager, VPN connections, or bastion hosts instead of opening SSH/RDP to the internet.
- Compliance frameworks: This check is relevant to CIS AWS Benchmarks, SOC2, ISO 27001, and many other compliance frameworks.