Skip to main content
emnode
Compliance High severity

AWS Security Hub · RDS

RDS.46: An RDS instance sits in a public subnet with an internet route

Written and reviewed by Emnode · Last reviewed

What does AWS Security Hub RDS.46 check?

RDS.46 is a network-topology check on the AWS::RDS::DBInstance resource. It reports FAILED when an RDS instance sits in a public subnet, one whose route table has a 0.0.0.0/0 (or ::/0) route pointing at an internet gateway.

Why does RDS.46 matter?

Subnet placement is a security boundary. The control does not care whether the database is encrypted, has a public IP, or has a locked-down security group today: it cares that the route to the internet is already sitting in the same room as the data. A database in a public subnet is one over-broad SG rule, one accidental 0.0.0.0/0 ingress, or one misconfigured NACL away from exposure. The downside on a customer or financial database is uncapped: breach notification, regulatory fines, and reputational damage.

How do I fix RDS.46?

  1. Provision private subnets across at least two AZs with no internet-gateway route.
  2. Build a DB subnet group from those private subnets only.
  3. Move the instance into it via snapshot-and-restore or a Multi-AZ-assisted migration during a maintenance window, then repoint clients.
  4. Make databases private by default in IaC so the finding stops appearing rather than being handled case by case.

Remediation script · bash

# Move the highest-impact databases onto IAM authentication first (free, no reboot).
for db in $(aws rds describe-db-instances \
    --query 'DBInstances[?IAMDatabaseAuthenticationEnabled==`false`].DBInstanceIdentifier' \
    --output text); do
  aws rds modify-db-instance --db-instance-identifier "$db" \
    --enable-iam-database-authentication --apply-immediately
  echo "$db: IAM database authentication enabled"
done

# Find every instance still using a default admin username (immutable; needs migration).
aws rds describe-db-instances \
  --query "DBInstances[?contains(['admin','postgres','root','sa','master','mysql','dbadmin'], MasterUsername)].[DBInstanceIdentifier,MasterUsername]" \
  --output table

# Recreate one of those with a non-default master username set explicitly at creation.
aws rds restore-db-cluster-from-snapshot \
  --db-cluster-identifier prod-orders-db-v2 \
  --snapshot-identifier prod-orders-db-pre-rename \
  --engine aurora-postgresql

Full walkthrough (console steps, edge cases and verification) in the lesson Harden database auth, ports and access.

Is RDS.46 a false positive?

A locked-down security group does not satisfy RDS.46: SG rules change in seconds, but the subnet's internet-gateway route is the structural gap the control flags. Only moving the instance to a private subnet clears it.

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