Tutorial and source code explaining how to create and manage a MariaDB (or MySQL) database with Terraform in AWS.

RDS MariaDB Database and Resource Tags

This is the continuation of a Terraform demo to create a VPC in AWS with an EC2 instance connected to MariaDB database running in RDS (Amazon Relational Database Service) using a single Terraform plan.

Operating System and software configuration is done using Ansible after the infrastructure has been created.

Continue the demo, see:

Download de the code from IT Wonder Lab public GitHub repository.

Configuring a RDS MariaDB Database with Terraform

I am a big fan of AWS RDS databases as you can access a ready to use database that is backed by AWS experience and has administration tools that are easy to use.

IT Wonder Lab recommendation is to use Cloud services as much as possible and focus all your resources and energy in configuring and developing what is really disruptive and unique.

In my opinion the only reason not to use a RDS database is if you have requirements that are not available in RDS, but even then, Do you really need those requirement?  ar you so unique? or aren’t those requirements going to be included in standardized services once you are done developing?

The AWS RDS database is fully configured in the terraform.tfvars file.

Following IT Wonder Lab best practices the RDS elements will be named following a pattern:

  • Cloud: a prefix specifying the unique name of this cloud across all available clouds and providers. In this case the prefix will be: ditwl that stands for Demo ITWonder Lab in lowercase.
  • Resource: a short name identifying the resource, in this case:
    • rds-mariadb: for RDS MariaDB type of resource
    • sg-rds-mariadbfor RDS Security Group for MariaBD type of resource
    • sr-rds-mariadbfor RDS Security Rule for MariaBD type of resource
  • Environment: for resources that are not to be shared between environments, a 3 letter acronym for the environment:
    • pro: production
    • pre: preproduction
    • dev: development
  • Visibility: for resources that can be either public or private, a 3 letter acronym for the visibility:
    • pub: for public resources
    • pri: for private resources
  • Name/ID: optional a name or ID that describes the usage of the resource or the number of the resource instance, for example:
    • DB resource number: this will be the RDS MariaDB 01 for Public Zones and Pro Environment. We might have new RDS DB on the future, adding a number now will make it easier to grow the infrastructure later on.
    • DB security group number: this will be the RDS MariaDB security group 01 for Public Zones and Pro Environment. We might have new security groups on the future, adding a number now will make it easier to grow the infrastructure later on.
    • Description of the purpose of the rule: using a description like instances_to_db_port explains the intended usage of the rule. In this case it is a rule to allow access from the EC2 instances to the RDS Database port.

