Skip to content

Aurora PostgreSQL DB clusters should publish logs to CloudWatch Logs

Aurora PostgreSQL generates logs that contain connection attempts, query errors, and authentication failures. Without exporting these to CloudWatch Logs, the data stays on the cluster and rotates away as storage fills. You lose the ability to set CloudWatch alarms on error patterns, run Logs Insights queries across clusters, or retain logs beyond the instance lifecycle.

CloudWatch export also decouples log retention from cluster operations. If a cluster is deleted or becomes unavailable, logs already shipped to CloudWatch survive. That matters during incident investigations where you need to trace activity on a cluster that no longer exists.

Retrofit consideration

Adding enabled_cloudwatch_logs_exports = ["postgresql"] to an existing aws_rds_cluster triggers an in-place modification. Terraform will show this as a change to the cluster resource; expect a brief latency increase during the modification, but no reboot or failover is required.

Implementation

Choose the approach that matches how you manage Terraform.

If you use terraform-aws-modules/rds-aurora/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.

module "rds_aurora" {
  source  = "terraform-aws-modules/rds-aurora/aws"
  version = ">=10.0.0,<11.0.0"

  create_db_subnet_group = true
  create_security_group  = true
  engine                 = "aurora-mysql"
  engine_version         = "8.0.mysql_aurora.3.08.0"
  instances = {
    one = {
      instance_class = "db.t4g.medium"
    }
  }
  manage_master_user_password = true
  master_username             = "root"
  name                        = "abc123"
  skip_final_snapshot         = true
  subnets                     = ["subnet-12345678", "subnet-12345678"]
  vpc_id                      = "vpc-12345678"
}

Use AWS provider resources directly. See docs for the resources involved: aws_rds_cluster.

resource "aws_rds_cluster" "this" {
  backtrack_window                = 72
  cluster_identifier              = "pofix-abc123"
  db_subnet_group_name            = "example-db-subnet-group"
  enabled_cloudwatch_logs_exports = ["audit", "postgresql"]
  engine                          = "aurora-postgresql"
  engine_version                  = "16.6"
  manage_master_user_password     = true
  master_username                 = "dbadmin"
  skip_final_snapshot             = true
  vpc_security_group_ids          = ["sg-12345678"]
}

What this control checks

Validates that aws_rds_cluster resources with engine = "aurora-postgresql" include "postgresql" in enabled_cloudwatch_logs_exports. A passing configuration sets enabled_cloudwatch_logs_exports = ["postgresql"] on the cluster resource. It fails when enabled_cloudwatch_logs_exports is omitted, set to an empty list, or doesn't contain "postgresql".

Note: the cluster's DB cluster parameter group must configure log_statement, log_min_duration_statement, or other relevant PostgreSQL logging parameters to produce meaningful output. Without those, the export pipeline exists but carries minimal data.

Common pitfalls

  • Parameter group logging not configured

    Enabling enabled_cloudwatch_logs_exports only sets up the export pipeline. If the associated aws_rds_cluster_parameter_group doesn't set parameters like log_statement, log_connections, or log_disconnections, the exported logs contain very little useful data. The control passes, but you gain minimal observability.

  • KMS permissions for encrypted log groups

    Log delivery silently fails if the target CloudWatch log group uses a customer managed KMS key and the key policy doesn't allow CloudWatch Logs in the account and region to use it. Basic delivery to unencrypted log groups doesn't require a custom IAM role, but encrypted groups need kms:Encrypt and kms:GenerateDataKey granted to the CloudWatch Logs service principal. Check the key policy before assuming delivery is working.

  • Confusing Aurora PostgreSQL with Aurora MySQL log types

    Aurora MySQL clusters use log types like audit, error, general, and slowquery. Aurora PostgreSQL only supports postgresql. Specifying MySQL log types on an Aurora PostgreSQL cluster is invalid and will be rejected by Terraform provider validation or the AWS API.

  • CloudWatch log group retention defaults to indefinite

    Use an aws_cloudwatch_log_group resource with retention_in_days to control costs and meet compliance retention requirements. When Aurora auto-creates the /aws/rds/cluster/<name>/postgresql log group, retention is set to Never Expire. If the group already exists, import it into state rather than letting Terraform create a duplicate.

Audit evidence

AWS Config rule evaluations showing compliant status for all Aurora PostgreSQL clusters confirm that EnabledCloudwatchLogsExports includes postgresql. Supporting evidence includes the RDS console cluster configuration page showing CloudWatch log exports enabled, or output from aws rds describe-db-clusters where the EnabledCloudwatchLogsExports array contains "postgresql" for each Aurora PostgreSQL cluster.

CloudWatch Logs should show active log groups following the /aws/rds/cluster/<cluster-name>/postgresql naming pattern with recent log streams. Retention policies on these log groups show that logs are kept for the required period. If a SIEM integration exists, evidence of log ingestion from these CloudWatch log groups is worth including in the audit package.

Framework-specific interpretation

Tool mappings

Use these identifiers to cross-reference this control across tools, reports, and evidence.

  • Compliance.tf Control: rds_db_cluster_aurora_postgres_logging_enabled

  • AWS Config Managed Rule: RDS_AURORA_POSTGRESQL_LOGS_TO_CLOUDWATCH

  • Checkov Checks: CKV2_AWS_27, CKV_AWS_324

  • Powerpipe Control: aws_compliance.control.rds_db_cluster_aurora_postgres_logging_enabled

  • Prowler Check: rds_cluster_integration_cloudwatch_logs

  • AWS Security Hub Control: RDS.37

Last reviewed: 2026-03-09