Skip to main content
emnode / learn
Compliance High severity

AWS Security Hub · RDS

RDS.18: RDS sits in a public subnet reachable from the internet

Written and reviewed by Emnode · Last reviewed

What does AWS Security Hub RDS.18 check?

RDS.18 evaluates whether an RDS DB instance sits in a public subnet — one whose route table has a 0.0.0.0/0 route to an Internet Gateway. It reports FAILED when the instance's subnet group includes any such subnet, regardless of the PubliclyAccessible flag.

Why does RDS.18 matter?

Most database breaches come from a misconfigured firewall rule, not broken encryption. A database in a public subnet is one bad Security Group change or route-table edit away from being reachable from anywhere on the internet. A database in a private subnet cannot be reached no matter what someone does to the SG — the packet has nowhere to route. RDS.18 is the network-layer safety net that makes exposure structurally impossible rather than merely discouraged.

How do I fix RDS.18?

  1. Ensure the VPC has private subnets across at least two AZs with no IGW route (NAT-only or no default route).
  2. Create a DB subnet group composed solely of those private subnets.
  3. Migrate the instance via snapshot-and-restore or a Multi-AZ-assisted move into the private subnet group, then cut over clients to the new endpoint.
  4. Add a Config rule or IaC lint so future instances cannot be placed in public subnets.

Remediation script · bash

# Move the highest-impact case first: an RDS instance in a public subnet group.
aws rds create-db-subnet-group \
  --db-subnet-group-name prod-db-subnets-private \
  --db-subnet-group-description "Private subnets only - no IGW route" \
  --subnet-ids subnet-0aa11bb22cc33dd44 subnet-0ee55ff66aa77bb88

aws rds modify-db-instance \
  --db-instance-identifier prod-payments-db \
  --db-subnet-group-name prod-db-subnets-private \
  --apply-immediately

# Provide a private path before moving compute, so it can still reach AWS services.
# A free S3 gateway endpoint, or a narrow interface endpoint instead of a NAT gateway.
aws ec2 create-vpc-endpoint --vpc-id vpc-0a1b2c3d \
  --vpc-endpoint-type Interface \
  --service-name com.amazonaws.us-east-1.ssm \
  --subnet-ids subnet-0aa11 subnet-0bb22 \
  --security-group-ids sg-0ccfn33 --private-dns-enabled

# Force Redshift bulk traffic through the VPC (confirm an S3 gateway endpoint exists first).
aws redshift modify-cluster \
  --cluster-identifier analytics-prod --enhanced-vpc-routing

Full walkthrough (console steps, edge cases and verification) in the lesson Move resources into private networks (VPC isolation).

Is RDS.18 a false positive?

RDS.18 is distinct from RDS.2 — it fires on subnet topology even when PubliclyAccessible is false. Setting the instance's access flag to private does not clear it; the subnet group itself must contain no public subnets.

Part of the learning path Tighten your databases
  • RDS.1 An RDS snapshot is shared publicly
  • RDS.2 An RDS instance is publicly accessible from the internet
  • RDS.3 RDS DB instances should be encrypted at rest
  • RDS.4 RDS snapshots should be encrypted at rest
  • RDS.5 RDS DB instances should use multiple AZs
  • RDS.6 RDS lacks enhanced monitoring
  • RDS.7 RDS clusters should have deletion protection
  • RDS.8 RDS DB instances should have deletion protection
  • RDS.9 RDS engine logs are not shipped to CloudWatch
  • RDS.10 RDS relies on long-lived database passwords
  • RDS.11 RDS instances should have automatic backups
  • RDS.12 IAM auth should be configured for RDS clusters