Skip to main content

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:

  1. Identify what's using the security group: Check which EC2 instances, load balancers, or other resources have this security group attached
  2. Document required access: Determine the minimum ports needed (e.g., 443 for HTTPS, 22 for SSH from specific IPs)
  3. Plan for maintenance access: Consider using AWS Systems Manager Session Manager for SSH-free access, or restrict SSH to your office IP ranges
  4. Test in non-production first: If possible, make changes to development/staging environments before production

AWS Console Method

  1. Sign in to the AWS Console
  2. Navigate to EC2 (search for it in the search bar)
  3. In the left sidebar, click Security Groups (under "Network & Security")
  4. Find and select the security group flagged by Prowler
  5. Click the Inbound rules tab at the bottom of the page
  6. Look for rules with:
    • Source: 0.0.0.0/0 or ::/0
    • Port range: All (or 0-65535)
  7. Click Edit inbound rules
  8. 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
  9. Click Save rules

Recommended replacement rules (instead of "all ports from anywhere"):

PurposePortSource
HTTPS web traffic4430.0.0.0/0 (if public-facing)
HTTP (redirect to HTTPS)800.0.0.0/0 (if needed)
SSH access22Your office IP or VPN CIDR
RDP access3389Your office IP or VPN CIDR
Application load balancerApp portSecurity 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/24 with 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:

  1. Go to EC2 > Security Groups in the AWS Console
  2. Select the security group you modified
  3. Review the Inbound rules tab
  4. Confirm there are no rules with:
    • Source 0.0.0.0/0 or ::/0 AND
    • Port range All or protocol All traffic
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

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.