Back to Checks
RDS instance is not publicly exposed to the Internet
rds_instance_no_public_access
Service: rdsSeverity: critical
OfficialBuilt-inVerified
Categories:internet-exposed
Resource Type:AwsRdsDbInstance
RDS DB instances are assessed for internet exposure using the PubliclyAccessible setting, security group ingress to the DB port from any address, and whether subnets are public. Instances that combine an internet-facing endpoint, open ingress, and public subnets are identified.
Risk
An internet-reachable database invites:
- Brute-force and vulnerability probing, risking availability and integrity
- Unauthorized queries and dumps leading to confidentiality loss
Compromise can enable lateral movement and persistence within the VPC.
Run this check with Prowler
Run in Prowler CloudRun
prowler aws --checks rds_instance_no_public_accessRecommendation
Keep databases private by applying least privilege at the network layer:
- Set
PubliclyAccessibletofalse - Place instances in private subnets
- Deny
0.0.0.0/0and::/0on the DB port - Expose access via private endpoints, VPN, or an application tier/DB proxy
Adopt defense in depth with monitoring and strong auth.
Remediation
CLI
aws rds modify-db-instance --db-instance-identifier <db_instance_id> --no-publicly-accessible --apply-immediatelyTerraform
# Ensure the RDS instance is not publicly accessible
resource "aws_db_instance" "<example_resource_name>" {
publicly_accessible = false # CRITICAL: disables public access (no public endpoint)
}NativeIaC
# CloudFormation: make the RDS instance private
Resources:
<example_resource_name>:
Type: AWS::RDS::DBInstance
Properties:
DBInstanceIdentifier: <example_resource_id>
PubliclyAccessible: false # CRITICAL: disables public access so the instance is not Internet-facingOther
1In the AWS console, go to RDS > Databases and select your DB instance
2Click Modify
3In Connectivity (Connectivity & security), set Public access to No (Not publicly accessible)
4Choose Continue, select Apply immediately (or during the next window), then click Modify DB instance
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.lib.security_groups import check_security_group
from prowler.providers.aws.services.rds.rds_client import rds_client
from prowler.providers.aws.services.vpc.vpc_client import vpc_client
class rds_instance_no_public_access(Check):
def execute(self):
findings = []
for db_instance in rds_client.db_instances.values():
report = Check_Report_AWS(metadata=self.metadata(), resource=db_instance)
report.status = "PASS"
report.status_extended = (
f"RDS Instance {db_instance.id} is not publicly accessible."
)
if db_instance.public:
report.status_extended = f"RDS Instance {db_instance.id} is set as publicly accessible, but is not publicly exposed."
# Check if any DB Instance Security Group is publicly open
if db_instance.security_groups:
public_sg = False
report.status_extended = f"RDS Instance {db_instance.id} is set as publicly accessible but filtered with security groups."
db_instance_port = db_instance.endpoint.get("Port")
if db_instance_port:
for security_group in ec2_client.security_groups.values():
if security_group.id in db_instance.security_groups:
for ingress_rule in security_group.ingress_rules:
if check_security_group(
ingress_rule,
"tcp",
[db_instance_port],
any_address=True,
):
report.status_extended = f"RDS Instance {db_instance.id} is set as publicly accessible and security group {security_group.name} ({security_group.id}) has {db_instance.engine} port {db_instance_port} open to the Internet at endpoint {db_instance.endpoint.get('Address')} but is not in a public subnet."
public_sg = True
if db_instance.subnet_ids:
for subnet_id in db_instance.subnet_ids:
if (
subnet_id in vpc_client.vpc_subnets
and vpc_client.vpc_subnets[
subnet_id
].public
):
report.status = "FAIL"
report.status_extended = f"RDS Instance {db_instance.id} is set as publicly accessible and security group {security_group.name} ({security_group.id}) has {db_instance.engine} port {db_instance_port} open to the Internet at endpoint {db_instance.endpoint.get('Address')} in a public subnet {subnet_id}."
break
if public_sg:
break
if public_sg:
break
findings.append(report)
return findings