Skip to content

codeforamerica/tofu-modules-aws-serverless-database

Repository files navigation

AWS Serverless Database Module

Main Checks GitHub Release

This module launches an Aurora Serverless v2 database cluster. Aurora serverless clusters measure capacity in ACUs (Aurora Capacity Units); each unit is approximately 2 GB of memory with corresponding CPU and networking.

Usage

Add this module to your main.tf (or appropriate) file and configure the inputs to match your desired configuration. For example:

module "database" {
  source = "github.com/codeforamerica/tofu-modules-aws-serverless-database?ref=1.7.0"

  project     = "my-project"
  environment = "dev"
  service     = "web"

  logging_key_arn = module.logging.kms_key_arn
  secrets_key_arn = module.secrets.kms_key_arn
  vpc_id          = module.vpc.vpc_id
  subnets         = module.vpc.private_subnets
  ingress_cidrs   = module.vpc.private_subnets_cidr_blocks

  min_capacity = 2
  max_capacity = 32
}

Make sure you re-run tofu init after adding the module to your configuration.

tofu init
tofu plan

To update the source for this module, pass -upgrade to tofu init:

tofu init -upgrade

Role name limitations

When creating the database cluster, a role will be created for database monitoring. A random string will be appended to the role name to ensure it is unique and allow replacement without a conflict. However, this means the rest of the role name must be 38 characters or fewer.

The role name is constructed as follows (before the suffix is added):

role_name = "${project}-${environment}-[${service}-]-db-mon"

If this combined string is longer than 38 characters, the module will fail to create the database cluster. You can help to reduce the length of the role by specifying short names for your project and (optionally) service using the project_short and service_short input variables, respectively.

Inputs

Name Description Type Default Required
logging_key_arn ARN of the KMS key for logging. string n/a yes
ingress_cidrs List of CIDR blocks to allow ingress. This is typically your private subnets. list(string) n/a yes
project Name of the project. string n/a yes
secrets_key_arn ARN of the KMS key for secrets. This will be used to encrypt database credentials. string n/a yes
subnets List of subnet ids the database instances may be placed in. list(string) n/a yes
vpc_id Id of the VPC to launch the database cluster into. string n/a yes
apply_immediately Whether to apply changes immediately rather than during the next maintenance window. WARNING: This may result in a restart of the cluster! bool false no
automatic_backup_retention_period Number of days to retain automatic backups, between 1 and 35. number 31 no
backup_namespace Namespace for backups, prefixed to vault names to produce globally unique names. string cfa no
backup_replica_region Region to use for cross-region backup replication. If not specified, no replica will be created. If specified, the module will create a backup vault in the specified region and configure the backup schedules to replicate to the replica vault. string null no
backup_retention_period Deprecated: Use automatic_backup_retention_period instead. number null no
backup_schedules Backup schedules to create for the database cluster. list(object) list(object) no
cluster_parameters Parameters to be set on the database cluster. list(object) [] no
configure_aws_backup Whether to configure AWS Backup with the defined backup schedules. bool false no
db_users Map of database users to create on the cluster. The map key becomes the database username. Requires enable_data_api = true and the AWS CLI must be installed on the OpenTofu runner. map(object) {} no
enable_data_api Whether to enable the Data API for the database cluster. bool false no
engine Database engine to use for the cluster. Valid values are "mysql" and "postgresql". string "postgresql" no
engine_version Version of the database engine to use. If left empty, the latest version will be used. Changing this value will result in downtime. string null no
environment Environment for the project. string "dev" no
force_delete Force deletion of resources. If changing to true, be sure to apply before destroying. bool false no
iam_authentication Whether to enable IAM authentication for the database cluster. bool true no
[iam_db_users] Map of IAM database users to create on the cluster. The map key becomes the database username. Requires iam_authentication = true and the AWS CLI must be installed on the OpenTofu runner. map(object) {} no
instances Number of instances to create in the database cluster. number 2 no
key_recovery_period Recovery period for deleted KMS keys in days. Must be between 7 and 30. number 30 no
min_capacity Minimum capacity for the serverless cluster in ACUs. number 2 no
max_capacity Maximum capacity for the serverless cluster in ACUs. number 10 no
password_rotation_frequency Number of days between automatic password rotations for the root user Set to 0 to disable automatic rotation. number 30 no
project_short Short name for the project. Used in resource names with character limits. Defaults to project. string "" no
service Optional service that these resources are supporting. Example: "api", "web", "worker". Used in resource names to differentiate from other services. string "" no
service_short Short name for the service. Used in resource names with character limits. Defaults to the same value as service. string "" no
security_group_rules Security group rules to control cluster ingress and egress. map(object) {} no
skip_final_snapshot Whether to skip the final snapshot when destroying the database cluster. bool false no
snapshot_identifier Optional name or ARN of the snapshot to restore the cluster from. Only applicable on create. bool false no
tags Optional tags to be applied to all resources. map(string) {} no

