How to store your DB credentials in Secrets Manager using Terraform
Tags: aws, secrets, security, terraform
Published: 2023-09-18 00:49:57

---
title: How to store your DB credentials in Secrets Manager using Terraform
published: true
date: 2023-04-11 02:08:44 UTC
tags: aws,secrets,security,terraform
canonical_url: https://awstip.com/how-to-store-your-db-credentials-in-secrets-manager-using-terraform-d2daeb0cbabc
---

In my previous two articles, I showed you [how to deploy a Java function as an AWS Lambda using AWS SAM](https://medium.com/@paulboeck/deploying-an-aws-lambda-with-sam-d8dc2be798e3?source=friends_link&sk=6b50fc2b83a642898464360f39a32bdf) and [how to stand up a MySQL RDS instance using Terraform](https://medium.com/@paulboeck/create-an-aws-rds-instance-with-terraform-e6bb9014dcde?source=friends_link&sk=691392c900b658b730d56d6f2fb75a4e). My larger goal is to show you how to set up a system leveraging Spring Boot and other Spring frameworks that reads weather data from a publicly available web API and inserts that data into MySQL for further analysis. The last thing you need to do before getting on with building that functionality and diving into Spring is to make sure the Lambda can connect to the MySQL instance. This is where AWS Secrets Manager comes in.

In this article, I’ll show you how to store the credentials as a secret in Secrets Manager using Terraform and discuss some options for how they can be configured. In [this follow-up article](https://medium.com/@paulboeck/aws-lambda-tutorial-using-secrets-manager-and-java-sdk-to-connect-to-mysql-8fcf3550dd86?source=friends_link&sk=deb569993db42885b2bd73be8ec1f721), I’ll show you what needs to be done in order for the Lambda function to access the secret.

![Terraform logo plus AWS Secrets Manager logo](https://cdn-images-1.medium.com/max/1024/1*VzOHlIQmZptWkvDb7T0yrw.png)

In order for the Lambda to connect to an RDS instance, it’s going to need access to the appropriate credentials to do so. Let’s explore some options for how we might set that up.

1. You could hard code the username and password in your code or properties files. This is a great option if you’re a lazy developer and you want to allow unauthorized access to your database. (_Hint_, this is a horrible option.)
2. You could add the username and password as environment variables configured on your Lambda function. This is a far better option than hard coding your credentials in your code and exposing them to anyone that has access to your source. However, anyone that has access to the Lambda function will be able to see the credentials in AWS. You can do better.
3. You could store the credentials as a secret in Secrets Manager. This lets you have more control over who can access the credentials since access to Secrets Manager must be configured in IAM. You have to jump through a few more hoops to make it work, but this is the option I’m recommending.
4. If you’re using MySQL or PostgreSQL, you can use IAM authentication. This method has it’s limitations and is beyond the scope of this article and my little project, but if you want to learn more about this method, you should search for articles that explain in detail how to do it, those articles do exist.

One thing I need to mention is that there is no free tier for Secrets Manager, you’re going to have to pay for each secret stored there. The current pricing structure can be found [here](https://aws.amazon.com/secrets-manager/pricing/). You’ll pay a monthly fee for each secret stored plus a fee for accessing the secret. At time of writing you’ll pay $0.40 per secret per month and $0.05 per 10,000 API calls. So it’s not very expensive, and if you use Terraform to do it as I’m going to show you, you can easily remove the secret if you’re just experimenting and the cost can be even lower as AWS will prorate the $0.40 per secret per month charge.

You’ll need to make a decision about how to structure your secret in Secrets Manager. At it’s core, a secret is just a string. You can store a JSON string in order to have a collection of key/value pairs stored as your secret. As I mentioned earlier, each secret stored will incur it’s own cost, so you may want to consider storing multiple values in a single secret to save money. To keep it simple, I’m going to store only the database password as a secret and will store it directly without wrapping it in JSON. Just know that you have the option to do so if you want to.

Alright, let’s get on with it then. Here’s how to store your secret using Terraform. It’s extremely simple. Here are the eight lines of Terraform code you’ll need. You can read my [previous article](https://medium.com/@paulboeck/create-an-aws-rds-instance-with-terraform-e6bb9014dcde?source=friends_link&sk=691392c900b658b730d56d6f2fb75a4e) for all the information you need about how to set up Terraform in your project, including how to set up variables so that the line secret\_string = var.db-password below works properly.

```
resource "aws_secretsmanager_secret" "example" {
  name = "weather-tracker-rds-password"
  recovery_window_in_days = 0 // Overriding the default recovery window of 30 days
}

resource "aws_secretsmanager_secret_version" "example" {
  secret_id = aws_secretsmanager_secret.example.id
  secret_string = var.db-password
}
```

If you do want to store multiple values using a JSON string, here’s an example of how you can set up the aws\_secretsmanager\_secret\_version resource to do that. As you can see, the JSON formatting is a bit more complex with all the quote escaping and whatnot. There are more elegant ways to do it if you go looking for them.

```
resource "aws_secretsmanager_secret_version" "example" {
  secret_id = aws_secretsmanager_secret.example.id
  secret_string = "{\"username\":\"${var.db-username}\", \"password\":\"${var.db-password}\"}"
}
```

One important thing to note about secrets stored in Secrets Manager is that by default, you can’t delete them immediately. AWS will put your secrets in a ‘scheduled for deletion’ state. The secret is still accessible and you’ll still pay for secrets in this state. Thankfully, Terraform allows you to specify recovery\_window\_in\_days = 0 which will override that default and allow you to immediately delete the secret you run terraform destroy which is perfect for this example. This value can also be set to a value between 7 and 30 days for use cases where you actually want the ability to schedule your secret deletion. You can find the Terraform documentation for this resource [here](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret) if you want to explore additional options, including secret rotation, that are available to you.

If you read the previous article about setting up an RDS instance with Terraform, you can hopefully start to realize one of the advantages of using Terraform to manage your infrastructure. If you add this Secrets Manager configuration to the RDS configuration, Terraform will create both resources using the same username and password, thus ensuring that your resources are configured to work together properly.

Now you know why you should store your database credentials in Secrets Manager and how to use Terraform to accomplish that goal. Having your credentials stored properly is great, but now you need to be able to actually use them to connect to your database. I’ll show you how to access the secret from a Java Lambda function using the [AWS SDK for Java](https://aws.amazon.com/sdk-for-java/) in [my next article](https://medium.com/@paulboeck/aws-lambda-tutorial-using-secrets-manager-and-java-sdk-to-connect-to-mysql-8fcf3550dd86?source=friends_link&sk=deb569993db42885b2bd73be8ec1f721).

Was this article helpful? Did you learn something? Was it worth your time, or a waste of time? I’d love to hear from you if you have questions or feedback on this article and/or if I can help you get past any stumbling blocks you may have encountered along the way!

* * *