Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Despliega un clúster de Amazon Aurora MySQL con Terraform

By TylerAug 5, 20246 min read

Esta página también está disponible en English, Deutsch, Français, Italiano, 日本語 y Português.

Desplegar bases de datos en la nube exige tener muy en cuenta la seguridad, la escalabilidad y la facilidad de gestión. Una mala configuración o un setup poco óptimo puede traducirse en grandes dolores de cabeza técnicos, deuda técnica y, en el peor de los casos, un impacto serio al negocio si se produce una caída o si la base de datos no rinde. Amazon Aurora MySQL ofrece un servicio de base de datos relacional altamente escalable y seguro.

En este blog vemos cómo automatizar el despliegue de un clúster de Amazon Aurora MySQL con Terraform, con foco en armar una configuración de alta disponibilidad con varias instancias de lectura para escalar las consultas.

Requisitos previos:

  • Una cuenta de AWS
  • Terraform instalado en tu máquina
  • Conocimientos de los servicios de AWS y de Terraform
  • Código de Terraform desde el repositorio de Github

Estructura del proyecto: nuestro proyecto en Terraform se organiza en módulos para mayor claridad y reutilización. Los módulos clave son:

  • Módulo KMS: gestiona las claves de cifrado de la base de datos.
  • Módulo del clúster Aurora: se encarga del despliegue y la configuración del clúster Aurora MySQL.

Resumen de la estructura modular de directorios

Esta estructura de directorios está pensada para organizar y gestionar el código de Terraform de forma eficiente al desplegar un clúster de Amazon Aurora MySQL con cifrado gestionado por AWS KMS.

Directorio raíz

Incluye main.tf, providers.tf, terraform.tfvars, variables.tf y outputs.tf.

  • main.tf: contiene la configuración principal donde se invocan los módulos.
  • providers.tf: define la configuración del proveedor y los requisitos de versión.
  • variables.tf: declara las variables que se usan en las distintas configuraciones.
  • terraform.tfvars: establece valores que sobrescriben las variables definidas en otros archivos.
  • outputs.tf: define las salidas de la configuración de Terraform.

Directorio de módulos

Contiene un subdirectorio por cada módulo del proyecto.

Módulo KMS: se encarga de crear y gestionar las claves de AWS KMS para cifrar los datos en reposo.

  • main.tf: contiene los recursos para crear las claves KMS.
  • variables.tf: define las variables de entrada propias de KMS.
  • outputs.tf: expone los atributos de salida de los recursos KMS.

Módulo del clúster Aurora: gestiona el despliegue del clúster Aurora MySQL.

  • main.tf: configura el clúster Aurora MySQL y los recursos asociados.
  • variables.tf: lista las variables de entrada propias del clúster Aurora MySQL.
  • outputs.tf: expone atributos como el endpoint de la base de datos.

Con esta estructura se logra un código limpio y ordenado, y se mejora la reutilización y el mantenimiento del código de Terraform, lo que facilita administrar los recursos en la nube de forma efectiva.

1\. Configuración del módulo KMS

El cifrado en reposo es clave para proteger los datos. El clúster Aurora MySQL usa AWS KMS para la gestión de claves; en concreto, AWS Customer Managed Key (CMK), donde tú creas, administras y eres dueño de la clave que cifra tu clúster Aurora. Gestionar tu propia clave KMS para el cifrado del clúster Aurora ofrece varias ventajas frente a usar una clave KMS gestionada por AWS: las CMK habilitan políticas de control de acceso granulares, e incluyen la posibilidad de definir quién puede usarlas y administrarlas; cada uso de una CMK queda registrado en CloudTrail con fines de auditoría —algo crucial para el cumplimiento normativo—, además del control geográfico, que te permite restringir el uso de la clave a regiones específicas de AWS. Los cargos por usar CMK —facturados por almacenamiento y uso de API— también son más predecibles y transparentes, lo que ayuda a presupuestar y gestionar costos en comparación con las claves gestionadas por AWS.

El módulo KMS se ocupa de crear y administrar estas claves; el archivo outputs.tf del módulo expone el nombre de la clave KMS que utilizará el módulo de Aurora.

# KMS Module - variables.tf
variable "rds" {
  description = "Enable customer managed KMS key for RDS"
  default     = true
  type        = bool
}
# KMS Module - main.tf
resource "aws_kms_key" "rds" {
  description             = "KMS key for RDS"
  enable_key_rotation     = true
  deletion_window_in_days = 30
}

Explicación:

  • Rotación de claves: la rotación automática refuerza la seguridad al cambiar de forma periódica la clave de cifrado subyacente.
  • Ventana de eliminación: indica el plazo previo a que una clave eliminada se destruya de forma irreversible, lo que permite recuperarla si fuera necesario.

2\. Configuración del módulo del clúster Aurora

El módulo del clúster Aurora es el corazón de nuestro despliegue. Configura la base de datos con parámetros de rendimiento y disponibilidad. Permite ajustar opciones que van desde el motor de base de datos a desplegar hasta la VPC y los Security Groups existentes con los que va a operar, e incluye opciones como evitar la eliminación accidental del clúster mediante Terraform —a menos que se quite explícitamente la cláusula prevent_destroy = true del bloque lifecycle del módulo:

