NEW Upcoming Enablement Session: Optimizing Auto Scaling Groups for ECS - Register Now

NEW Featured eBook: AWS Cloud Cost Allocation: The Complete Guide - Download Now

AWS RDS with public subnets with open ports

You should provision AWS RDS instances in private subnets to shield them from direct internet traffic. However, suppose you must deploy an RDS instance on public subnets for any reason. In that case, you must verify that no inbound rules exist in any security group that permits unfettered access (i.e., 0.0.0.0/0 or::/0) (particularly on the TCP/IP port that your Database listens on).

The table below lists the default endpoint ports for each RDS database engine:

Database EngineDefault Port
Aurora/MySQL/MariaDB3306
PostgreSQL5432
SQL Server1433
Oracle1521

 

To use the least privilege principle, only known hosts, services, IP addresses, or security groups should be permitted. Unrestricted access to an RDS instance allows malicious attackers to brute force their way in and potentially get network access. This can lead to harmful activities like hacking and man-in-the-middle (MITM) attacks.

This rule can help you with the following:

Compliance Frameworks’ reports

SOC 2 Readiness Report
HIPAA Readiness Report
CIS Readiness Report
AWS Well-Architected Lens

AWS Well-Architected Framework Lens
AWS MSP Partner Program Validation Audit Checklist

Audit

To verify if your RDS Instance security groups enable unrestricted incoming access to the listening port, follow the steps below:

1. Access the RDS dashboard at https://console.aws.amazon.com/rds/.

2. Under the RDS Dashboard Resources section, click DB Instances.

3. Select the DB Identifier to inspect.

4. Click on Connectivity & security Tab and examine the following information:

a.Subnets: This information is available in the middle Networking sub-section.

An RDS instance could be provisioned in multiple subnets, as shown below

1. Click on the first subnet link as shown above to navigate to the VPC Subnets page.

2. Select the linked subnet listed on the page and scroll down to view the Route Table tab.

If an Internet Gateway (igw-xxxxxxxxxxx) routes to CIDR block 0.0.0.0/0 as shown below, the RDS instance in question is deployed in a public subnet.

Skip to Part b as soon as you find a public subnet attached to the RDS instance.

3. Steps 1 and 2 should be repeated to ascertain the status of other VPC subnets connected with the specified RDS instance.

4. If there are no public subnets attached to your RDS instance, your instance is protected from direct internet traffic and can only be accessed within the desired VPC.

b.Public accessible: This information is available on the right side under the Security section.

If the value is set to :

1. Yes indicates that your RDS instance has a public IP address and that anyone outside the VPC may connect to it. If this is the case, proceed to Part C.

2.No signifies that EC2 instances and other devices outside of the VPC cannot connect to the instance. Instead, you specify access using a security group.

Proceed to **Part C** to determine which security group has been attached and which incoming rules have been defined.

c.VPC Security Groups: This information may be found on the right side under the Security section. Note there might be several security groups associated with the instance.

Clicking on any security group will redirect you to its configuration of inbound and outbound rules, as shown below.

But before doing that, let’s examine the port number which the Database is listening on as described below:

    • Port Number: This information is generally available on the left side under the Endpoint & port section. For example, in the screenshot below, the port number that exampledb is listening on is 5432.

Now click on the first security group to redirect to the Security Group Configuration Page.

Select the Security group listed on the page and click on the Inbound Rules tab. Note that if one or more rules have the source set to 0.0.0.0/0** or**::/0 as identified in the screenshot below, the security group in question allows unrestricted traffic on port 5432.

5. Replicate steps 3–4 for other RDS database instances deployed in the current region.

6. Change the AWS region from the top menu and repeat the audit procedure.

1. To retrieve the names (identifiers) of all RDS database instances present in the chosen AWS region, execute the describe-db-instances command while using specified custom query parameters as shown below:

aws rds describe-db-instances \\
	--region us-east-1 \\
	--query 'DBInstances[*].DBInstanceIdentifier'

**Output**
[
    "database-11",
    "database-1-instance-1-us-east-1c",
    "database-2-instance-1",
    "demo-database",
    "exampledb"
]

For this explainer, we will examine the security configuration of the demo-database shown above.
 
2. Examine Subnets associated with the specified RDS database

a. Re-execute the describe-db-instances command with the following specified parameters as shown below:

I.-db-instance-identifier

