RDS Publicly Accessible No Leaves an Open Security Group Rule Live
PubliclyAccessible No only removes an RDS instance's public IP; a leftover 0.0.0.0/0 security group rule keeps the database reachable from anywhere already inside the VPC, and can be silently reactivated by a restore or replica promotion.
Operational summary
At a glance
- Symptom
- An Amazon RDS instance shows "Publicly Accessible: No" in the console, yet a security review or an internal reachability test still finds the database…
- Likely cause
- The root cause is a security group attached to the RDS instance that still contains an inbound rule permitting traffic from 0.0.0.0/0 on the…
- Impact
- Any workload with network-layer reach into the VPC, not just the public internet, can attempt direct connections to the database port without further gatekeeping.
- Verification signal
- Validation succeeds only when the scoped rule blocks unauthorised sources while every legitimate application path keeps working.Re-run aws ec2 describe-security-groups and confirm the 0.0.0.0/0 entry on the database…
- Safe correction
- The correction is to remove the broad ingress rule and replace it with a scoped rule that names only the specific application-tier security group or narrow CIDR range…
- Rollback or recovery
- Rollback is a same-session, rule-level reversal, not a resource rebuild.If application connectivity fails validation, restore the original ingress rule immediately from the captured sg-before.json using aws ec2 authorize-security-group-ingress…
Symptom
An Amazon RDS instance shows “Publicly Accessible: No” in the console, yet a security review or an internal reachability test still finds the database port answering from outside the intended network boundary. Teams that treat the PubliclyAccessible flag as their only exposure control discover, usually during an audit or a near-miss, that the database was never actually isolated the way they assumed.
False Assumption
The team assumed that setting PubliclyAccessible to No is, by itself, sufficient to prevent the database from being reached over any unintended network path.
In practice, PubliclyAccessible only controls whether the DB instance’s network interface receives a publicly resolvable DNS name and a public IP address. It does not modify, and is not linked to, the inbound rules on the security group attached to that network interface. Two independent controls exist side by side, and disabling one does nothing to the other.
Root Cause
The root cause is a security group attached to the RDS instance that still contains an inbound rule permitting traffic from 0.0.0.0/0 on the database port, left over from an earlier development or testing phase and never revoked.
Because AWS treats the PubliclyAccessible attribute and security group membership as orthogonal settings, turning PubliclyAccessible off removes only the public IP address. Any resource that already has a network path into the VPC — a peered VPC, a Transit Gateway attachment, a site-to-site VPN, or another instance inside the same VPC — can still reach the database directly on that port, because the security group rule never stopped permitting it.
Impact
Any workload with network-layer reach into the VPC, not just the public internet, can attempt direct connections to the database port without further gatekeeping. In a shared or peered VPC environment this can mean unrelated teams, a compromised same-VPC host, or a misconfigured public-facing load balancer in the same VPC gain a direct path to a database the owning team believed was locked down.
The exposure also persists across seemingly unrelated operational events. A snapshot restore, a read-replica promotion, or a later console edit that flips PubliclyAccessible back to Yes for a temporary diagnostic task reactivates internet-facing exposure immediately, because the underlying security group rule was never fixed.
Diagnosis
Confirm the current state with read-only checks before changing anything.
| Check | What it confirms |
|---|---|
| PubliclyAccessible flag | Whether the instance currently has a public IP or DNS name assigned |
| Security group inbound rules | Whether 0.0.0.0/0 or an overly broad source is permitted on the database port |
| Subnet route table | Whether the DB subnet has a route to an internet gateway (public subnet) |
- Run
aws rds describe-db-instancesfor the instance to record the PubliclyAccessible flag and the attached security group IDs. - Run
aws ec2 describe-security-groupsagainst each attached group ID and inspect every IpPermissions entry for a 0.0.0.0/0 or ::/0 source on the database port. - Run
aws ec2 describe-route-tablesfor the DB subnet to confirm whether it is a public subnet with a route to an internet gateway, which raises the practical risk if the security group is also broad.
An example of the pattern to look for in the security group output — illustrative only, not a captured production value — is an ingress entry such as:
{ "IpProtocol": "tcp", "FromPort": 5432, "ToPort": 5432, "IpRanges": [{ "CidrIp": "0.0.0.0/0" }] }
Any rule matching this shape on the database port, on a security group attached to an RDS instance, is the condition this trap describes, regardless of the PubliclyAccessible value shown in the console.
Correction
The correction is to remove the broad ingress rule and replace it with a scoped rule that names only the specific application-tier security group or narrow CIDR range that legitimately needs database access.
- Capture the existing rule set first:
aws ec2 describe-security-groups --group-ids <sg-id> > sg-before.json. - Revoke the broad rule:
aws ec2 revoke-security-group-ingress --group-id <sg-id> --protocol tcp --port <db-port> --cidr 0.0.0.0/0. - Authorise a scoped replacement:
aws ec2 authorize-security-group-ingress --group-id <sg-id> --protocol tcp --port <db-port> --source-group <app-tier-sg-id>.
Apply this change first in a non-production or isolated validation environment using the same subnet group and application-tier security group topology as production, before touching the live instance. Perform the change during a maintenance window with the application team on standby, because a scoping error can remove legitimate access as readily as it removes illegitimate access.
Validation
Validation succeeds only when the scoped rule blocks unauthorised sources while every legitimate application path keeps working.
- Re-run
aws ec2 describe-security-groupsand confirm the 0.0.0.0/0 entry on the database port is gone and only the scoped source remains. - From an authorised application-tier host, confirm the database connection still succeeds and the application’s health checks stay green through at least one full monitoring cycle.
- From a host that is not in the authorised security group, confirm the connection attempt times out or is refused on the database port.
- Re-run
aws rds describe-db-instancesand confirm PubliclyAccessible is still No, so the two controls are now aligned rather than one silently compensating for the other.
Rollback
Rollback is a same-session, rule-level reversal, not a resource rebuild.
If application connectivity fails validation, restore the original ingress rule immediately from the captured sg-before.json using aws ec2 authorize-security-group-ingress with the same parameters that were revoked, then stop the change and reopen it as a planned exercise once every legitimate source has been identified. Do not delete or recreate the security group object itself; keep the rollback scoped to individual ingress rule entries so the recovery path stays fast and low-risk. Treat any connectivity failure that persists beyond one monitoring cycle after rollback as a signal to escalate to the on-call platform lead rather than continuing to iterate on the live database’s security group.
Prevention
Enable the AWS Config managed rule rds-instance-public-access-check so that a broad security group combined with public accessibility is flagged automatically rather than relying on manual review of the console flag alone. Extend the same automated check, or an equivalent custom rule, to also evaluate the security group’s own inbound rules independently of the PubliclyAccessible attribute, since the flag alone cannot tell you whether the underlying rule set is safe.
Require that every RDS instance uses a dedicated, purpose-specific security group rather than a shared or default group, and add a step to snapshot-restore and read-replica-promotion runbooks that re-verifies both PubliclyAccessible and the attached security group’s rules immediately after the operation completes, before treating the new resource as production-ready.
Apply the safer control
Before you change production
Confirm the affected scope, export the current configuration, and test the replacement control in a non-production environment first.
Fix commands and configuration
aws rds describe-db-instancesaws ec2 describe-security-groupsaws ec2 describe-route-tablesVerify, roll back or escalate
Verify
Validation succeeds only when the scoped rule blocks unauthorised sources while every legitimate application path keeps working.Re-run aws ec2 describe-security-groups and confirm the 0.0.0.0/0 entry on the database port is gone and only the scoped source remains.From an authorised application-tier…
Rollback
Rollback is a same-session, rule-level reversal, not a resource rebuild.If application connectivity fails validation, restore the original ingress rule immediately from the captured sg-before.json using aws ec2 authorize-security-group-ingress with the same parameters that were revoked, then stop the change and…
Escalate
Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.