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 thatexampledb
is listening on is5432
.
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 to0.0.0.0/0** or**::/0
as identified in the screenshot below, the security group in question allows unrestricted traffic on port5432
.
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.