{"id":934,"date":"2023-07-17T10:15:14","date_gmt":"2023-07-17T10:15:14","guid":{"rendered":"https:\/\/blog.ngocha.biz\/?p=934"},"modified":"2023-07-17T10:15:14","modified_gmt":"2023-07-17T10:15:14","slug":"terraform-aws-rds","status":"publish","type":"post","link":"https:\/\/blog.ngocha.biz\/?p=934","title":{"rendered":"Terraform AWS RDS Provisioning [Practical Guide]"},"content":{"rendered":"<p>In this blog, you will learn Terraform AWS RDS provisioning with secret manager integration using step-by-step guides.<\/p>\n<h2 id=\"prerequisites\"><strong>Prerequisites<\/strong><\/h2>\n<p>To follow this guide you need to have the following.<\/p>\n<ol>\n<li>The latest Terraform binary is installed and configured in your system.<\/li>\n<li><a href=\"https:\/\/devopscube.com\/install-configure-aws-cli-linux\/\">AWS CLI installed <\/a>and configured with a Valid AWS account with permission to deploy RDS instances.<\/li>\n<li>If you using an ec2 instance for provisioning, ensure you have a valid<a href=\"https:\/\/devopscube.com\/aws-iam-role-instance-profile\/\"> IAM role<\/a> attached to the instance with RDS provisioning permissions.<\/li>\n<\/ol>\n<h2 id=\"terraform-rds-workflow\">Terraform RDS <strong>Workflow<\/strong><\/h2>\n<p>The following image shows the RDS provisioning workflow using Terraform.<\/p>\n<figure class=\"kg-card kg-image-card kg-card-hascaption\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/rds-terraform-workflow-1.gif\" class=\"kg-image\" alt=\"Terraform RDS provisioning Workflow\" loading=\"lazy\" width=\"1280\" height=\"800\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/rds-terraform-workflow-1.gif 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/rds-terraform-workflow-1.gif 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/rds-terraform-workflow-1.gif 1280w\" sizes=\"auto, (min-width: 720px) 720px\"><figcaption><span style=\"white-space: pre-wrap;\">Click to View in HD<\/span><\/figcaption><\/figure>\n<p>Here is the workflow explanation.<\/p>\n<ol>\n<li>Terraform code is developed, tested, and pushed to GitHub<\/li>\n<li>Pull the terraform code to the workstation or server where you have the terraform and AWS CLI configured. Ideally, this would be an agent of a CI server like <a href=\"https:\/\/devopscube.com\/jenkins-2-tutorials-getting-started-guide\/\">Jenkins<\/a><\/li>\n<li>Execute the terraform RDS script by passing the variables required for RDS provisioning.<\/li>\n<li>RDS gets provisioned and the password for RDS will be automatically created and stored in the AWS secrets manager. You can also use direct passwords instead of secret manager. However, it is not recommended to keep secrets in terraform code.<\/li>\n<li>Once the RDS instance is provisioned the RDS endpoint, address, and secret manager secret <a href=\"https:\/\/devopscube.com\/aws-arn-guide\/\">arn<\/a> get added to the terraform output. With the secret arn, applications can retrieve the DB username and password from the secrets manager.<\/li>\n<li>If you use s3 as a remote state, the state file gets stored in s3 or else the state gets stored locally. It is not recommended to use the local state in real projects.<\/li>\n<\/ol>\n<h2 id=\"terraform-rds-code-repository\"><strong>Terraform RDS Code<\/strong> Repository<\/h2>\n<p>RDS terraform code is part of the <a href=\"https:\/\/github.com\/techiescamp\/terraform-aws.git?ref=devopscube.com\" rel=\"noreferrer noopener\">terraform AWS<\/a> repository. Clone it to your workstation to follow the guide.<\/p>\n<pre><code>git clone https:\/\/github.com\/techiescamp\/terraform-aws.git<\/code><\/pre>\n<p>Fork and clone the repository if you intend to reuse and make changes as per your requirements.<\/p>\n<h2 id=\"terraform-aws-rds-provisioning-workflow\"><strong>Terraform AWS<\/strong> RDS Provisioning Workflow<\/h2>\n<p>The RDS terraform script is structured in the following way.<\/p>\n<pre><code>\u251c\u2500\u2500 environments\n\u2502   \u251c\u2500\u2500 dev\n\u2502   \u2502   \u251c\u2500\u2500 rds\n\u2502   \u2502   \u2502   \u251c\u2500\u2500 main.tf\n\u2502   \u2502   \u2502   \u2514\u2500\u2500 variables.tf\n\u251c\u2500\u2500 modules\n\u2502   \u251c\u2500\u2500 rds\n\u2502   \u2502   \u251c\u2500\u2500 main.tf\n\u2502   \u2502   \u251c\u2500\u2500 outputs.tf\n\u2502   \u2502   \u2514\u2500\u2500 variables.tf\n\u2514\u2500\u2500 vars\n    \u2514\u2500\u2500 dev\n        \u2514\u2500\u2500 rds.tfvars<\/code><\/pre>\n<p><code><strong>vars<\/strong><\/code> folder contains the variables file named <code>rds.tfvars<\/code><\/p>\n<p><code><strong>environments<\/strong><\/code> folder contains the terraform code (<code>main.tf<\/code>) that calls the actual RDS module from the modules directory.<\/p>\n<p>The module contains the following resources<\/p>\n<ol>\n<li><strong>Security Group: <\/strong>To allow &amp; deny access to\/from the instance.<\/li>\n<li><strong>Subnet Group:<\/strong> For demo purposes, we have added the subnet group. Ideally, you don&#8217;t need to create a subnet group for each RDS. You can re-use the existing subnet groups as there is a <a href=\"https:\/\/docs.aws.amazon.com\/AmazonRDS\/latest\/UserGuide\/CHAP_Limits.html?ref=devopscube.com\" rel=\"noreferrer noopener\">default limit of 50 subnet groups<\/a> you can create per region. The limits can be increased by request though.<\/li>\n<li><strong>RDS: <\/strong>Resource to provision RDS instances based on the variables.<\/li>\n<\/ol>\n<figure class=\"kg-card kg-image-card kg-card-hascaption\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/rds-terraform-code-workflow-1.gif\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"1080\" height=\"1080\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/rds-terraform-code-workflow-1.gif 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/rds-terraform-code-workflow-1.gif 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/rds-terraform-code-workflow-1.gif 1080w\" sizes=\"auto, (min-width: 720px) 720px\"><figcaption><span style=\"white-space: pre-wrap;\">Click to View in HD<\/span><\/figcaption><\/figure>\n<blockquote><p><strong>Note: <\/strong>There are many parameters supported by RDS. If you want to deploy RDS for production use cases, please refer to the official documentation and design a solution that complies with security and availability as per organizational standards. Refer to  terraform official <a href=\"https:\/\/registry.terraform.io\/providers\/hashicorp\/aws\/latest\/docs\/resources\/db_instance?ref=devopscube.com\" rel=\"noreferrer noopener\">aws_db_instance resource documenation<\/a> to know about all the supported parameters.<\/p><\/blockquote>\n<h2 id=\"provisioning-rds-using-terraform\">Provisioning RDS Using Terraform<\/h2>\n<p>Follow the steps given in this section to provision an RDS instance.<\/p>\n<blockquote><p><strong>Note<\/strong>: For this demo, we will be using the MySQL RDS instance that is<strong> publicly accessible over port 3306<\/strong>. If you deploying it in project environemnt, modify the paramters to restrict access to only required IP ranges.<\/p><\/blockquote>\n<p>I assume <strong>terraform-aws<\/strong> folder as the root folder for the entire guide.<\/p>\n<p><strong>Step 1: <\/strong>Modify the RDS variables<\/p>\n<p>Open the <strong><code>rds.tfvars<\/code><\/strong> file present in the <strong>vars\/dev<\/strong> folder. Change these variables according to your requirements. The following are the variables present.<\/p>\n<p>Primarily you need to change the variables marked in bold.<\/p>\n<ol>\n<li>Replace <strong>subnet_ids<\/strong> with your <strong>subnet<\/strong> ids.<\/li>\n<li>If you want to manage the RDS secret using AWS secrets manager, ensure you set <code>set_secret_manager_password = true<\/code> and <code>set_db_password  = false<\/code>. The condition is handled inside the RDS module code.<\/li>\n<li>Change the <strong>cidr_block<\/strong> to the CIDR range from which access is required to RDS.<\/li>\n<li>Replace <strong>db_engine<\/strong> with the required DB engineer. RDS supports Aurora, MariaDB, PostgreSQL, Oracle, and Microsoft SQL Server.<\/li>\n<\/ol>\n<p>Other variables are self-explanatory and change<\/p>\n<pre><code># Network Vars\nregion                      = \"us-west-2\"\nsubnet_ids                  = [\"subnet-058a7514ba8adbb07\", \"subnet-0dbcd1ac168414927\", \"subnet-032f5077729435858\"]\nmulti_az                    = false\npublicly_accessible         = true\n\n# DB Vars\ndb_engine                   = \"mysql\"\ndb_storage_type             = \"gp2\"\ndb_username                 = \"techiescamp\"\ndb_instance_class           = \"db.t2.micro\"\ndb_storage_size             = 20\nset_secret_manager_password = false\nset_db_password             = true\ndb_password                 = \"rdssecret\"\n\n# Security Group Vars\nfrom_port                   = 3306\nto_port                     = 3306\nprotocol                    = \"tcp\"\ncidr_block                  = [\"0.0.0.0\/0\"]\n\n# Backup vars\nbackup_retention_period     = 7\ndelete_automated_backups    = true\ncopy_tags_to_snapshot       = true\nskip_final_snapshot         = true\napply_immediately           = true\n\n# Tag Vars\nowner                       = \"techiescamp-devops\"\nenvironment                 = \"dev\"\ncost_center                 = \"techiescamp\"\napplication                 = \"techiescamp-commerce\"<\/code><\/pre>\n<p><strong>Step 2:<\/strong> Initialize terraform<\/p>\n<p>Once the variables are modified as per your requirements, go to the terminal and cd into <strong><code>environments\/dev\/rds<\/code><\/strong> directory.<\/p>\n<pre><code>cd environments\/dev\/rds<\/code><\/pre>\n<p>Inside the rds folder, you can find the <strong>main.tf<\/strong> file where it <strong>calls the rds module<\/strong> present in the modules directory as shown below.<\/p>\n<pre><code>provider \"aws\" {\n  region = var.region\n}\n\nmodule \"rds\" {\n  source                      = \"..\/..\/..\/modules\/rds\"\n  region                      = var.region\n  subnet_ids = var.subnet_ids\n  db_engine                   = var.db_engine\n  db_storage_type             = var.db_storage_type\n  db_username                 = var.db_username\n  set_secret_manager_password = var.set_secret_manager_password\n  set_db_password             = var.set_db_password\n  db_password                 = var.db_password\n  db_instance_class           = var.db_instance_class\n  db_storage_size             = var.db_storage_size\n  from_port                   = var.from_port\n  to_port                     = var.to_port\n  protocol                    = var.protocol\n  cidr_block                  = var.cidr_block\n  backup_retention_period     = var.backup_retention_period\n  multi_az                    = var.multi_az\n  delete_automated_backups    = var.delete_automated_backups\n  copy_tags_to_snapshot       = var.copy_tags_to_snapshot\n  publicly_accessible         = var.publicly_accessible\n  skip_final_snapshot         = var.skip_final_snapshot\n  apply_immediately           = var.apply_immediately\n  owner                       = var.owner\n  cost_center                 = var.cost_center\n  environment                 = var.environment\n  application                 = var.application\n}<\/code><\/pre>\n<p>Initialize Terraform using the following command<\/p>\n<pre><code>terraform init<\/code><\/pre>\n<p>This command initializes terraform. Make sure to run the init command inside the <strong>environments\/dev\/rds<\/strong> directory.<\/p>\n<p><strong>Step 3: <\/strong>To verify the configurations, run terraform plan with the variable file.<\/p>\n<pre><code>terraform plan  -var-file=..\/..\/..\/vars\/dev\/rds.tfvars<\/code><\/pre>\n<p>This command displays the plan which is going to execute.<\/p>\n<p><strong>Step 4:<\/strong> Apply the terraform configurations.<\/p>\n<p>After verifying, apply the configurations using the command given below.<\/p>\n<pre><code>terraform apply -var-file=..\/..\/..\/vars\/dev\/rds.tfvars --auto-approve<\/code><\/pre>\n<p>This command applies the changes to start the provisioning using the variables given in the <strong>rds.tfvars<\/strong> file. The <strong><code>--auto-approve<\/code><\/strong> flag automatically approves the provisioning without manual confirmation.<\/p>\n<p><strong>Step 5:<\/strong> Validate provisioned RDS instances<\/p>\n<p>Once the terraform is executed, you can validate the RDS instance by getting the RDS DNS endpoint, address, and secret arn using the following command.<\/p>\n<pre><code>terraform output<\/code><\/pre>\n<p>Also, use the AWS console and verify all the RDS instance details.<\/p>\n<p>Try accessing the database using the username, password, and RDS endpoint as host. You can use MySQL client or MySQL workbench utility.<\/p>\n<p>If you have enabled secret management using secrets manager, you can retrieve the secret from the AWS console.<\/p>\n<p><strong>Step 5:<\/strong> To clean up the setup, execute the following command.<\/p>\n<pre><code>terraform destroy -var-file=..\/..\/..\/vars\/dev\/rds.tfvars --auto-approve<\/code><\/pre>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>In this guide, we looked at <strong>terraform aws rds<\/strong> provisioning.<\/p>\n<p>RDS supports password management using a secrets manager. It creates and stores the username and password during provisioning. Each secret in the secret manager <strong>costs $.50.<\/strong> The secret created by RDS cannot be modified separately. Also, by default, <strong>password rotation<\/strong> is enabled for the master password with a <strong>rotation schedule of 7 days.<\/strong> That value can be modified in the secrets manager.<\/p>\n<p>You can also look at the <a href=\"https:\/\/github.com\/terraform-aws-modules\/terraform-aws-rds\/tree\/master?ref=devopscube.com\" rel=\"noreferrer noopener\">AWS RDS community module<\/a> to learn more.<\/p>\n<p>When using RDS for production, you must consider <strong>security, availability, <\/strong><a href=\"https:\/\/devopscube.com\/how-to-setup-and-push-serverapplication-logs-to-aws-cloudwatch\/\"><strong>cloudwatch logging<\/strong><\/a><strong>, scalability, and <\/strong><a href=\"https:\/\/devopscube.com\/devops-tools-for-infrastructure-automation\/\"><strong>monitoring<\/strong><\/a>. Whether you are using a community module or a custom RDS, terraform AWS module, ensure you follow the organization&#8217;s standards.<\/p>\n<p>Next, you can try our <a href=\"https:\/\/devopscube.com\/terraform-autoscaling-group\/\" rel=\"noreferrer noopener\">Terraform autoscaling group<\/a> deployment guide.<\/p>\n<p>I hope this guide is helpful. Do let me know your feedback in the comments.<\/p>\n<hr>\n<p><strong>Ngu\u1ed3n:<\/strong> <a href=\"https:\/\/devopscube.com\/terraform-aws-rds\/\" target=\"_blank\" rel=\"noopener noreferrer\">Terraform AWS RDS Provisioning [Practical Guide] \u2014 DevOpsCube<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Source: https:\/\/devopscube.com\/terraform-aws-rds\/<\/p>\n","protected":false},"author":1,"featured_media":935,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-934","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/934","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=934"}],"version-history":[{"count":0,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/934\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/media\/935"}],"wp:attachment":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=934"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=934"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=934"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}