# Aurora Cluster Module - variables.tf
variable "read_replica_count" {
  description = "Number of Read Replicas in addition to Writer instance"
  type        = number
}
# Aurora MySQL Cluster config
resource "aws_rds_cluster" "aurora_mysql_cluster" {
  cluster_identifier                    = var.name
  engine                                = var.engine
  engine_mode                           = var.engine_mode
  engine_version                        = var.aurora_mysql_cluster_engine_version
  database_name                         = var.database_name

  master_username                       = var.aurora_mysql_cluster_master_username

  # Create and store password in Secrets Manager
  manage_master_user_password           = true
  final_snapshot_identifier             = "${var.name}-snapshot"
  skip_final_snapshot                   = var.skip_final_snapshot
  deletion_protection                   = var.deletion_protection
  backup_retention_period               = var.backup_retention_period
  preferred_backup_window               = var.backup_window
  preferred_maintenance_window          = var.maintenance_window
  port                                  = var.port
  db_subnet_group_name                  = aws_db_subnet_group.db_subnet_group.name
  vpc_security_group_ids                = concat(var.security_group_ids, [aws_security_group.aurora_mysql_sg.id])

  apply_immediately                     = true
  iam_database_authentication_enabled   = false
  copy_tags_to_snapshot                 = true
  storage_encrypted                     = true
  kms_key_id                            = var.kms_key_id

  db_cluster_parameter_group_name       = aws_rds_cluster_parameter_group.cluster_param_group.name

  enabled_cloudwatch_logs_exports = var.engine_mode == "serverless" ? [] : var.enabled_cloudwatch_logs_exports

  tags = merge(var.tags, { "Name" = var.name })

  lifecycle {
    ignore_changes = [ engine_version, scaling_configuration, engine_mode ]
    prevent_destroy = true
  }
}

# Aurora MySQL Instances within Cluster - one Writer and "read_replica_count" Readers
resource "aws_rds_cluster_instance" "aurora_mysql_instance" {
  count                             = var.engine_mode == "serverless" ? 0 : (1 + var.read_replica_count)
  identifier                        = "${var.name}-${count.index}"
  cluster_identifier                = aws_rds_cluster.aurora_mysql_cluster.id
  engine                            = var.engine
  engine_version                    = var.aurora_mysql_cluster_engine_version
  instance_class                    = var.instance_type

  db_subnet_group_name              = aws_db_subnet_group.db_subnet_group.name
  db_parameter_group_name           = aws_db_parameter_group.db_param_group.name

  monitoring_role_arn               = var.create_monitoring_role && var.monitoring_interval > 0 ? aws_iam_role.rds_enhanced_monitoring[0].arn : null
  monitoring_interval               = var.create_monitoring_role && var.monitoring_interval > 0 ? var.monitoring_interval : null
  auto_minor_version_upgrade        = true

  performance_insights_enabled      = true

  tags                              = var.tags

  lifecycle {
    ignore_changes = [ engine_version ]
  }
}

Parámetros de configuración importantes (defínelos en terraform.tfvars):

  • Identificador del clúster: identificador único del clúster Aurora; clave para su gestión.
  • Configuración del motor: define el motor de base de datos y la versión, garantizando compatibilidad y disponibilidad de funciones. Puede ser Aurora MySQL 5.7.x o MySQL 8.0.x, aunque hoy se recomienda usar 8.0.x, ya que AWS dejó de mantener la 5.7.x y solo ofrece soporte extendido (de pago).
  • Cantidad de instancias: controla el número de instancias de lectura que se crean junto con la de escritura, lo que facilita el escalado de lectura.
  • Seguridad y red: asocia el clúster a una configuración específica de VPC y Security Group, garantizando que opere dentro de un entorno de red seguro y aislado. Vas a usar los IDs de subred y demás valores asociados de una VPC existente donde quieras colocar tu nuevo clúster Aurora MySQL.
  • Gestión de credenciales: se apoya en Secrets Manager para almacenar el usuario y la contraseña de la base de datos, siguiendo las mejores prácticas para el manejo de credenciales.

3\. Salidas y gestión

Las salidas son fundamentales para obtener los datos de conexión y administrar el clúster después del despliegue, así como para pasar valores en tiempo de ejecución entre módulos cuando haga falta.

# Outputs - outputs.tf
output "aurora_cluster_endpoint" {
  description = "The endpoint at which the Aurora cluster is accessible"
  value       = aws_rds_cluster.aurora.endpoint
}
# Outputs - outputs.tf
output "aurora_cluster_reader_endpoint" {
  description = "The reader endpoint for the Aurora cluster"
  value       = aws_rds_cluster.aurora.reader_endpoint
}

4\. Conclusión

Usar Terraform para desplegar clústeres de Amazon Aurora MySQL simplifica el proceso y asegura consistencia y repetibilidad entre entornos. Al apoyarte en módulos para las claves de cifrado de cliente de KMS y para la configuración fina del clúster Aurora, el setup se mantiene modular y fácil de ajustar. Esta solución aprovecha las nuevas capacidades integradas de AWS para crear y almacenar tu contraseña maestra de MySQL de forma nativa en Secrets Manager. Este enfoque se alinea con las mejores prácticas de arquitectura cloud, incluidas la seguridad, la escalabilidad y la recuperación ante desastres. Ya sea para escalar instancias de lectura ante más carga o para gestionar claves de cifrado de forma segura, Terraform ofrece una solución sólida para administrar configuraciones de clústeres Aurora MySQL en AWS, desde las más simples hasta las más complejas, y para todo tipo de casos de uso.

¿Te quedan dudas sobre cómo aplicar estas recomendaciones para desplegar un clúster Aurora MySQL ajustado a tu caso de uso en tu entorno de AWS con Terraform?

Contáctanos en DoiT International. Contamos exclusivamente con talento sénior de Engineering y nos especializamos en consultoría cloud avanzada para diseño de arquitectura, asesoría en debugging y servicios de consultoría.