backup_schedules

You can enable backups using AWS Backup by setting configure_aws_backup to true. When enabled, the module will create a backup vault in the current region.

module "database" {
  source = "github.com/codeforamerica/tofu-modules-aws-serverless-database?ref=1.7.0"

  project     = "my-project"
  environment = "dev"
  service     = "web"

  logging_key_arn = module.logging.kms_key_arn
  secrets_key_arn = module.secrets.kms_key_arn
  vpc_id          = module.vpc.vpc_id
  subnets         = module.vpc.private_subnets
  ingress_cidrs   = module.vpc.private_subnets_cidr_blocks

  configure_aws_backup = true
}

This will configure AWS Backup to use the following default schedule:

Note

Cron schedules are evaluated as UTC. With the defaults below, backups are scheduled for 9am UTC/4am EST/1am PST.

- name: daily
  schedule: cron(0 9 ? * * *)
  start_window: 320
  completion_window: 1440
  retention: 31
- name: monthly
  schedule: cron(0 9 1 * ? *)
  start_window: 320
  completion_window: 1440
  retention: 395
- name: yearly
  schedule: cron(0 9 1 1 ? *)
  start_window: 320
  completion_window: 1440
  retention: 1095

You can override the default schedule by setting backup_schedules:

backup_schedules = [{
    name = "daily"
    schedule = "cron(0 4 ? * * *)"
    start_window = 320
    completion_window = 1440
    retention = 8
  }, {
    name = "weekly"
    schedule = "cron(0 4 * * * 0)"
    start_window = 320
    completion_window = 1440
    retention = 53
  }]

Additionally, you can configure replication of backups to another region by setting backup_replica_region. If left empty, no replicas will be created.

backup_replica_region = "us-west-2"
Name Description Type Default Required
name Name of schedule. string n/a yes
schedule The cron schedule on which to create the backup, evaluated as UTC. string n/a yes
retention Number of days to retain the backup before it is deleted. number n/a yes
completion_window Number of minutes after a backup has successfully started in which it must complete before being cancelled. number 1440 no
start_window Number of minutes after the scheduled time in which the backup must be successfully started before being cancelled. number 320 no

cluster_parameters

You can override the default cluster parameters by passing a list of parameters and their values. Some parameters can be applied immediately, while others will require a restart of the cluster. See the documentation for the appropriate database engine to determine which parameters can be applied immediately.

Note

If a parameter requires a restart, you must set the apply_method to "pending-reboot".

cluster_parameters = [
  {
    name  = "log_statement"
    value = "all"
  },
  {
    name = "shared_preload_libraries"
    value = "pg_stat_statements,pglogical"
    apply_method = "pending-reboot"
  }
]
Name Description Type Default Required
name Name of the parameter to set. string n/a yes
value Value to set the parameter to. string n/a yes
apply_method How to apply the parameter. Can be immediate or pending-reboot. string "immediate" no

db_users

Warning

Creation of standard database users is limited to read-only users. We highly recommend using [iam_db_users][iam_db_users] instead for enhanced security. If you must rely on a user with a password, ensure that password is kept secure and rotated regularly.

The same dependency on the RDS Data API exists for db_users as iam_db_users

Although discouraged, it is occasionally necessary to create a read-only database user with a password. This option gives you the ability to create read-only database users with access to specific databases.

Provide a map of users, the keys of which will become the username. For example:

Caution

Database usernames should be treated as sensitive values and should not be committed directly to your repository.

Usernames are presented as strings here for demonstration purposes only.

