Skip to content

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 apply will fail with an API error if you set iam_database_authentication_enabled = true on an engine version that doesn't support it (MySQL pre-5.6.34, PostgreSQL pre-9.5.15). This won't surface during terraform 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 needs rds-db:connect with a resource ARN in the form arn:aws:rds-db:REGION:ACCOUNT:dbuser:DBI_RESOURCE_ID/DB_USER. The DBI resource ID is not the instance ID; it comes from dbi-resource-id in describe-db-instances output. 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 = true explicitly on each aws_db_instance that uses replicate_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).

Tool mappings

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

  • Compliance.tf Control: rds_db_instance_iam_authentication_enabled

  • AWS Config Managed Rule: RDS_INSTANCE_IAM_AUTHENTICATION_ENABLED

  • Checkov Check: CKV_AWS_161

  • Powerpipe Control: aws_compliance.control.rds_db_instance_iam_authentication_enabled

  • Prowler Checks: rds_cluster_iam_authentication_enabled, rds_instance_iam_authentication_enabled

  • AWS Security Hub Control: RDS.10

  • KICS Query: 88fd05e0-ac0e-43d2-ba6d-fc0ba60ae1a6

  • Trivy Check: AWS-0176

Last reviewed: 2026-03-09