Skip to main content
cd ../config-traps
risk/register/rds-snapshot-restores-silently-reset-publiclyaccessible.html
AWS RDS Networkinghigh severityAWS RDS

RDS Snapshot Restores Silently Reset PubliclyAccessible

Overview

A snapshot or point-in-time restore on Amazon RDS can hand out a public IP and public DNS endpoint even when the source instance and its security group were locked to VPC-only traffic, because the restore API defaults differ from the create API and no alarm fires when it happens.

At a glance

Unsafe setting
Restoring an RDS instance from a snapshot or point-in-time without explicitly passing PubliclyAccessible=false.
Failure trigger
A DR runbook or Terraform apply calls the restore API without the flag, and the API defaults it to true.
Blast radius
The restored database gets a public endpoint despite a VPC-only security group, and a later rule change exposes it to the internet unnoticed.
Recommended control
Force --no-publicly-accessible on every restore call and enforce it centrally with the rds-instance-public-access-check Config rule and auto-remediation.

Fix commands and configuration

aws rds restore-db-instance-from-snapshot --db-snapshot-identifier <snap> --db-instance-identifier <name> --no-publicly-accessible
rds-instance-public-access-check
AWSConfigRemediation-DisablePublicAccessForRDSInstance

The Trap

RestoreDBInstanceFromSnapshot and RestoreDBInstanceToPointInTime default PubliclyAccessible to true

The Default State

CreateDBInstance defaults PubliclyAccessible to false, so most engineers assume the setting is inherited or safely off by default across the RDS API surface. It is not. When you call RestoreDBInstanceFromSnapshot or RestoreDBInstanceToPointInTime and omit the PubliclyAccessible parameter, the AWS API sets it to true regardless of what the source instance had configured. Console-driven restores carry the same behaviour: the tick box defaults to enabled unless someone actively unticks it during the restore wizard. Terraform modules that use aws_db_instance with a snapshot_identifier and omit an explicit publicly_accessible argument inherit whatever the last apply state recorded, which frequently drifts to true after a manual console restore performed during an incident.

The Blast Radius

Disaster recovery runbooks and point-in-time restores are usually executed under time pressure, precisely when nobody is re-checking network flags. The restored instance receives a public DNS name and a public IP on its ENI. The security group may still list only the VPC CIDR, but the endpoint is now internet-routable, which means any later security group edit, VPC peering misconfiguration, or a stale 0.0.0.0/0 rule left from testing turns a private database into an internet-facing one instantly, with no deployment event to flag it. Port scanners and Shodan-style crawlers pick up the exposed endpoint within hours through passive DNS collection, and engine banner information leaks even before the security group is loosened, giving attackers version and patch-level intelligence for free.

The Lead Mechanic Fix

Never omit the flag on a restore call. Run aws rds restore-db-instance-from-snapshot --db-snapshot-identifier <snap> --db-instance-identifier <name> --no-publicly-accessible and the equivalent for RestoreDBInstanceToPointInTime. Enforce this with the AWS Config managed rule rds-instance-public-access-check paired with the SSM automation document AWSConfigRemediation-DisablePublicAccessForRDSInstance for automatic remediation, and set Terraform’s publicly_accessible explicitly to false on every db_instance resource with no ignore_changes lifecycle block masking drift.