enable_data_api = true
db_users    = {
  "myreadonlyuser" = {
    databases = ["my_stats"]
  }
}

This will create a new database user with SELECT access to the specified database(s). The user will be assigned a randomly generated password, and their credentials will be stored in AWS Secrets Manager. The ARN of the secret for each user is available in the db_user_secret_arns output.

Name Description Type Default Required
databases List of databases to grant the user access to. list(string) n/a yes
privileges Privileges to grant on the databases for the user. The only valid value is "readonly". string "readonly" no

iam_db_users

You can optionally create database users to be used for IAM based authentication. This allows your application(s) to connect to the database without managing a static password that needs to be rotated regularly.

Note

To avoid needing to connect directly to the database, these users are managed using RDS Data API. As a result, enable_data_api must be set to true for this to succeed, and the OpenTofu runner must have the AWS CLI installed.

Provide a map of users, the keys of which will become the username. For example:

Caution

Database usernames should be treated as sensitive values and should not be committed directly to your repository.

Usernames are presented as strings here for demonstration purposes only.

enable_data_api = true
iam_db_users    = {
  "myapp" = {
    privileges = "all"
  },
  "myapp_ro" = {
    databases  = ["myapp", "myapp_queue"]
    privileges = "readonly"
  }
}

To grant your resources the privileges to connect to the database as the user, an IAM policy is created for each user, and mapped to the username in the iam_db_user_policy_arns output. You can attach this policy to one or more IAM roles which are attached to your resources.

Tip

You can also pass the policy ARN to another module that's responsible for configuring your roles, such as our aws_fargate_service module.

Name Description Type Default Required
databases List of databases to grant the user access to. Leave empty to grant access to all databases. list(string) [] no
privileges Privileges to grant on the databases for the user. Valid values are "all" and "readonly". string "all" no

security_group_rules

Security group rules control network access to the cluster. By default, the cluster will not be available on the network can only be accessed via the Data API. You can use security_group_rules to define rules to ingress and/or egress traffic.

Tip

If you just want to allow access to the database from one or more CIDR blocks, you can use the ingress_cidrs input variable for convenience.

security_group_rules = {
  vpc_peer = {
    description = "Allow access from VPC peer"
    type        = "ingress"
    protocol    = "tcp"
    from_port   = 5432
    to_port     = 5432
    cidr_blocks = ["10.123.0.0/16"]
  }
  replication = {
    description = "Allow egress for replication"
    type        = "egress"
    cidr_blocks = ["10.123.0.0/16"]
  }
}

Caution

Be careful when using egress rules. In most cases, this will not be necessary and can present a security risk. If you do need to use egress rules, be sure to restrict the narrowest set of destinations that are necessary.

Leaving your egress rules too broad can allow your data to be exfiltrated by a bad actor.

Name Description Type Default Required
description Description of the rule. string "Managed by OpenTofu" no
type Type of rule. Can be ingress or egress. string "ingress" no
protocol Protocol to use. Valid values: icmp, icmpv6, tcp, udp, or all. string "tcp" no
from_port Starting port for the rule. Defaults to the port for the database engine. number 5432 or 3306 no
to_port Ending port for the rule. Defaults to the port for the database engine. number 5432 or 3306 no
cidr_blocks List of CIDR blocks to allow access. list(string) [] no
ipv6_cidr_blocks List of IPv6 CIDR blocks to allow access. list(string) [] no
prefix_list_ids List of prefix list IDs to allow access. list(string) [] no
source_security_group_id ID of another security group to allow access. string null no

Outputs

Name Description Type
backup_key_arn ARN of the primary KMS key for backups, if created. string
backup_vault_arn ARN of the backup vault, if created. string
backup_vault_replica_arn ARN of the backup vault replica, if created. string
cluster_endpoint DNS endpoint to connect to the database cluster. string
cluster_id ID of the RDS database cluster. string
cluster_resource_id Resource ID of the RDS database cluster. string
db_user_secret_arns Map of database username to the ARN of the Secrets Manager secret containing their credentials. map(string)
iam_db_user_policy_arns Map of IAM database username to the ARN of the IAM policy granting rds-db:connect access for that user. map(string)
secret_arn ARN of the secret holding database credentials. string

About

OpenTofu module to create a manage an AWS Aurora serverless database.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors