RDS PubliclyAccessible Fixes Wait for Maintenance Window
An engineer runs modify-db-instance with -no-publicly-accessible but omits -apply-immediately, so AWS defers the change to the next maintenance window while the instance keeps answering on 3306 or 5432 across 0.0.0.0/0. Security Hub, ticketing systems and the engineer all treat the exposure as closed while it remains live for days.
Operational summary
At a glance
- Symptom
- An audit remediation ticket is closed based on a successful API call while the instance remains publicly reachable until the next maintenance window.
- Likely cause
- modify-db-instance --no-publicly-accessible is run without --apply-immediately, so the change sits in PendingModifiedValues instead of taking effect.
- Impact
- The database stays reachable on 0.0.0.0/0 over 3306/5432 for days while dashboards and tickets report the exposure as resolved.
- Verification signal
- Re-run the detection test and a controlled negative-path test.
- Safe correction
- Pair PubliclyAccessible changes with --apply-immediately, verify PendingModifiedValues is empty, and enforce closure via AWS Config auto-remediation.
- Rollback or recovery
- Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.
The Trap
Deferred PubliclyAccessible remediation. A database is exposed with PubliclyAccessible: true and a security group ingress rule of 0.0.0.0/0 on port 3306 (MySQL/Aurora) or 5432 (PostgreSQL). An engineer spots this in an audit and runs aws rds modify-db-instance --no-publicly-accessible, closes the ticket, and moves on. The change never actually applies.
The Default State
The AWS CLI’s modify-db-instance command defaults --apply-immediately to false unless explicitly overridden. The Management Console mirrors this: the “Scheduling of modifications” section on the Modify page pre-selects “Apply during the next scheduled maintenance window” rather than “Apply immediately”. Any change to PubliclyAccessible submitted without the immediate flag is written into PendingModifiedValues, not into the live instance state.
The Blast Radius
describe-db-instances continues to return PubliclyAccessible: true until the preferred maintenance window arrives, which can be seven days out, or indefinitely if the window keeps getting skipped because AutoMinorVersionUpgrade is disabled and no other pending change forces a window event. The security group’s 0.0.0.0/0 rule on 3306/5432 is untouched by this modify call entirely, since it’s a separate EC2 resource, so the endpoint remains internet-reachable throughout. Meanwhile the ticket is closed, the change history shows a successful API call, and cached AWS Security Hub findings for control RDS.2 may briefly show resolved. Mass scanners on Shodan and routine masscan sweeps continue to enumerate the open port and attempt master-user credential brute force during the entire gap, with no alerting difference between “fix pending” and “fix applied”.
The Lead Mechanic Fix
Always pair the flag with immediate application and verify state explicitly: aws rds modify-db-instance --db-instance-identifier prod-db --no-publicly-accessible --apply-immediately, then confirm with aws rds describe-db-instances --db-instance-identifier prod-db --query 'DBInstances[0].[PubliclyAccessible,PendingModifiedValues]' until PendingModifiedValues returns empty. Separately revoke the security group rule: aws ec2 revoke-security-group-ingress --group-id sg-xxxxxxxx --protocol tcp --port 3306 --cidr 0.0.0.0/0. For standing enforcement, deploy the AWS Config managed rule rds-instance-public-access-check with automatic remediation via the SSM document AWSConfigRemediation-DisablePublicAccessForRDSInstance, which sets ApplyImmediately=true internally and closes the pending-state gap that manual CLI runs leave open.
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 modify-db-instance --db-instance-identifier prod-db --no-publicly-accessible --apply-immediatelyaws rds describe-db-instances --db-instance-identifier prod-db --query 'DBInstances[0].[PubliclyAccessible,PendingModifiedValues]'PendingModifiedValuesVerify, roll back or escalate
Verify
Re-run the detection test and a controlled negative-path test. Confirm the unsafe behaviour is blocked while approved traffic still succeeds.
Rollback
Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.
Escalate
Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.