Skip to main content
emnode / learn
Compliance Medium severity

AWS Security Hub · RDS

RDS.38: RDS PostgreSQL should be encrypted in transit

Written and reviewed by Emnode · Last reviewed

What does AWS Security Hub RDS.38 check?

RDS.38 inspects the parameter group on a standalone RDS for PostgreSQL instance and checks the rds.force_ssl parameter. It reports FAILED when rds.force_ssl is 0 — the instance permits TLS but does not require it. It evaluates standalone instances only, not Aurora-style cluster members.

Why does RDS.38 matter?

RDS for PostgreSQL supports SSL/TLS out of the box, but "can" is not "must": by default the instance happily accepts a plaintext connection from any client that doesn't ask for SSL. A single misconfigured application, an old driver, or a forgotten cron job then ships credentials and query data across the network in the clear. Setting rds.force_ssl to 1 flips the database from SSL-optional to SSL-required and rejects any non-TLS connection at the door.

How do I fix RDS.38?

  1. Confirm all clients can negotiate TLS before enforcing.
  2. Set rds.force_ssl=1 in a custom DB parameter group and attach it to the instance.
  3. Reboot if the parameter requires it, then verify plaintext connections are refused.
  4. Standardise the parameter group across PostgreSQL instances.

Remediation script · bash

# Find the highest-impact plaintext-permitting stores across engines.
aws rds describe-db-instances \
  --query 'DBInstances[].DBInstanceIdentifier' --output text
aws elasticache describe-replication-groups \
  --query 'ReplicationGroups[?TransitEncryptionEnabled==`false`].ReplicationGroupId' \
  --output text

# RDS for PostgreSQL: require TLS via rds.force_ssl (static -> needs a reboot).
PG=$(aws rds describe-db-instances --db-instance-identifier prod-orders-pg \
  --query 'DBInstances[].DBParameterGroups[].DBParameterGroupName' --output text)
aws rds modify-db-parameter-group --db-parameter-group-name "$PG" \
  --parameters 'ParameterName=rds.force_ssl,ParameterValue=1,ApplyMethod=pending-reboot'
aws rds reboot-db-instance --db-instance-identifier prod-orders-pg

# Redshift: require_ssl on a custom cluster parameter group, then reboot.
aws redshift modify-cluster-parameter-group --parameter-group-name analytics-tls \
  --parameters ParameterName=require_ssl,ParameterValue=true
aws redshift reboot-cluster --cluster-identifier analytics-prod

Full walkthrough (console steps, edge cases and verification) in the lesson Enforce TLS on database and cache connections.

Is RDS.38 a false positive?

RDS.38 covers standalone instances only — Aurora PostgreSQL cluster members use a cluster parameter group and are governed by a different control, so a cluster member will not appear under RDS.38.

Part of the learning path Encrypt everything
  • RDS.1 An RDS snapshot is shared publicly
  • RDS.2 An RDS instance is publicly accessible from the internet
  • RDS.3 RDS DB instances should be encrypted at rest
  • RDS.4 RDS snapshots should be encrypted at rest
  • RDS.5 RDS DB instances should use multiple AZs
  • RDS.6 RDS lacks enhanced monitoring
  • RDS.7 RDS clusters should have deletion protection
  • RDS.8 RDS DB instances should have deletion protection
  • RDS.9 RDS engine logs are not shipped to CloudWatch
  • RDS.10 RDS relies on long-lived database passwords
  • RDS.11 RDS instances should have automatic backups
  • RDS.12 IAM auth should be configured for RDS clusters