RDS DB instances should have iam authentication enabled
IAM database authentication replaces long-lived database passwords with short-lived tokens generated via the rds-db:connect IAM action. Tokens expire after 15 minutes, which eliminates credentials sitting in config files, environment variables, or secrets managers with stale rotation schedules. Network traffic to the database is also forced over SSL when IAM auth is used.
Password-based authentication creates ongoing operational burden around rotation and a real security risk when credentials leak. IAM auth ties database access to your existing IAM policies, and every token request lands in CloudTrail tied to a specific principal.
Retrofit consideration
Enabling IAM authentication on an existing instance requires no downtime, but every application connecting to the database must be updated to generate IAM auth tokens via aws rds generate-db-auth-token instead of using static passwords. This is a code-level change across all consumers.
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 = "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 = "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 = "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 = "iso270012013.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 = "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"]
iam_database_authentication_enabled = true
}
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"
iam_database_authentication_enabled = true
}
What this control checks
This control validates that the aws_db_instance resource has iam_database_authentication_enabled set to true. When the argument is omitted or set to false, the control fails. Supported engines include MySQL, PostgreSQL, and Aurora-compatible instances created outside of aws_rds_cluster. For Aurora clusters managed via aws_rds_cluster, the same argument exists on that resource, but this control targets standalone DB instances only. No additional Terraform resources are required to pass. IAM policies granting rds-db:connect to the appropriate principals must be created separately for authentication to work end-to-end.
Common pitfalls
Unsupported engine versions silently ignore the flag
terraform applywill fail with an API error if you setiam_database_authentication_enabled = trueon an engine version that doesn't support it (MySQL pre-5.6.34, PostgreSQL pre-9.5.15). This won't surface duringterraform plan. Check the AWS docs for your exact engine and version before enabling.Max connections limit with IAM auth
200 new IAM-authenticated connections per second is the AWS-imposed limit per instance. Workloads that open and close connections at high frequency without pooling will hit this ceiling. There is nothing to configure in Terraform to raise it.
Token generation requires network and IAM permissions
Applications must call
aws rds generate-db-auth-token(or the SDK equivalent) before each connection. The IAM principal needsrds-db:connectwith a resource ARN in the formarn:aws:rds-db:REGION:ACCOUNT:dbuser:DBI_RESOURCE_ID/DB_USER. The DBI resource ID is not the instance ID; it comes fromdbi-resource-idindescribe-db-instancesoutput. Get that ARN wrong and authentication failures look identical to bad database credentials.Read replicas need independent configuration
Read replicas don't inherit this setting from the source instance. Set
iam_database_authentication_enabled = trueexplicitly on eachaws_db_instancethat usesreplicate_source_db.
Audit evidence
AWS Config rule rds-instance-iam-authentication-enabled showing all instances COMPLIANT is the primary evidence artifact. The RDS console (instance configuration tab, "IAM DB authentication: Enabled") or aws rds describe-db-instances output with IAMDatabaseAuthenticationEnabled: true works as supporting documentation.
CloudTrail logs with rds-db:connect calls confirm applications are actually using IAM auth, not just that it's enabled. IAM policies on application roles should show rds-db:connect scoped to specific database resource ARNs.
Framework-specific interpretation
SOC 2: CC6.1 and CC6.3 want logical access controls bound to authenticated identities, not shared credentials. IAM auth replaces static database passwords with 15-minute tokens tied to IAM principals, satisfying both the unique identification and session management expectations. CloudTrail records of token requests also feed into CC7.2 monitoring.
PCI DSS v4.0: Requirement 8 mandates unique IDs and strong authentication for all access to system components in scope for cardholder data. IAM database authentication assigns every connection attempt to a specific IAM principal and forces SSL on the connection, addressing both the identification and in-transit protection requirements.
HIPAA Omnibus Rule 2013: HIPAA's unique user identification requirement under 45 CFR 164.312(a)(2)(i) applies directly: shared database passwords fail the test, IAM auth passes it. Every token request lands in CloudTrail tied to a specific IAM principal, which also covers the audit trail obligation under 164.312(b).
Related controls
Tool mappings
Use these identifiers to cross-reference this control across tools, reports, and evidence.
Compliance.tf Control:
rds_db_instance_iam_authentication_enabledAWS Config Managed Rule:
RDS_INSTANCE_IAM_AUTHENTICATION_ENABLEDCheckov Check:
CKV_AWS_161Powerpipe Control:
aws_compliance.control.rds_db_instance_iam_authentication_enabledProwler Checks:
rds_cluster_iam_authentication_enabled,rds_instance_iam_authentication_enabledAWS Security Hub Control:
RDS.10KICS Query:
88fd05e0-ac0e-43d2-ba6d-fc0ba60ae1a6Trivy Check:
AWS-0176
Last reviewed: 2026-03-09