Back to Checks
stackit

IaaS security groups do not allow unrestricted database access

iaas_security_group_database_unrestricted
Service: iaasSeverity: high
OfficialBuilt-inVerified
Categories:internet-exposed
Resource Type:NotDefined

Security groups should not allow unrestricted access to database ports from the public internet (0.0.0.0/0 or ::/0). This includes MySQL (3306), PostgreSQL (5432), MongoDB (27017), Redis (6379), SQL Server (1433), and CouchDB (5984). Unrestricted database access can lead to data breaches and unauthorized access.

Risk

Allowing unrestricted database access from the internet exposes sensitive data to potential breaches, unauthorized access, data exfiltration, and malicious attacks. Databases often contain critical business data and should never be directly accessible from the public internet.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler stackit --checks iaas_security_group_database_unrestricted

Recommendation

Restrict database access to specific application servers or trusted IP ranges. Use private networks for database connectivity and implement additional security layers such as VPNs, private endpoints, or application-level authentication.

Remediation

Other

1In the StackIT Portal open Networking > Security Groups and select the affected security group. 2. Locate the ingress rules that allow database ports (3306, 5432, 27017, 6379, 1433, 5984) from 0.0.0.0/0 or ::/0. 3. Delete those rules or restrict their source to the specific application servers or trusted IP ranges. 4. Prefer private networking for database connectivity and do not expose database ports to the internet. 5. Re-run Prowler to confirm the finding is resolved.

Check Code

from prowler.lib.check.models import Check, CheckReportStackIT
from prowler.providers.stackit.services.iaas.iaas_client import iaas_client

# Database ports to check
DATABASE_PORTS = {
    3306: "MySQL",
    5432: "PostgreSQL",
    27017: "MongoDB",
    6379: "Redis",
    1433: "SQL Server",
    5984: "CouchDB",
}


class iaas_security_group_database_unrestricted(Check):
    """
    Check if IaaS security groups allow unrestricted database access.

    This check verifies that security groups do not allow database ports
    (MySQL, PostgreSQL, MongoDB, Redis, SQL Server, CouchDB) access
    from the public internet (0.0.0.0/0 or ::/0).
    """

    def execute(self):
        """
        Execute the check for all security groups in the StackIT project.

        Returns:
            list: A list of CheckReportStackIT findings
        """
        findings = []

        for security_group in iaas_client.security_groups:
            if not (iaas_client.scan_unused_services or security_group.in_use):
                continue
            exposed_databases = set()
            exposing_rule = None

            # Check each ingress rule
            for rule in security_group.rules:
                # Only check ingress TCP rules that are unrestricted
                if rule.is_ingress() and rule.is_tcp() and rule.is_unrestricted():
                    # Check if rule allows any database ports
                    for port, db_name in DATABASE_PORTS.items():
                        if rule.includes_port(port):
                            exposed_databases.add(f"{db_name} (port {port})")
                    # Track the first exposing rule for the message
                    if exposed_databases and not exposing_rule:
                        exposing_rule = rule

            # Create a finding report for this security group
            report = CheckReportStackIT(
                metadata=self.metadata(),
                resource=security_group,
            )

            if exposed_databases:
                report.status = "FAIL"
                databases_list = ", ".join(sorted(exposed_databases))
                report.status_extended = (
                    f"Security group {security_group.name} allows unrestricted database access "
                    f"to: {databases_list} from {exposing_rule.get_ip_range_display()} via rule {exposing_rule.get_rule_display_name()}."
                )
            else:
                report.status = "PASS"
                report.status_extended = f"Security group {security_group.name} does not allow unrestricted database access."

            report.resource_id = security_group.id
            report.resource_name = security_group.name
            report.location = security_group.region

            findings.append(report)

        return findings