Back to Checks
aws

RDS instance SSL/TLS certificate has more than 3 months of validity remaining

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

RDS DB instances are evaluated for server certificate validity windows, including default and customer-managed certificates. Certificates expired or approaching expiration (e.g., <1 month, <3 months, 3-6 months, >6 months) are identified using the certificate valid_till date.

Risk

Without timely rotation:

  • TLS failures block DB connections, impacting availability
  • Bypassed or weak validation enables MITM, risking confidentiality and integrity
  • Emergency changes increase operational risk and error rates

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks rds_instance_certificate_expiration

Recommendation

Establish a certificate lifecycle for RDS:

  • Rotate server/CA certs well before expiry; avoid pinned or outdated CAs
  • Keep client trust stores current and enforce TLS with validation
  • Monitor expiry and automate alerts/rotation
  • For custom certs, apply least privilege, separation of duties, and periodic key rotation; test changes

Remediation

CLI

aws rds modify-db-instance --db-instance-identifier <example_resource_id> --ca-certificate-identifier rds-ca-rsa2048-g1 --apply-immediately

Terraform

# Set a current CA on the RDS instance
resource "aws_db_instance" "<example_resource_name>" {
  identifier          = "<example_resource_id>"
  ca_cert_identifier  = "rds-ca-rsa2048-g1"  # CRITICAL: rotates to a valid CA to ensure certificate validity >3 months
}

NativeIaC

# CloudFormation: update RDS instance CA to a current certificate
Resources:
  <example_resource_name>:
    Type: AWS::RDS::DBInstance
    Properties:
      CACertificateIdentifier: rds-ca-rsa2048-g1  # CRITICAL: rotates to a valid CA to restore >3 months certificate validity

Other

1In the AWS Console, go to RDS > Databases and select the DB instance
2Click Modify
3In Connectivity (or Certificate authority), select rds-ca-rsa2048-g1
4Check Apply immediately
5Click Continue (if shown) and then Modify DB instance

Check Code

from datetime import datetime

from dateutil import relativedelta
from pytz import utc

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


class rds_instance_certificate_expiration(Check):
    # RDS Certificates with an expiration greater than 3 months the check will PASS with a severity of informational if greater than 6 months and a severity of low if between 3 and 6 months.
    # RDS Certificates that expires in less than 3 months the check will FAIL with a severity of medium.
    # RDS Certificates that expires in less than a month the check will FAIL with a severity of high.
    # RDS Certificates that are expired the check will FAIL with a severity of critical.
    def execute(self):
        findings = []
        for db_instance in rds_client.db_instances.values():
            report = Check_Report_AWS(metadata=self.metadata(), resource=db_instance)
            report.status = "FAIL"
            report.check_metadata.Severity = Severity.critical
            report.status_extended = (
                f"RDS Instance {db_instance.id} certificate has expired."
            )

            # Check only RDS DB instances that support parameter group encryption
            for cert in db_instance.cert:
                if not cert.customer_override:
                    if cert.valid_till > datetime.now(
                        utc
                    ) + relativedelta.relativedelta(months=6):
                        report.status = "PASS"
                        report.check_metadata.Severity = Severity.informational
                        report.status_extended = f"RDS Instance {db_instance.id} certificate has over 6 months of validity left."
                    elif cert.valid_till < datetime.now(
                        utc
                    ) + relativedelta.relativedelta(
                        months=6
                    ) and cert.valid_till > datetime.now(
                        utc
                    ) + relativedelta.relativedelta(
                        months=3
                    ):
                        report.status = "PASS"
                        report.check_metadata.Severity = Severity.low
                        report.status_extended = f"RDS Instance {db_instance.id} certificate has between 3 and 6 months of validity."
                    elif cert.valid_till < datetime.now(
                        utc
                    ) + relativedelta.relativedelta(
                        months=3
                    ) and cert.valid_till > datetime.now(
                        utc
                    ) + relativedelta.relativedelta(
                        months=1
                    ):
                        report.status = "FAIL"
                        report.check_metadata.Severity = Severity.medium
                        report.status_extended = f"RDS Instance {db_instance.id} certificate less than 3 months of validity."
                    elif cert.valid_till < datetime.now(
                        utc
                    ) + relativedelta.relativedelta(
                        months=1
                    ) and cert.valid_till > datetime.now(
                        utc
                    ):
                        report.status = "FAIL"
                        report.check_metadata.Severity = Severity.high
                        report.status_extended = f"RDS Instance {db_instance.id} certificate less than 1 month of validity."
                    else:
                        report.status = "FAIL"
                        report.check_metadata.Severity = Severity.critical
                        report.status_extended = (
                            f"RDS Instance {db_instance.id} certificate has expired."
                        )
                else:
                    if cert.valid_till > datetime.now(
                        utc
                    ) + relativedelta.relativedelta(months=6):
                        report.status = "PASS"
                        report.check_metadata.Severity = Severity.informational
                        report.status_extended = f"RDS Instance {db_instance.id} custom certificate has over 6 months of validity left."
                    elif cert.valid_till < datetime.now(
                        utc
                    ) + relativedelta.relativedelta(
                        months=6
                    ) and cert.valid_till > datetime.now(
                        utc
                    ) + relativedelta.relativedelta(
                        months=3
                    ):
                        report.status = "PASS"
                        report.check_metadata.Severity = Severity.low
                        report.status_extended = f"RDS Instance {db_instance.id} custom certificate has between 3 and 6 months of validity."
                    elif cert.valid_till < datetime.now(
                        utc
                    ) + relativedelta.relativedelta(
                        months=3
                    ) and cert.valid_till > datetime.now(
                        utc
                    ) + relativedelta.relativedelta(
                        months=1
                    ):
                        report.status = "FAIL"
                        report.check_metadata.Severity = Severity.medium
                        report.status_extended = f"RDS Instance {db_instance.id} custom certificate less than 3 months of validity."
                    elif cert.valid_till < datetime.now(
                        utc
                    ) + relativedelta.relativedelta(
                        months=1
                    ) and cert.valid_till > datetime.now(
                        utc
                    ):
                        report.status = "FAIL"
                        report.check_metadata.Severity = Severity.high
                        report.status_extended = f"RDS Instance {db_instance.id} custom certificate less than 1 month of validity."
                    else:
                        report.status = "FAIL"
                        report.check_metadata.Severity = Severity.critical
                        report.status_extended = f"RDS Instance {db_instance.id} custom certificate has expired."
            findings.append(report)

        return findings