Back to Checks
aws

RDS instance or cluster enforces SSL/TLS encryption for client connections

rds_instance_transport_encrypted
Service: rdsSeverity: high
OfficialBuilt-inVerified
Categories:encryption
Resource Type:AwsRdsDbInstance

RDS DB instances and DB clusters enforce SSL/TLS for client connections via parameter groups. The check looks for rds.force_ssl=1 (PostgreSQL, SQL Server) or require_secure_transport enabled (MySQL-family) and identifies databases where encryption enforcement isn't active.

Risk

Without enforced TLS, clients can connect or downgrade to plaintext, exposing credentials and queries to interception. Adversaries can perform MITM, steal secrets, and tamper traffic, undermining confidentiality and integrity and enabling reuse of captured database credentials.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks rds_instance_transport_encrypted

Recommendation

Enforce transport encryption at the database layer:

  • Enable rds.force_ssl=1 or require_secure_transport in parameter groups
  • Configure clients to require certificate validation and prevent fallback
  • Use current TLS versions and trusted CAs
  • Prefer private network access as defense in depth

Remediation

CLI

aws rds modify-db-parameter-group --region <REGION_NAME> --db-parameter-group-name <PARAMETER_GROUP_NAME> --parameters ParameterName='rds.force_ssl',ParameterValue='1',ApplyMethod='pending-reboot'

Terraform

# DB instances
resource "aws_db_parameter_group" "example_pg" {
  name   = "<example_resource_name>"
  family = "<DB_PARAMETER_FAMILY>"

  parameter {
    name  = "rds.force_ssl"
    value = "1"  # Critical: requires SSL/TLS for PostgreSQL/SQL Server instances
  }
}

resource "aws_db_parameter_group" "example_mysql" {
  name   = "<example_resource_name>"
  family = "<DB_PARAMETER_FAMILY>"

  parameter {
    name  = "require_secure_transport"
    value = "1"  # Critical: requires SSL/TLS for MySQL/MariaDB instances
  }
}

# Aurora clusters
resource "aws_rds_cluster_parameter_group" "example_aurora_pg" {
  name   = "<example_resource_name>"
  family = "<DB_CLUSTER_PARAMETER_FAMILY>"

  parameter {
    name  = "rds.force_ssl"
    value = "1"  # Critical: requires SSL/TLS for Aurora PostgreSQL clusters
  }
}

resource "aws_rds_cluster_parameter_group" "example_aurora_mysql" {
  name   = "<example_resource_name>"
  family = "<DB_CLUSTER_PARAMETER_FAMILY>"

  parameter {
    name  = "require_secure_transport"
    value = "ON"  # Critical: requires SSL/TLS for Aurora MySQL clusters
  }
}

NativeIaC

# CloudFormation: set required parameter to enforce SSL/TLS
Resources:
  ExampleDBParameterGroupPostgres:
    Type: AWS::RDS::DBParameterGroup
    Properties:
      Family: <DB_PARAMETER_FAMILY>
      Description: Enforce SSL/TLS
      Parameters:
        rds.force_ssl: "1"  # Critical: requires SSL/TLS for PostgreSQL/SQL Server instances

  ExampleDBParameterGroupMySQL:
    Type: AWS::RDS::DBParameterGroup
    Properties:
      Family: <DB_PARAMETER_FAMILY>
      Description: Enforce SSL/TLS
      Parameters:
        require_secure_transport: "1"  # Critical: requires SSL/TLS for MySQL/MariaDB instances

  ExampleDBClusterParameterGroupAuroraPostgres:
    Type: AWS::RDS::DBClusterParameterGroup
    Properties:
      Family: <DB_CLUSTER_PARAMETER_FAMILY>
      Description: Enforce SSL/TLS
      Parameters:
        rds.force_ssl: "1"  # Critical: requires SSL/TLS for Aurora PostgreSQL clusters

  ExampleDBClusterParameterGroupAuroraMySQL:
    Type: AWS::RDS::DBClusterParameterGroup
    Properties:
      Family: <DB_CLUSTER_PARAMETER_FAMILY>
      Description: Enforce SSL/TLS
      Parameters:
        require_secure_transport: ON  # Critical: requires SSL/TLS for Aurora MySQL clusters

Other

1In the AWS Console, go to RDS > Parameter groups
2For DB instances:
3- Edit the DB parameter group attached to the instance (or create one and attach it)
4- Set rds.force_ssl = 1 for PostgreSQL/SQL Server, or require_secure_transport = 1 for MySQL/MariaDB
5- Save. If the parameter is static, reboot the instance
6For Aurora clusters:
7- Edit the DB cluster parameter group attached to the cluster (or create one and attach it)
8- Set rds.force_ssl = 1 for Aurora PostgreSQL, or require_secure_transport = ON for Aurora MySQL
9- Save. Reboot instances if changes are pending-reboot
10Verify the parameter group is associated to the target instance/cluster and status shows the new value applied

Check Code

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.rds.rds_client import rds_client


class rds_instance_transport_encrypted(Check):
    def execute(self):
        findings = []
        supported_engines = [
            "sqlserver-se",
            "sqlserver-ee",
            "sqlserver-ex",
            "sqlserver-web",
            "postgres",
            "aurora-postgresql",
            "mysql",
            "mariadb",
            "aurora-mysql",
        ]
        for db_instance in rds_client.db_instances.values():
            report = Check_Report_AWS(metadata=self.metadata(), resource=db_instance)
            report.status = "FAIL"
            report.status_extended = (
                f"RDS Instance {db_instance.id} connections are not encrypted."
            )

            # Check only RDS DB instances that support parameter group encryption
            if not db_instance.cluster_id and any(
                engine in db_instance.engine for engine in supported_engines
            ):
                if db_instance.engine in [
                    "sqlserver-se",
                    "sqlserver-ee",
                    "sqlserver-ex",
                    "sqlserver-web",
                    "postgres",
                    "aurora-postgresql",
                ]:
                    for parameter in db_instance.parameters:
                        if (
                            parameter["ParameterName"] == "rds.force_ssl"
                            and parameter.get("ParameterValue", "0") == "1"
                        ):
                            report.status = "PASS"
                            report.status_extended = f"RDS Instance {db_instance.id} connections use SSL encryption."
                else:
                    for parameter in db_instance.parameters:
                        if (
                            parameter["ParameterName"] == "require_secure_transport"
                            and parameter.get("ParameterValue", "0") == "1"
                        ):
                            report.status = "PASS"
                            report.status_extended = f"RDS Instance {db_instance.id} connections use SSL encryption."

                findings.append(report)

        for db_cluster in rds_client.db_clusters:
            report = Check_Report_AWS(
                metadata=self.metadata(),
                resource=rds_client.db_clusters[db_cluster],
            )
            report.status = "FAIL"
            report.status_extended = f"RDS Cluster {rds_client.db_clusters[db_cluster].id} connections are not encrypted."
            # Check RDS Clusters that support TLS encryption
            if rds_client.db_clusters[db_cluster].force_ssl == "1":
                report.status = "PASS"
                report.status_extended = f"RDS Cluster {rds_client.db_clusters[db_cluster].id} connections use SSL encryption."
            if rds_client.db_clusters[db_cluster].require_secure_transport == "ON":
                report.status = "PASS"
                report.status_extended = f"RDS Cluster {rds_client.db_clusters[db_cluster].id} connections use SSL encryption."

            findings.append(report)

        return findings