AWS RDS with public subnets with open ports

Risk level: High

Rule ID: RDS-007

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 Engine Default Port
Aurora/MySQL/MariaDB 3306
PostgreSQL 5432
SQL Server 1433
Oracle 1521

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:

 

Using AWS Console

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.

Using AWS CLI

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

Using AWS Console

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.

Using AWS CLI

1. Execute the revoke-security-group-ingress command after substituting the Security Group Name and Port number as follows

  • <SECURITY_GROUP_ID>: ID of the Security Group identified in Step 4 of Audit Section above
  • <PORT>: Port Number RDS Instance is listening on.

This will remove any affected inbound rules from the designated security group for a specific port number with the source defined as 0.0.0.0/0.

Note that the command returns true on successful revocation.

aws ec2 revoke-security-group-ingress \\
	--region us-east-1 \\
	--group-id sg-0d87d2c655bd8cd7f \\
	--protocol tcp \\
	--port 5432 \\
	--cidr 0.0.0.0/0

**Output**
{
    "Return": true
}

 
2. Next, run the authorize-security-group-ingress command to add the inbound rules with better access configurations.

To achieve this, implement one of the following steps:

a. Allow Port from a specific host only

aws ec2 authorize-security-group-ingress \\
	--region us-east-1 \\
	--group-id sg-0d87d2c655bd8cd7f \\
	--protocol tcp \\
	--port 5432 \\
	--cidr X.X.X.X./32

b. Allow Port from a specific IP Range

aws ec2 authorize-security-group-ingress \\
	--region us-east-1 \\
	--group-id sg-0d87d2c655bd8cd7f \\
	--protocol tcp \\
	--port 5432 \\
	--cidr X.X.X.X./24

c. Allow Port from another security group

aws ec2 authorize-security-group-ingress \\
	--region us-east-1 \\
	--group-id sg-0d87d2c655bd8cd7f \\
	--protocol tcp \\
	--port 5432 \\
	--source-group **MyWebAppSecurityGroup**

 
3. Execute Steps 1 - 2 to update other identified EC2 security groups.
 
4. Update the --region parameter and perform Steps 1 - 3 to discover and fix security groups in 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.