Be aware of the password in clear text in terraform.tfvars. It will also show in terraform.tftstate and terraform.tfstate.backup.  Currently, the recommended action for passwords in Terraform files is to change them after resource creation using a different tool (AWS cli, AWS Console, Ansible, DB Client …). A changed password in Terraform doesn’t trigger a resource property change.


  # MariaDB PRO 01
  aws_rds_mariadb_pro_pub_01 = {
    identifier              = "ditwl-rds-mariadb-pro-pub-01"
    allocated_storage       = 20 #GB
    storage_type            = "gp2"
    final_snapshot_id       = "ditwl-rds-mariadb-pro-pub-01-final"
    skip_final_snapshot     = false
    engine                  = "mariadb"
    engine_version          = "10.2.11"
    instance_class          = "db.t2.micro"
    password                = "*************"
    username                = "ditwlRDSPROdb01" #Start with a letter. Only numbers, letters, and _ accepted, 1 to 16 characters long
    availability_zone       = "us-east-1a"
    backup_retention_period = 5
    #db_subnet_group_name   = See var "${var.aws_rds_sn_pro_01["name"]}"
    multi_az                = false
    vpc_security_group_ids  = ""
    parameter_group_name    = ""
    allow_major_version_up  = ""
    publicly_accessible     = true
    tag_private_name        = "ditwl-rds-mariadb-pro-pub-01"
    tag_public_name         = "ditwl-rds-mariadb-pro-pub-01"
    tag_app                 = "mariadb"
    tag_app_id              = "mariadb-01"
    tag_os                  = "rds"
    tags_environment        = "pro"
    tag_cost_center         = "ditwl_permanent"

  # RDS Security Group
  aws_sg_rds_mariadb_pro_pub_01 = {
    sec_name        = "ditwl-aws-sg-rds-mariadb-pro-pub-01"
    sec_description = "ditwl - MariaDb server access rules - Pub, Env: PRO"
    allow_all_outbound = false
    # Allow access from EC2 instances to DB port
    aws_sr_rds_mariadb_pro_pub_01_instances_to_db_port = {
      type              = "ingress"
      from_port         = "3306"
      to_port           = "3306"
      protocol          = "tcp"
      #source_security_group_id "${module.aws_sec_group_ec2_default.id}"
      description       = "Access from Instances to DB port"

aws_rds_pro_mariadb_01.tf is used to create the security group, assign the security rule and launch the database.

# RDS MariaDB

  # Group
  module "aws_sg_rds_mariadb_pro_pub_01" {
    source      = "./modules/aws/security/group"
    vpc_id      = "${module.aws_network_vpc.id}"
    name        = "${var.aws_sg_rds_mariadb_pro_pub_01["sec_name"]}"
    description = "${var.aws_sg_rds_mariadb_pro_pub_01["sec_description"]}"

  # Rules
  # Access from instances in group aws_sec_group_ec2_default to DB Port
  module "aws_sr_rds_mariadb_pro_pub_01_instances_to_db_port" {
    source            = "./modules/aws/security/rule/source_group"
    security_group_id = "${module.aws_sg_rds_mariadb_pro_pub_01.id}"
    type              = "${var.aws_sr_rds_mariadb_pro_pub_01_instances_to_db_port["type"]}"
    from_port         = "${var.aws_sr_rds_mariadb_pro_pub_01_instances_to_db_port["from_port"]}"
    to_port           = "${var.aws_sr_rds_mariadb_pro_pub_01_instances_to_db_port["to_port"]}"
    protocol          = "${var.aws_sr_rds_mariadb_pro_pub_01_instances_to_db_port["protocol"]}"
    source_security_group_id = "${module.aws_sec_group_ec2_default.id}"
    description       = "${var.aws_sr_rds_mariadb_pro_pub_01_instances_to_db_port["description"]}"

module "aws_rds_mariadb_pro_pub_01" {
  source = "./modules/aws/rds/instance"

  identifier              = "${var.aws_rds_mariadb_pro_pub_01["identifier"]}"
  allocated_storage       = "${var.aws_rds_mariadb_pro_pub_01["allocated_storage"]}"
  storage_type            = "${var.aws_rds_mariadb_pro_pub_01["storage_type"]}"
  final_snapshot_id       = "${var.aws_rds_mariadb_pro_pub_01["final_snapshot_id"]}"
  skip_final_snapshot     = "${var.aws_rds_mariadb_pro_pub_01["skip_final_snapshot"]}"
  engine                  = "${var.aws_rds_mariadb_pro_pub_01["engine"]}"
  engine_version          = "${var.aws_rds_mariadb_pro_pub_01["engine_version"]}"
  instance_class          = "${var.aws_rds_mariadb_pro_pub_01["instance_class"]}"
  password                = "${var.aws_rds_mariadb_pro_pub_01["password"]}"
  username                = "${var.aws_rds_mariadb_pro_pub_01["username"]}"
  availability_zone       = "${var.aws_rds_mariadb_pro_pub_01["availability_zone"]}"
  backup_retention_period = "${var.aws_rds_mariadb_pro_pub_01["backup_retention_period"]}"

  # Workaround for dependency. We need Terraform to wait for aws_rds_sn_pro_01 creation before the RDS DB can use it.
  db_subnet_group_name    = "${module.aws_rds_sn_pub_pro_01.id}" #"${var.aws_rds_sn_pro_01["name"]}"

  multi_az                = "${var.aws_rds_mariadb_pro_pub_01["multi_az"]}"
  vpc_security_group_ids  = ["${module.aws_sg_rds_mariadb_default.id}","${module.aws_sg_rds_mariadb_pro_pub_01.id}"]
  publicly_accessible     = "${var.aws_rds_mariadb_pro_pub_01["publicly_accessible"]}"

  #parameter_group_name    = "${aws_db_parameter_group.rds_pos_96_db_parameter_group_01.id}"
  allow_major_version_up  = "${var.aws_rds_mariadb_pro_pub_01["allow_major_version_up"]}"
  tag_private_name        = "${var.aws_rds_mariadb_pro_pub_01["tag_private_name"]}"
  tag_public_name         = "${var.aws_rds_mariadb_pro_pub_01["tag_public_name"]}"
  tag_app                 = "${var.aws_rds_mariadb_pro_pub_01["tag_app"]}"
  tag_app_id              = "${var.aws_rds_mariadb_pro_pub_01["tag_app_id"]}"
  tag_os                  = "${var.aws_rds_mariadb_pro_pub_01["tag_os"]}"
  tags_environment        = "${var.aws_rds_mariadb_pro_pub_01["tags_environment"]}"
  tag_cost_center         = "${var.aws_rds_mariadb_pro_pub_01["tag_cost_center"]}"

A workaround is used to create a dependency between the RDS subnet group and the RDS database. See RDS subnet group creation in part II (VPC/RDS Sub Nets).

db_subnet_group_name = "${module.aws_rds_sn_pub_pro_01.id}"

In order to launch the RDS database the subnet needs to exist, we provide the name of the RDS subnet using the output ID of the RDS subnet as source, this way Terraform is forced to create the RDS subnet first in order to evaluate the output ID.

Tagging AWS RDS Databases in Terraform

Tags can be used to identify resources, split costs between cost centers, and for further configuration and provisioning with dynamic inventories.

IT Wonder Lab recommends adding at least these tags to all resources.

  • Private Name: The private name for this element, it is used for DNS registration in private zone and should follow a standard and be unique. It can be used for monitoring and server naming.
  • Public Name: The public name for the element, it can be used in DNS registration in public zones and can be the same for many instances, as instances can be behind load balancers. In RDS it is the same as the private name.
  • App: The name of the main application that will be used in the resource.
  • App ID: A unique characteristic of the application or a number that can be used to differentiate multiple different instances of the same application, for example imagine you have to releases of the same application in the same environment, App ID could be the release number.
  • OS: The operating system of the instance, useful for applying basic configuration.
  • Environment: Used for environment identification, it is a 3 letter acronym for the environment:
  • Cost Center:  one or many cost centers that this resource should be assigned to. The cost center is used in billing to classify resources, for example if you provide resources for different customers, some resources are shared and other are costs associated to a specific customer.

Values should all be in lowercase without spaces.


Table showing tag keys and values

Tags and its values for an AWS RDS instance

Continue the demo, see:

How useful was this post?

Click on a star to rate it!

Average rating 4.8 / 5. Vote count: 5

No votes so far! Be the first to rate this post.

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?

Leave a Reply


This site uses Akismet to reduce spam. Learn how your comment data is processed.