Terraform AWS RDS Cluster Deployment and Multi-Region Failover Architectures

Building production grade Amazon RDS clusters with Terraform requires precise handling of cluster level attributes, instance placement, encryption, networking, and cross region replication. The awsrdscluster resource defines attributes applied to the entire cluster of RDS Cluster Instances and is the foundation for creating and using Amazon Aurora, a MySQL compatible database engine. For more information on Amazon Aurora, see Aurora on Amazon RDS in the Amazon RDS User Guide. For information on the difference between the available Aurora MySQL engines see Comparison between Aurora MySQL 1 and Aurora MySQL 2 in the Amazon RDS User Guide.

Introduction to RDS Cluster Resources in Terraform

AWS RDS is a managed service that simplifies setting up, operating, and scaling relational databases in the cloud. AWS RDS is a managed relational database service supporting MySQL, PostgreSQL, MariaDB, Oracle, and SQL Server. Using Terraform’s AWS provider, you declare your database configuration as version-controlled code, apply it repeatably with terraform apply, and track state across environments.

Changes to a RDS Cluster can occur when you manually change a parameter, such as port, and are reflected in the next maintenance window. Because of this, Terraform may report a difference in its planning phase because a modification has not yet taken place. You can use the applyimmediately flag to instruct the service to apply the change immediately. Note: using applyimmediately can result in a brief downtime as the server reboots. See the AWS Docs on RDS Maintenance for more information.

Note: All arguments including the username and password will be stored in the raw state as plain-text.

RDS Clusters can be imported using the cluster_identifier, e.g.

bash terraform import aws_rds_cluster.aurora_cluster aurora-prod-cluster

Timeouts configuration options for awsrdscluster are:

Operation Default Purpose
create 120 minutes Used for Cluster creation
update 120 minutes Used for Cluster modifications
delete 120 minutes Used for destroying cluster. This includes any cleanup task during the destroying process

The resource also exposes hostedzoneid as The Route53 Hosted Zone ID of the endpoint.

Provider Configuration for Multi Region Deployments

Deploying a multi-region AWS RDS cluster with an automatic failover setup using Terraform starts with provider configuration. By leveraging AWS RDS and Terraform, we can set up highly available, fault-tolerant database architectures across multiple regions. This ensures that your applications remain online even in the event of regional outages, providing resilience and scalability for critical applications.

Before starting, ensure you have the following:

  • AWS Account: An active AWS account with the necessary permissions
  • AWS CLI: AWS CLI should be configured with your AWS credentials
  • Terraform Installed: Terraform must be installed on your local machine

The provider file tells Terraform which provider you are using.

hcl provider "aws" { region = local.region_0 profile = "<profile-name>" default_tags { tags = { Owner = "primary" Project = "AWS Multi Region rds with active/active setup" Provisioner = "Terraform" } } } provider "aws" { alias = "secondory" region = local.region_1 profile = "<profile-name>" default_tags { tags = { Owner = "secondory" Project = "AWS Multi Region rds with active/active setup" Provisioner = "Terraform" } } }

Terraform data sources allow you to fetch information from your cloud provider and use it within your configuration.

Aurora Global Cluster Module Patterns

A common pattern for primary and secondary Aurora deployments uses the terraform-aws-modules/rds-aurora/aws module with a global cluster identifier.

Primary region configuration:

hcl module "aurora_primary" { source = "terraform-aws-modules/rds-aurora/aws" name = "${local.environment}-${local.region_0}" database_name = aws_rds_global_cluster.this.database_name engine = aws_rds_global_cluster.this.engine engine_version = aws_rds_global_cluster.this.engine_version global_cluster_identifier = aws_rds_global_cluster.this.id instance_class = "db.r6g.large" instances = { for i in range(2) : i => {} } kms_key_id = data.aws_kms_key.rds_0.arn publicly_accessible = true vpc_id = module.vpc_0.vpc_id db_subnet_group_name = module.vpc_0.database_subnet_group_name security_group_rules = { vpc_ingress = { cidr_blocks = concat( module.vpc_0.public_subnets_cidr_blocks, module.vpc_1.public_subnets_cidr_blocks, ) } } master_username = local.database_username master_password = local.database_password skip_final_snapshot = true tags = var.tags }

Secondary region configuration uses a different provider alias and is marked as non-primary:

