Creating AWS RDS Database with Terraform (4/5)

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.

Prerequisites and source code:

Configuring a RDS MariaDB Database with Terraform

AWS RDS databases are ready to use database backed by AWS experience and with easy to use administration tools.

Best Practice: Use Cloud Services When Possible

Focus all your resources and energy in configuring and developing what is really disruptive and unique. Data Bases, Email servers, DNS servers, Queues are now a commodity.

Most of the time if you need full control of those services and If you don’t have millions of customers there is a big probability that you have a wrong design.

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-mariadb: for RDS Security Group for MariaBD type of resource
    • sr-rds-mariadb: for 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.

#------------------------
# RDS INSTANCES
#------------------------

  #------------------------
  # 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 aws_rds_sn_pro_01["name"]
    multi_az                = false
    vpc_security_group_ids  = ""
    parameter_group_name    = ""
    allow_major_version_up  = false
    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 my 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
#----------------------

# SECURITY
  # 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_sg_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 #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

Tag the RDS instance with all the needed identifiers.

Best Practice: Tag all your AWS Resources

Tags can be used to identify resources, split costs between cost centers, and for further configuration, provisioning and monitoring with dynamic inventories using Ansible or other tools.

Recommended tags:

  • 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.

Example:

Table showing tag keys and values
Tags and its values for an AWS RDS instance

Continue the Terraform and Ansible demo, see:

Creating AWS RDS Database with Terraform (4/5)

Leave a Reply

Your email address will not be published. Required fields are marked *

AWS Users
AWS

Create an AWS Account for Demos

In order to run the examples presented in IT Wonder Lab you will need accounts in different cloud providers. Most of the providers offer free