Skip to content

Commit b6b97f6

Browse files
Rahul-4480vjdhama
authored andcommitted
add blog on managing Credentials and Secrets in Terraform
1 parent b40868f commit b6b97f6

File tree

1 file changed

+369
-0
lines changed

1 file changed

+369
-0
lines changed
Lines changed: 369 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,369 @@
1+
---
2+
title: "Managing Credentials and Secrets in Terraform"
3+
authorId: "rahul"
4+
date: 2024-08-06
5+
draft: false
6+
featured: true
7+
weight: 1
8+
---
9+
10+
When working with Terraform, managing credentials and secrets securely is crucial. In this blog, we'll explore several methods for managing secrets and credentials securely, including environment variables, GitHub Secrets, encrypted files with AWS KMS, and AWS Secrets Manager. We’ll also compare these methods to help you choose the best approach for your needs.
11+
12+
### Method 1: Environment Variables
13+
14+
Using environment variables to manage secrets in Terraform is straightforward and commonly used. This approach keeps sensitive data like usernames and passwords out of your codebase and allows for easy integration with your CI/CD pipelines.
15+
16+
#### Step-by-Step Guide
17+
18+
Imagine you need to create an AWS RDS instance, and you want to keep the database username and password secure.
19+
20+
**1. Define Sensitive Variables in Terraform:**
21+
22+
First, define your sensitive variables in your Terraform configuration file. Marking them as sensitive ensures that Terraform treats them securely.
23+
24+
```hcl
25+
variable "db_password" {
26+
type = string
27+
sensitive = true
28+
}
29+
30+
variable "db_username" {
31+
type = string
32+
sensitive = true
33+
}
34+
```
35+
36+
**2. Use Variables in Resource Definitions:**
37+
38+
Use these variables in your resource definitions. Here’s an example of an AWS RDS instance where the database username and password are sourced from the defined variables.
39+
40+
```hcl
41+
resource "aws_db_instance" "example" {
42+
identifier = "mydbinstance"
43+
engine = "mysql"
44+
instance_class = "db.t3.micro"
45+
allocated_storage = 10
46+
publicly_accessible = true
47+
skip_final_snapshot = true
48+
username = var.db_username
49+
password = var.db_password
50+
}
51+
```
52+
53+
**3. Set Environment Variables:**
54+
55+
Before applying your Terraform configuration, set the environment variables for the database username and password. This can be done in your shell or CI/CD pipeline configuration.
56+
57+
```sh
58+
export TF_VAR_db_username="my_db_username"
59+
export TF_VAR_db_password="my_db_password"
60+
```
61+
62+
**4. Apply Terraform Configuration:**
63+
64+
Finally, run your Terraform commands as usual. Terraform will read the environment variables and use them to configure your resources.
65+
66+
```sh
67+
terraform init
68+
terraform plan
69+
terraform apply
70+
```
71+
72+
### Method 2: Encrypted Files (KMS)
73+
74+
Using encrypted files to manage secrets in Terraform is a robust approach that enhances security by leveraging AWS Key Management Service (KMS). This method ensures that sensitive information is stored in an encrypted format and decrypted only when needed by Terraform.
75+
76+
#### Step-by-Step Guide
77+
78+
Imagine you need to create an AWS RDS instance, and you want to keep the database username and password secure by storing them in an encrypted file.
79+
80+
**1. Create a YAML File with Credentials:**
81+
82+
First, create a YAML file (db-creds.yml) that contains your database credentials:
83+
84+
```yaml
85+
db_username: my_db_username
86+
db_password: my_db_password
87+
```
88+
89+
**2. Encrypt the YAML File Using AWS KMS:**
90+
91+
*Alternative 1: Using AWS CLI*
92+
93+
You can use the AWS CLI to manually encrypt your YAML file:
94+
95+
```sh
96+
aws kms encrypt --key-id <your-kms-key-id> --region <your-region> --plaintext fileb://db-creds.yml --output text --query CiphertextBlob > db-creds.yml.encrypted
97+
```
98+
99+
Replace `<your-kms-key-id>` and `<your-region>` with your KMS key ID and AWS region, respectively.
100+
101+
*Alternative 2: Using Terraform*
102+
103+
You can also handle encryption through Terraform:
104+
105+
```hcl
106+
variable "db_username" {
107+
type = string
108+
sensitive = true
109+
}
110+
111+
variable "db_password" {
112+
type = string
113+
sensitive = true
114+
}
115+
116+
resource "aws_kms_key" "db_creds_key" {
117+
description = "KMS key for encrypting database credentials"
118+
tags = {
119+
Name = "db_creds_key"
120+
}
121+
}
122+
123+
resource "aws_kms_ciphertext" "db_creds" {
124+
key_id = aws_kms_key.db_creds_key.id
125+
plaintext = jsonencode({
126+
db_username = var.db_username
127+
db_password = var.db_password
128+
})
129+
context = {
130+
"Purpose" = "Encrypting database credentials"
131+
}
132+
}
133+
134+
resource "aws_secretsmanager_secret" "db_creds" {
135+
name = "db-credentials"
136+
}
137+
138+
resource "aws_secretsmanager_secret_version" "db_creds_version" {
139+
secret_id = aws_secretsmanager_secret.db_creds.id
140+
secret_string = aws_kms_ciphertext.db_creds.ciphertext_blob
141+
}
142+
```
143+
144+
Note: Store your secrets in a `terraform.tfvars` file or pass them as environment variables:
145+
146+
```hcl
147+
# terraform.tfvars
148+
db_username = "my_db_username"
149+
db_password = "my_db_password"
150+
```
151+
152+
Alternatively, set environment variables before running Terraform commands:
153+
154+
```sh
155+
export TF_VAR_db_username="my_db_username"
156+
export TF_VAR_db_password="my_db_password"
157+
```
158+
159+
**3. Define KMS Data Source in Terraform:**
160+
161+
Use the `aws_secretsmanager_secret_version` data source in your Terraform configuration to retrieve and decrypt the encrypted file:
162+
163+
```hcl
164+
data "aws_secretsmanager_secret_version" "creds" {
165+
secret_id = aws_secretsmanager_secret.db_creds.id
166+
depends_on = [aws_secretsmanager_secret.db_creds, aws_secretsmanager_secret_version.db_creds_version]
167+
}
168+
169+
locals {
170+
db_cred = jsondecode(data.aws_secretsmanager_secret_version.creds.secret_string)
171+
}
172+
```
173+
174+
**4. Use Decrypted Credentials in Resource Definitions:**
175+
176+
Use the decrypted credentials in your resource definitions. Here’s an example of an AWS RDS instance where the database username and password are sourced from the decrypted file:
177+
178+
```hcl
179+
resource "aws_db_instance" "example" {
180+
identifier = "mydbinstance"
181+
engine = "mysql"
182+
instance_class = "db.t3.micro"
183+
allocated_storage = 10
184+
publicly_accessible = true
185+
skip_final_snapshot = true
186+
username = local.db_cred.db_username
187+
password = local.db_cred.db_password
188+
}
189+
```
190+
191+
**5. Apply Terraform Configuration:**
192+
193+
Finally, run your Terraform commands as usual. Terraform will decrypt the file using AWS KMS and use the credentials to configure your resources:
194+
195+
```sh
196+
terraform init
197+
terraform plan
198+
terraform apply
199+
```
200+
201+
### Method 3: AWS Secrets Manager
202+
203+
AWS Secrets Manager provides a secure way to store and manage sensitive information such as database credentials, API keys, and other secrets. This method allows you to retrieve secrets dynamically within your Terraform configuration, ensuring that sensitive data is never hard-coded in your Terraform files.
204+
205+
#### Step-by-Step Guide
206+
207+
Here’s how you can manage your database credentials using AWS Secrets Manager:
208+
209+
**1. Store Your Secrets in AWS Secrets Manager using Terraform:**
210+
211+
First, use Terraform to create a secret in AWS Secrets Manager. Define the secret in your Terraform configuration, using variables to keep sensitive information secure:
212+
213+
```hcl
214+
variable "db_username" {
215+
type = string
216+
sensitive = true
217+
}
218+
219+
variable "db_password" {
220+
type = string
221+
sensitive = true
222+
}
223+
224+
resource "aws_secretsmanager_secret" "mysql_cred" {
225+
name = "mysql-cred"
226+
}
227+
228+
resource "aws_secretsmanager_secret_version" "mysql_cred_version" {
229+
secret_id = aws_secretsmanager_secret.mysql_cred.id
230+
secret_string = jsonencode({
231+
db_username = var.db_username
232+
db_password = var.db_password
233+
})
234+
}
235+
```
236+
237+
Note: Store your secrets in a `terraform.tfvars` file or pass them as environment variables:
238+
239+
```hcl
240+
# terraform.tfvars
241+
db_username = "my_db_username"
242+
db_password = "my_db_password"
243+
```
244+
245+
Alternatively, set environment variables before running Terraform commands:
246+
247+
```sh
248+
export TF_VAR_db_username="my_db_username"
249+
export TF_VAR_db_password="my_db_password"
250+
```
251+
252+
**2. Retrieve Secrets in Terraform:**
253+
254+
Use the `aws_secretsmanager_secret_version` data source to fetch the secret from AWS Secrets Manager:
255+
256+
```hcl
257+
data "aws_secretsmanager_secret_version" "creds" {
258+
secret_id = aws_secretsmanager_secret.mysql_cred.id
259+
depends_on = [aws_secretsmanager_secret.mysql_cred, aws_secretsmanager_secret_version.mysql_cred_version]
260+
}
261+
262+
locals {
263+
db_cred = jsondecode(data.aws_secretsmanager_secret_version.creds.secret_string)
264+
}
265+
```
266+
267+
**3. Use Retrieved Secrets in Resource Definitions:**
268+
269+
Use the retrieved credentials in your resource definitions. Here’s an example of an AWS RDS instance where the database username and password are sourced from AWS Secrets Manager:
270+
271+
```hcl
272+
resource "aws_db_instance" "example" {
273+
identifier = "mydbinstance"
274+
engine = "mysql"
275+
instance_class = "db.t3.micro"
276+
allocated_storage = 10
277+
publicly_accessible = true
278+
skip_final_snapshot = true
279+
username = local.db_cred.db_username
280+
password = local.db_cred.db_password
281+
}
282+
```
283+
284+
**Alternative: Store Secrets Using AWS CLI:**
285+
286+
If you prefer, you can also store your secrets in AWS Secrets Manager using the AWS CLI. This can be an alternative to storing secrets directly via Terraform:
287+
288+
```sh
289+
aws secretsmanager create-secret --name mysql-cred --secret-string '{"db_username":"my_db_username","db_password":"my_db_password"}'
290+
```
291+
292+
**4. Apply Terraform Configuration:**
293+
294+
Run your Terraform commands as usual. Terraform will retrieve the secret values from AWS Secrets Manager and use them to configure your resources:
295+
296+
```sh
297+
terraform init
298+
terraform plan
299+
terraform apply
300+
```
301+
302+
### Method 4: GitHub Secrets
303+
304+
For projects managed with GitHub, using GitHub Secrets is a convenient way to store
305+
306+
and manage secrets securely within GitHub Actions workflows. This method is particularly useful for CI/CD pipelines where you need to keep sensitive data safe while automating deployments.
307+
308+
#### Step-by-Step Guide
309+
310+
Here’s how you can manage your database credentials using GitHub Secrets:
311+
312+
**1. Add Secrets to GitHub Repository:**
313+
314+
Navigate to your GitHub repository, go to **Settings > Secrets and variables > Actions**, and add your secrets. Use names like `DB_USERNAME` and `DB_PASSWORD`.
315+
316+
**2. Access Secrets in GitHub Actions Workflow:**
317+
318+
In your GitHub Actions workflow file (`.github/workflows/your-workflow.yml`), you can access these secrets as environment variables:
319+
320+
```yaml
321+
name: Deploy
322+
323+
on:
324+
push:
325+
branches:
326+
- main
327+
328+
jobs:
329+
deploy:
330+
runs-on: ubuntu-latest
331+
332+
steps:
333+
- name: Checkout code
334+
uses: actions/checkout@v3
335+
336+
- name: Set up Terraform
337+
uses: hashicorp/setup-terraform@v2
338+
with:
339+
terraform_version: 1.3.6
340+
341+
- name: Terraform Init
342+
run: terraform init
343+
344+
- name: Terraform Apply
345+
env:
346+
TF_VAR_db_username: ${{ secrets.DB_USERNAME }}
347+
TF_VAR_db_password: ${{ secrets.DB_PASSWORD }}
348+
run: terraform apply -auto-approve
349+
```
350+
351+
**3. Use Secrets in Terraform Configuration:**
352+
353+
Your Terraform configuration file remains unchanged, as it relies on the environment variables provided by GitHub Actions.
354+
355+
### Comparison of Methods
356+
357+
| **Method** | **Pros** | **Cons** | **Use Case** |
358+
|-------------------------|-----------------------------------------------|------------------------------------------------|---------------------------------------------|
359+
| **Environment Variables** | Simple to set up and use. | Secrets are exposed in environment variables. | Suitable for quick setups or local development. |
360+
| **Encrypted Files (KMS)** | High security with encryption at rest. | Requires additional steps for encryption/decryption. | Ideal for scenarios where KMS is already used. |
361+
| **AWS Secrets Manager** | Secure storage with automatic rotation. | Costs associated with Secrets Manager. | Best for production environments needing dynamic secrets. |
362+
| **GitHub Secrets** | Convenient for CI/CD workflows. | Limited to GitHub Actions. | Good for managing secrets in CI/CD pipelines. |
363+
364+
### Recommendations
365+
366+
- **Development Environments:** Environment variables or encrypted files (KMS) can be sufficient and are easier to set up.
367+
- **Production Environments:** AWS Secrets Manager provides robust security features and is recommended for managing secrets in production.
368+
369+
By understanding and applying these methods, you can ensure that your sensitive information remains secure and your Terraform configurations are well-managed.

0 commit comments

Comments
 (0)