II.-query : Specify DBInstances[*].DBSubnetGroup.Subnets[]' to retrieve the attached instance subnets

aws rds describe-db-instances \\
	--region us-east-1 \\
	--db-instance-identifier demo-database \\
	--query 'DBInstances[*].DBSubnetGroup.Subnets[]'

**Output**
[
    {
        "SubnetIdentifier": "subnet-025f7a629b8692edb",
        "SubnetAvailabilityZone": {
            "Name": "us-east-1c"
        },
        "SubnetOutpost": {},
        "SubnetStatus": "Active"
    },
    {
        "SubnetIdentifier": "subnet-003304063571937fe",
        "SubnetAvailabilityZone": {
            "Name": "us-east-1d"
        },
        "SubnetOutpost": {},
        "SubnetStatus": "Active"
    },
    {
        "SubnetIdentifier": "subnet-0fd0d04b27a3be494",
        "SubnetAvailabilityZone": {
            "Name": "us-east-1a"
        },
        "SubnetOutpost": {},
        "SubnetStatus": "Active"
    },
    {
        "SubnetIdentifier": "subnet-073950b4b2b8a5d53",
        "SubnetAvailabilityZone": {
            "Name": "us-east-1f"
        },
        "SubnetOutpost": {},
        "SubnetStatus": "Active"
    },
    {
        "SubnetIdentifier": "subnet-065a001c2b9059c7f",
        "SubnetAvailabilityZone": {
            "Name": "us-east-1e"
        },
        "SubnetOutpost": {},
        "SubnetStatus": "Active"
    },
    {
        "SubnetIdentifier": "subnet-0bb07bbfbf8f677d1",
        "SubnetAvailabilityZone": {
            "Name": "us-east-1b"
        },
        "SubnetOutpost": {},
        "SubnetStatus": "Active"
    }
]

The resulting output provides a list of subnets associated with the instance.

b. Now, attach the previously obtained SubnetIDs in executing the describe-route-tables command which will specify the VPC route table’s routes associated with the specified subnet.

aws ec2 describe-route-tables \\
	--region us-east-1 \\
	--filters "Name=association.subnet-id,Values=subnet-025f7a629b8692edb" \\
	--query 'RouteTables[*].Routes[]'

**Output**
[]

The result should include any explicit route tables and related subnet routes. If a subnet is not expressly paired with a route table, the command returns an empty list. In such circumstances, the subnet is implicitly linked to the VPC’s main route table.

In this example, the command’s output is an empty list; hence the subnet is associated with the main route table of the VPC.

c. Execute the describe-db-instances command with the parameters outlined below to retrieve the affiliated RDS instance’s VPC:

aws rds describe-db-instances \\
        --region us-east-1 \\
        --db-instance-identifier demo-database \\
        --query 'DBInstances[*].DBSubnetGroup.VpcId'

**Output**
[
    "vpc-xxxxxxxxxxx"
]

d. Using the VPCId returned above, re-execute the describe-route-tables command to retrieve the main route table and associated routes with the VPC

aws ec2 describe-route-tables \\
	--region us-east-1 --filters Name=vpc-id,Values=vpc-xxxxxxxxx Name=association.main,Values=true \\
--query 'RouteTables[*].{TableId: RouteTableId, Routes: Routes}'

**Output**
[
    {
        "TableId": "rtb-08e639f9d2a0ff58c",
        "Routes": [
            {
                "DestinationCidrBlock": "172.30.0.0/16",
                "GatewayId": "local",
                "Origin": "CreateRouteTable",
                "State": "active"
            },
            **{
                "DestinationCidrBlock": "0.0.0.0/0",
                "GatewayId": "igw-0ad7d2f4f4e64e9f2",
                "Origin": "CreateRoute",
                "State": "active"
            }**
        ]
    }
]

As earlier mentioned, if an Internet Gateway (igw-xxxxxxxxxxx) routes to CIDR block 0.0.0.0/0 as shown below, the RDS instance in question is deployed in a public subnet.

Skip to Step 3 as soon as you find a public subnet attached to the RDS instance.

e. Repeat steps 2b and 2c to ascertain the status of other VPC subnets connected with the specified RDS instance.

f. If there are no public subnets attached to your RDS instance, your instance is protected from direct internet traffic and can only be accessed within the desired VPC.

 
3. Execute thedescribe-db-instances with the specified parameters and query filter shown below to check if the RDS in question is publicly accessible or not:

aws rds describe-db-instances \\
        --region us-east-1 \\
        --db-instance-identifier demo-database \\
        --query 'DBInstances[*].PubliclyAccessible'

**Output**
[
    true
]

If the output is:

1.true, it means that a public IP address has been assigned to your RDS instance, and anyone can connect to it outside VPC.

2. **false** means that EC2 instances and other devices outside VPC can’t connect to the instance. You define the access via a security group instead.

 
4. Execute thedescribe-db-instances with the specified parameters and query filter shown below to check the security groups attached to the specified RDS Instance:

aws rds describe-db-instances \\
        --region us-east-1 \\
        --db-instance-identifier demo-database \\
        --query 'DBInstances[*].VpcSecurityGroups'

Output
[
    [
        {
            "VpcSecurityGroupId": "sg-0d87d2c655bd8cd7f",
            "Status": "active"
        }
    ]
]

The command should retrieve the list of all Security Groups attached to the RDS Instance.
 
5. Execute the describe-security-groups command with the specified parameters and query filter shown below to ascertain the inbound rules defined for the security group in question.

aws ec2 describe-security-groups \\
 --region us-east-1 \\
 --group-ids sg-0d87d2c655bd8cd7f \\
 --query 'SecurityGroups[*].IpPermissions'

**Output**
[
    [
        {
            "FromPort": 5432,
            "IpProtocol": "tcp",
            "IpRanges": [
                {
                    "CidrIp": "0.0.0.0/0"
                }
            ],
            "Ipv6Ranges": [],
            "PrefixListIds": [],
            "ToPort": 5432,
            "UserIdGroupPairs": []
        }
    ]
]
	

Note that if one or more rules in the IpRanges list have the CidrIp set to 0.0.0.0/0 as identified in the output above, the security group in question allows unrestricted traffic on port 5432.
 
6. You should repeat steps 1–5 to validate the security setup for the current region’s other deployed RDS database instances.
 
7. Update the —region parameter in all the steps above and perform the entire audit process again.

Remediation / Resolution

1. Access the EC2 Dashboard at https://console.aws.amazon.com/ec2/.

2. In the Network & Security section on the left, choose Security Groups.

3. Please choose one of the filtered security groups we discovered in Step 3c of the Audit section and scroll down to the Inbound rules tab.

4. Select the Security Group Rule corresponding to the RDS Port Number identified in **Step 3c of the Audit section.**

5.Edit Inbound Rules to edit the incoming traffic control rules.

6. To do this, follow one of the following steps:

a. Click the dropdown box in the Source column and select the custom option and perform one of the following actions based on your specified access details:

  • Set the static IP/Elastic IP address with the suffix set to /32, e.g., x.x.x.x/32.
  • Select an appropriate option under the CIDR blocks sub-section. This will be the IP address range of the permitted hosts.
  • Set another security group’s name or ID. The selected security group must be provisioned in the same region.

7. Save the updated info.

8. Repeat steps 4 – 6 to update other filtered security groups.

9. To identify and modify security groups that allow unrestricted access, change the region name from the top menu and repeat the entire procedure.

1. Run describe-db-instance command (OSX/Linux/UNIX) to list all RDS instance names, available in the selected AWS region:

aws rds describe-db-instances 
--region ap-south-1   
--query 'DBInstances[?DBInstanceStatus==`available`].[DBInstanceIdentifier]' 
--output table

The command should return each database instance identifier:

2. Run modify-db-instance command (OSX/Linux/UNIX) to modify the selected RDS instance configuration. The following command example enables Multi-AZ deployment for an RDS instance named database-1. The configuration change is asynchronously applied as soon as possible:

aws rds modify-db-instance 
--db-instance-identifier database-1 
--multi-az 
--apply-immediately 
--output table

3. Run describe-db-instance command (OSX/Linux/UNIX) using the RDS instance identifier to check if the Multi-AZ feature has been successfully enabled:

aws rds describe-db-instances 
--region ap-south-1     
--db-instance-identifier database-1  
--query 'DBInstances[*].[MultiAZ]'    
--output table

4. The command output should show the current status:

Steps can be repeated for other AWS regions. Change the AWS region by using the –region filter to repeat the process for other regions.

Still Need Help?

Come see why we are the #1 cloud management platform and why companies like Uber, Dickey’s BBQ Pit and Norwegian Cruise Line trust nOps to manage their cloud.