Security group has no 0.0.0.0/0 or ::/0 ingress to any port, or is attached only to allowed interface types or instance owners
EC2 security groups with internet-sourced ingress from 0.0.0.0/0 or ::/0 to any port, and their attachments, are evaluated. Groups linked to network interfaces or instance owners outside an approved list for public exposure are identified.
Risk
Open ingress to any port on non-approved interfaces enables external scanning, brute force, and exploitation of unintended services. This threatens confidentiality (unauthorized access), integrity (tampering), and availability (DoS), and facilitates lateral movement.
Run this check with Prowler
Run in Prowler Cloudprowler aws --checks ec2_securitygroup_allow_ingress_from_internet_to_any_portRecommendation
Apply least privilege: restrict ingress to required ports and trusted sources; avoid 0.0.0.0/0 and ::/0 except for managed public endpoints. Place workloads behind load balancers, API gateways, or WAFs; use private networking. Allow public rules only on approved interface types.
Remediation
Terraform
# Security group with no Internet-open ingress
resource "aws_security_group" "<example_resource_name>" {
name = "<example_resource_name>"
vpc_id = "<example_resource_id>"
# Critical: no ingress blocks -> prevents 0.0.0.0/0 or ::/0 inbound
}NativeIaC
# CloudFormation: security group without Internet-open ingress
Resources:
<example_resource_name>:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "SG without Internet ingress"
VpcId: "<example_resource_id>"
SecurityGroupIngress: [] # Critical: no 0.0.0.0/0 or ::/0 inbound; denies all inboundOther
Check Code
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_all_ports import (
ec2_securitygroup_allow_ingress_from_internet_to_all_ports,
)
from prowler.providers.aws.services.ec2.ec2_service import NetworkInterface
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
from prowler.providers.aws.services.vpc.vpc_client import vpc_client
class ec2_securitygroup_allow_ingress_from_internet_to_any_port(Check):
def execute(self):
findings = []
for security_group_arn, security_group in ec2_client.security_groups.items():
# Only execute the check if the check ec2_securitygroup_allow_ingress_from_internet_to_all_ports has not failed
if not ec2_client.is_failed_check(
ec2_securitygroup_allow_ingress_from_internet_to_all_ports.__name__,
security_group_arn,
):
# Check if ignoring flag is set and if the VPC and the SG is in use
if ec2_client.provider.scan_unused_services or (
security_group.vpc_id in vpc_client.vpcs
and vpc_client.vpcs[security_group.vpc_id].in_use
and len(security_group.network_interfaces) > 0
):
report = Check_Report_AWS(
metadata=self.metadata(), resource=security_group
)
report.resource_details = security_group.name
report.status = "PASS"
report.status_extended = f"Security group {security_group.name} ({security_group.id}) does not have any port open to the Internet."
for ingress_rule in security_group.ingress_rules:
if check_security_group(
ingress_rule, "-1", any_address=True, all_ports=True
):
self.check_enis(
report=report,
security_group_name=security_group.name,
security_group_id=security_group.id,
enis=security_group.network_interfaces,
)
if report.status == "FAIL":
break
findings.append(report)
return findings
def check_enis(
self,
report,
security_group_name: str,
security_group_id: str,
enis: list[NetworkInterface],
):
report.status_extended = f"Security group {security_group_name} ({security_group_id}) has at least one port open to the Internet but it is not attached to any network interface."
for eni in enis:
if eni.type in ec2_client.audit_config.get(
"ec2_allowed_interface_types", ["api_gateway_managed", "vpc_endpoint"]
):
report.status = "PASS"
report.status_extended = f"Security group {security_group_name} ({security_group_id}) has at least one port open to the Internet and it is attached to an allowed network interface type ({eni.type})."
continue
if eni.attachment.instance_owner_id in ec2_client.audit_config.get(
"ec2_allowed_instance_owners", ["amazon-elb"]
):
report.status = "PASS"
report.status_extended = f"Security group {security_group_name} ({security_group_id}) has at least one port open to the Internet and it is attached to an allowed network interface instance owner ({eni.attachment.instance_owner_id})."
continue
if eni.type not in ec2_client.audit_config.get(
"ec2_allowed_interface_types", ["api_gateway_managed", "vpc_endpoint"]
):
report.status = "FAIL"
report.status_extended = f"Security group {security_group_name} ({security_group_id}) has at least one port open to the Internet but its network interface type ({eni.type}) is not allowed."
elif eni.attachment.instance_owner_id not in ec2_client.audit_config.get(
"ec2_allowed_instance_owners", ["amazon-elb"]
):
report.status = "FAIL"
report.status_extended = f"Security group {security_group_name} ({security_group_id}) has at least one port open to the Internet but its network interface instance owner ({eni.attachment.instance_owner_id}) is not allowed."
else:
report.status = "FAIL"
report.status_extended = f"Security group {security_group_name} ({security_group_id}) has at least one port open to the Internet but neither its network interface type ({eni.type}) nor its network interface instance owner ({eni.attachment.instance_owner_id}) are allowed."
if report.status == "FAIL":
break