hcl module "aurora_secondary" { source = "terraform-aws-modules/rds-aurora/aws" providers = { aws = aws.secondory } is_primary_cluster = false name = "${local.environment}-${local.region_1}" engine = aws_rds_global_cluster.this.engine engine_version = aws_rds_global_cluster.this.engine_version global_cluster_identifier = aws_rds_global_cluster.this.id source_region = local.region_0 instance_class = "db.r6g.large" instances = { for i in range(2) : i => {} } kms_key_id = data.aws_kms_key.rds_1.arn publicly_accessible = true vpc_id = module.vpc_1.vpc_id db_subnet_group_name =

Managing Aurora Postgres Clusters with Secrets

A Terraform module for managing a simple Aurora Postgres cluster gets a list of inputs, and creates an Aurora Postgres Cluster, with a configurable number of instances. In addition, it creates a secret on AWS Secrets Manager, to store credentials to access the recently created cluster. This output secret has the root user, password, endpoint and readerendpoint, that represents the read-only endpoint for the Aurora cluster, automatically load-balanced across replicas. You can see more information on awsrds_cluster documentation.

There is a naming convention for the created resources, and the caller is allowed to provide some prefixes and suffixes, that are used to build the names.

Community Modules for RDS Aurora

Terraform module to provision an RDS Aurora cluster for MySQL or Postgres. Supports Amazon Aurora Serverless.

Tip
For a complete example, see examples/complete.

Example PostgreSQL deployment:

hcl module "rds_cluster_aurora_postgres" { source = "cloudposse/rds-cluster/aws" name = "postgres" engine = "aurora-postgresql" cluster_family = "aurora-postgresql9.6" cluster_size = 2 namespace = "eg" stage = "dev" admin_user = "admin1" admin_password = "Test123456789" db_name = "dbname" db_port = 5432 instance_type = "db.r4.large" vpc_id = "vpc-xxxxxxxx" security_groups = ["sg-xxxxxxxx"] subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"] zone_id = "Zxxxxxxxx" }

Serverless example:

hcl module "rds_cluster_aurora_mysql_serverless" { source = "cloudposse/rds-cluster/aws" namespace = "eg" stage = "dev" name = "db" engine = "aurora" engine_mode = "serverless" cluster_family = "aurora5.6" cluster_size = 0 admin_user = "admin1" admin_password = "Test123456789" db_name = "dbname" db_port = 3306 instance_type = "db.t2.small" vpc_id = "vpc-xxxxxxxx" security_groups = ["sg-xxxxxxxx"] subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"] zone_id = "Zxxxxxxxx" enable_http_endpoint = true scaling_configuration = [ { auto_pause = true max_capacity = 256 min_capacity = } ] }

Module parameters commonly include:

Parameter Description
engine aurora-postgresql or aurora-mysql
cluster_family e.g. aurora-postgresql9.6
cluster_size Number of instances including writer and readers
instance_type db.r4.large, db.r6g.large, db.t2.small
db_port 5432 for Postgres, 3306 for MySQL
engine_mode provisioned or serverless

Full Lifecycle Configuration with Terraform

To create an AWS RDS instance with Terraform, define an awsdbinstance resource with your chosen engine, instance class, storage, and credentials. From there, you can layer in VPC placement, backups, monitoring, and Multi-AZ HA as needed.

In this guide, we’ll walk through the full configuration lifecycle step by step:

  • Configuring a basic RDS instance
  • Placing it inside a VPC with subnet groups and security groups
  • Enabling automated backups and maintenance windows
  • Setting up CloudWatch monitoring and Performance Insights
  • Managing parameter groups for engine-level tuning
  • Securing access with IAM and encryption
  • Configuring Multi-AZ replication for high availability
  • Using the AWS RDS Terraform module as an alternative approach

Note: All code examples discussed here are available in this GitHub repository.

Multi Region Active Active Considerations

Multi region RDS architectures require careful handling of global cluster identifiers, KMS keys per region, and security group rules spanning regions. The example primary module uses:

  • engine = awsrdsglobal_cluster.this.engine
  • engineversion = awsrdsglobalcluster.this.engine_version
  • globalclusteridentifier = awsrdsglobal_cluster.this.id
  • kmskeyid = data.awskmskey.rds_0.arn
  • publicly_accessible = true
  • vpcid = module.vpc0.vpc_id
  • dbsubnetgroupname = module.vpc0.databasesubnetgroup_name

Security group ingress concatenates public subnet CIDR blocks from both regions to allow cross region connectivity.

The secondary module mirrors these settings but uses providers = { aws = aws.secondory }, isprimarycluster = false, sourceregion = local.region0, and region specific KMS key and VPC.

Best Practices and Operational Notes

  • Store credentials in AWS Secrets Manager rather than plain state. Modules that create a secret for root user, password, endpoint and reader_endpoint reduce exposure.
  • Pin module versions to avoid unexpected changes. Cloud Posse recommends pinning every module to a specific version.
  • Use default_tags at provider level for ownership and project tracking.
  • Apply immediately with caution due to brief downtime risk during server reboot.
  • Monitor maintenance windows for parameter changes. Terraform planning may report drift until the maintenance window applies changes.
  • Ensure databasename, engine, and engineversion are consistent across primary and secondary in a global cluster.

Conclusion

Terraform provides a declarative path to build highly available AWS RDS clusters with automated failover across regions. Using awsrdscluster resources, Aurora global clusters, and community modules you can define provider aliases for multi region deployments, enforce naming conventions with prefixes and suffixes, and integrate secrets management for credentials. Combining primary and secondary Aurora modules with region specific KMS keys, VPCs, subnet groups, and security rules creates resilient architectures. Operational considerations around apply_immediately, maintenance windows, state storage of plain text credentials, and timeout defaults for create, update, and delete operations remain central to safe production rollouts. Version controlled Terraform code with proper module pinning, tagging, and data sources for cloud information enables repeatable, auditable RDS cluster lifecycles.

Sources

  1. https://dev.to/aws-builders/terraform-deploying-multi-region-aws-rds-cluster-with-failover-setup-using-terraform-4ahg
  2. https://github.com/madelabs/terraform-aws-rds-cluster
  3. https://docs.w3cub.com/terraform/providers/aws/r/rds_cluster.html
  4. https://github.com/cloudposse/terraform-aws-rds-cluster
  5. https://spacelift.io/blog/terraform-aws-rds

Related Posts