Description

Ensure that no Amazon RDS DB instance is exposed to the Internet. A DB instance is considered exposed when all three conditions are true: its Public access setting is enabled, one of its security groups allows inbound traffic to the database port from any address (0.0.0.0/0 or ::/0), and it is placed in a public subnet (a subnet whose route table sends traffic to an internet gateway).

Rationale

A database that can be reached from the Internet is continuously probed for weak passwords and known vulnerabilities. A successful attack can expose or delete data and can be used as a starting point to move to other resources in the VPC. Keeping DB instances private, in private subnets and with security groups that only allow trusted sources, applies least privilege at the network layer. Access from outside the VPC should go through a VPN, a bastion host or an application tier.

Impact

  • Removes direct Internet access to the database endpoint

  • Reduces the risk of brute-force attacks, data exposure and service disruption

  • Clients that connect to the database over the Internet lose access until they connect through a VPN, AWS Direct Connect, a bastion host or another private path

Default Value

In the RDS console, Public access is set to No by default when a DB instance is created. When an instance is created through the API or CLI without this setting, the default depends on the VPC and DB subnet group used, and an instance in a default VPC can be publicly accessible.

Pre-Requisites

  • IAM permissions: rds:DescribeDBInstances, rds:ModifyDBInstance, ec2:DescribeSecurityGroupRules, ec2:DescribeRouteTables and ec2:RevokeSecurityGroupIngress

  • A list of the clients that need database access and how they will connect after the change

  • Confirmation from the application owner that no required client depends on Internet access to the database

Remediation

Test Plan

Console:

  1. Sign in to the AWS Management Console at https://console.aws.amazon.com.

  2. Open the Amazon RDS console and select Databases.

  3. Select a DB instance and open the Connectivity & security tab.

  4. Check whether Publicly accessible is Yes. If it is No, the instance passes.

  5. Note the database Port, then open each listed VPC security group and check its Inbound rules for a rule that allows the database port (or all traffic) from 0.0.0.0/0 or ::/0.

  6. Open each subnet listed for the instance and check its Route table for a route with target igw-... (internet gateway).

  7. Repeat for each DB instance in each region in use.

  8. If all three conditions are met, follow the implementation steps.

CLI:

Show the public access setting, port, security groups and subnets of all DB instances:

aws rds describe-db-instances --region <REGION> --query "DBInstances[].[DBInstanceIdentifier,PubliclyAccessible,Endpoint.Port,VpcSecurityGroups[].VpcSecurityGroupId,DBSubnetGroup.Subnets[].SubnetIdentifier]"

For each security group of a publicly accessible instance, list its inbound rules open to the Internet:

aws ec2 describe-security-group-rules --region <REGION> --filters Name=group-id,Values=<SECURITY_GROUP_ID> --query "SecurityGroupRules[?IsEgress==\`false\` && (CidrIpv4=='0.0.0.0/0' || CidrIpv6=='::/0')].[SecurityGroupRuleId,IpProtocol,FromPort,ToPort,CidrIpv4,CidrIpv6]" --output table

For each subnet, show the routes of its route table (if nothing is returned, the subnet uses the main route table of the VPC):

aws ec2 describe-route-tables --region <REGION> --filters Name=association.subnet-id,Values=<SUBNET_ID> --query "RouteTables[].Routes[].[DestinationCidrBlock,DestinationIpv6CidrBlock,GatewayId]" --output table

A DB instance fails if PubliclyAccessible is true, a security group has an inbound rule from 0.0.0.0/0 or ::/0 that covers the database port (or protocol -1), and at least one of its subnets has a route to an internet gateway (igw-...).

Implementation Steps

Console:

  1. Sign in to the AWS Management Console at https://console.aws.amazon.com.

  2. Open the Amazon RDS console and select Databases.

  3. Select the DB instance found in the Test Plan and choose Modify.

  4. In the Connectivity section, under Additional configuration, set Public access to Not publicly accessible.

  5. Choose Continue.

  6. Under Schedule modifications, select Apply immediately or apply the change during the next maintenance window.

  7. Choose Modify DB instance.

  8. In the EC2 console, edit the inbound rules of the instance's security groups and replace any rule open to 0.0.0.0/0 or ::/0 with a rule that allows only trusted IP ranges or security groups.

  9. Repeat for each affected DB instance in each region in use.

CLI:

Turn off public access for the DB instance:

aws rds modify-db-instance --region <REGION> --db-instance-identifier <DB_INSTANCE_ID> --no-publicly-accessible --apply-immediately

Remove the security group rule that is open to the Internet, using the rule ID from the Test Plan output:

aws ec2 revoke-security-group-ingress --region <REGION> --group-id <SECURITY_GROUP_ID> --security-group-rule-ids <SECURITY_GROUP_RULE_ID>

Backout Plan

Before making changes, save the current inbound rules of each security group:

aws ec2 describe-security-group-rules --region <REGION> --filters Name=group-id,Values=<SECURITY_GROUP_ID> > <SECURITY_GROUP_ID>-rules-backup.json

To roll back:

  1. Sign in to the AWS Management Console at https://console.aws.amazon.com.

  2. Open the Amazon RDS console, select the DB instance and choose Modify.

  3. In the Connectivity section, set Public access to Publicly accessible.

  4. Choose Continue, select when to apply the change, then choose Modify DB instance.

  5. In the EC2 console, re-add the removed inbound rules using the saved backup.

CLI:

aws rds modify-db-instance --region <REGION> --db-instance-identifier <DB_INSTANCE_ID> --publicly-accessible --apply-immediately

Note: rolling back exposes the database to the Internet again. Use it only as a temporary measure while private access is arranged.

Reference