RDS DB instances should have logging enabled
Database logs capture authentication failures, slow queries, configuration changes, and runtime errors. Without exporting these to CloudWatch, you lose centralized visibility and the ability to trigger alarms on anomalous activity. Incident responders depend on these logs to reconstruct timelines during a breach.
Retaining logs only on the DB instance is risky: they rotate on a fixed schedule and are gone entirely if the instance is deleted. CloudWatch export gives you durable, searchable log streams with configurable retention and alerting.
Retrofit consideration
Enabling log exports on a running instance triggers a brief configuration change with no downtime. That said, enabling verbose log types like general on a high-traffic MySQL instance can meaningfully increase I/O and CloudWatch Logs ingestion costs. Test in a non-production environment first.
Implementation
Choose the approach that matches how you manage Terraform.
Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.
module "rds" {
source = "soc2.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "pcidss.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "hipaa.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "gdpr.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "nist80053.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "fedrampmoderate.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "cisv80ig1.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "nist800171.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "cisacyberessentials.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "nydfs23.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "ffiec.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "acscessentialeight.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "cfrpart11.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "rbicybersecurity.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "rbiitfnbfc.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "fedramplow.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "hipaasecurity2003.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "nistcsfv11.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "nist80053rev4.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
module "rds" {
source = "pcidssv321.compliance.tf/terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
If you use terraform-aws-modules/rds/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" {
source = "terraform-aws-modules/rds/aws"
version = ">=7.0.0"
allocated_storage = 20
db_name = "myapp"
db_subnet_group_name = "example-db-subnet-group"
engine = "mysql"
engine_version = "8.0.41"
family = "mysql8.0"
identifier = "abc123"
instance_class = "db.t3.micro"
major_engine_version = "8.0"
password_wo = "change-me-in-production"
skip_final_snapshot = true
username = "dbadmin"
vpc_security_group_ids = ["sg-12345678"]
}
Use AWS provider resources directly. See docs for the resources involved: aws_db_instance.
resource "aws_db_instance" "this" {
allocated_storage = 20
enabled_cloudwatch_logs_exports = ["general", "slowquery"]
engine = "mysql"
identifier = "pofix-abc123"
instance_class = "db.t3.micro"
monitoring_interval = 60
monitoring_role_arn = "arn:aws:iam::123456789012:role/example-role"
password = "ChangeMe123!"
skip_final_snapshot = true
username = "dbadmin"
}
What this control checks
In the aws_db_instance resource, enabled_cloudwatch_logs_exports must be set to a non-empty list of log type strings. Valid values are engine-specific: MySQL and MariaDB support audit, error, general, and slowquery; PostgreSQL supports postgresql and upgrade; Oracle supports alert, audit, listener, and trace; SQL Server supports agent and error. It fails when enabled_cloudwatch_logs_exports is omitted entirely or set to []. At least one log type is sufficient; all available types are not required.
Note that aws_db_parameter_group or aws_rds_cluster_parameter_group may also need engine-level parameters set (for example, log_output = FILE for MySQL general and slow query logs) for the export to produce actual log data in CloudWatch.
Common pitfalls
Engine-specific log types cause plan errors
PostgreSQL doesn't support the
auditlog type, soenabled_cloudwatch_logs_exports = ["audit"]on a PostgreSQL instance fails at apply time. Match log type strings to the engine. Use conditional logic or engine-specific variable maps in your module to avoid hardcoding values that only work for one engine family.Parameter group must enable the log source
MySQL's
generalandslowquerylog exports require matching parameter group settings:general_log = 1orslow_query_log = 1, andlog_output = FILE. Skip those and the export is configured but CloudWatch receives no data, which creates a false sense of compliance. The control passes; the logs don't flow.IAM service-linked role permissions
RDS needs the
AWSServiceRoleForRDSservice-linked role to publish logs to CloudWatch. In accounts where SCPs restrict service-linked role creation, log exports silently fail. Verify the role exists viaaws iam get-role --role-name AWSServiceRoleForRDSbefore assuming logging is working.CloudWatch Logs costs on verbose log types
generallogging on a busy MySQL instance can generate gigabytes of log data per day. CloudWatch Logs ingestion pricing varies by region, log class, and volume tier. Start witherrorandslowquery; addgeneralonly when you actually need it for audit or active debugging.
Audit evidence
Auditors expect AWS Config rule evaluation results for rds-logging-enabled showing all DB instances as COMPLIANT. Supporting evidence includes CloudWatch Logs console screenshots of active log groups under /aws/rds/instance/<instance-id>/ with recent log stream activity, confirming logs are actually flowing. CloudTrail events for ModifyDBInstance calls that include CloudwatchLogsExportConfiguration show when logging was enabled and by whom.
For ongoing assurance, a CloudWatch Logs Insights query across RDS log groups showing data within the retention window demonstrates that logs are not just configured but actively collected.
Framework-specific interpretation
SOC 2: CC7.2 expects monitoring of system components to detect anomalies. Database log exports are the raw telemetry for detective controls here, covering both the Security and Availability trust service criteria.
PCI DSS v4.0: Requirement 10.2 mandates logging of access to cardholder data environment components. RDS log exports can support this, though what gets captured depends on which log types you enable and how the engine is configured. Authentication events and errors are covered; query-level detail requires additional log types.
HIPAA Omnibus Rule 2013: The HIPAA Omnibus Rule at 45 CFR 164.312(b) calls for audit controls on systems that store or process ePHI. Exporting RDS logs to CloudWatch is one approach to capturing database access patterns and detecting unauthorized queries against protected health information, though logging alone doesn't cover the full audit control requirement.
GDPR: GDPR Article 32 asks for technical measures that ensure the security of processing. Database logs provide the audit trail for detecting unauthorized access to personal data and support the accountability obligation under Article 5(2).
NIST SP 800-53 Rev 5: AU-2, AU-3, and AU-6 together cover event logging, record content, and audit review. CloudWatch Logs export satisfies the durability and centralization expectations and makes records available for automated alerting, which AU-6 expects.
FedRAMP Moderate Baseline Rev 4: AU-2 and AU-3 require generating and retaining audit records for defined events, including authentication attempts and query activity. At the Moderate baseline, exporting RDS logs to CloudWatch is one way to satisfy this for database-level activity.
Related controls
Tool mappings
Use these identifiers to cross-reference this control across tools, reports, and evidence.
Compliance.tf Control:
rds_db_instance_logging_enabledAWS Config Managed Rule:
RDS_LOGGING_ENABLEDCheckov Check:
CKV_AWS_129Powerpipe Control:
aws_compliance.control.rds_db_instance_logging_enabledProwler Check:
rds_instance_integration_cloudwatch_logsAWS Security Hub Controls:
RDS.36,RDS.40,RDS.42,RDS.9KICS Query:
8d7f7b8c-6c7c-40f8-baa6-62006c6c7b56
Last reviewed: 2026-03-09