
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Hardcoded credentials in source code or environment variables remain a primary vector for data breaches and compliance failures. To manage secrets with AWS Secrets Manager effectively, you must move beyond simple storage and implement automated rotation, strict IAM scoping, and infrastructure-as-code provisioning. This guide provides the exact configuration patterns I use to secure production databases and API keys while maintaining SOC 2 audit readiness.
How do you manage secrets with AWS Secrets Manager using Terraform?
Provisioning secrets manually through the AWS Console is unrepeatable and unauditable. When you adopt Infrastructure as Code with Terraform, you define the secret metadata and permissions declaratively. Crucially, never store the actual secret value in your Terraform state file. Instead, create the secret shell in Terraform and populate the value separately via CI/CD or CLI.
Terraform configuration for secret metadata
This configuration creates a secret for an RDS database. Note the lifecycle block ignoring value changes to prevent Terraform from overwriting rotated credentials.
resource "aws_secretsmanager_secret" "db_credentials" {
name = "prod/myapp/db-credentials"
description = "Production PostgreSQL credentials for MyApp"
kms_key_id = aws_kms_key.secrets_key.arn
tags = {
Environment = "production"
ManagedBy = "terraform"
Compliance = "SOC2"
}
lifecycle {
ignore_changes = [
# Allow external rotation or CI updates without TF drift
]
}
}
# Separate resource for initial value (optional, prefer CI injection)
resource "aws_secretsmanager_secret_version" "db_credentials_initial" {
secret_id = aws_secretsmanager_secret.db_credentials.id
secret_string = jsonencode({
username = "app_user"
password = "INITIAL_PLACEHOLDER_ROTATE_IMMEDIATELY"
host = "prod-db.cluster-xyz.us-east-1.rds.amazonaws.com"
port = 5432
dbname = "myapp_prod"
})
lifecycle {
ignore_changes = [secret_string]
}
} Injecting values securely via CLI
After Terraform applies the metadata, inject the real credential from your CI runner or secure workstation. This keeps the plaintext out of version control entirely.
aws secretsmanager put-secret-value \
--secret-id prod/myapp/db-credentials \
--secret-string '{"username":"app_user","password":"Str0ng!P@ssw0rd#2026","host":"prod-db.cluster-xyz.us-east-1.rds.amazonaws.com","port":5432,"dbname":"myapp_prod"}' \
--region us-east-1 How do you configure IAM policies for least-privilege secret access?
Overly permissive IAM is the most common failure when teams implement AWS IAM best practices. Never grant secretsmanager:GetSecretValue on *. Scope access by resource ARN and condition keys. Attach this policy to the application role, not the user.
- Resource-level permissions: Restrict to exact secret ARNs or prefixes like
arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/myapp/*. - Condition keys: Use
secretsmanager:ResourceTag/Environmentto prevent dev roles from reading prod secrets. - Deny-by-default: Explicitly deny
secretsmanager:DeleteSecretandsecretsmanager:PutSecretValuefor application roles; only CI/admin roles should write. - KMS dependency: Remember that Secrets Manager uses KMS. The role needs
kms:Decrypton the specific key, or GetSecretValue fails silently.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowReadAppSecrets",
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret"
],
"Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/myapp/*",
"Condition": {
"StringEquals": {
"secretsmanager:ResourceTag/Environment": "production"
}
}
},
{
"Sid": "AllowKMSDecryptForSecrets",
"Effect": "Allow",
"Action": "kms:Decrypt",
"Resource": "arn:aws:kms:us-east-1:123456789012:key/mrk-abc123def456",
"Condition": {
"StringEquals": {
"kms:ViaService": "secretsmanager.us-east-1.amazonaws.com"
}
}
}
]
} How does automatic rotation work for RDS credentials in AWS Secrets Manager?
Static credentials are a liability. Automatic rotation eliminates stale passwords and satisfies compliance controls requiring periodic credential renewal. When you manage secrets with AWS Secrets Manager for RDS, use the managed rotation Lambda rather than writing custom rotation logic.
Enabling managed rotation for Aurora PostgreSQL
The managed rotation template handles the create-test-promote cycle automatically. Configure it in Terraform alongside your secret.
resource "aws_secretsmanager_secret_rotation" "db_rotation" {
secret_id = aws_secretsmanager_secret.db_credentials.id
rotation_lambda_arn = aws_lambda_function.rds_rotation.arn
rotation_rules {
automatically_after_days = 30
duration = "4h"
schedule_expression = "rate(30 days)"
}
}
# Use AWS-managed rotation template
resource "aws_lambda_function" "rds_rotation" {
function_name = "secrets-manager-rds-rotation"
runtime = "python3.12"
handler = "main.lambda_handler"
filename = "rotation-lambda.zip"
role = aws_iam_role.rotation_lambda.arn
environment {
variables = {
SECRETS_MANAGER_ENDPOINT = "https://secretsmanager.us-east-1.amazonaws.com"
}
}
vpc_config {
subnet_ids = var.private_subnet_ids
security_group_ids = [aws_security_group.rotation_lambda.id]
}
} A common mistake is forgetting VPC configuration. The rotation Lambda must reside in the same VPC as your RDS instance with network access to the database port. Without this, rotation fails at the TestSecret step.
How do you retrieve secrets in applications without hardcoding?
Applications should fetch secrets at runtime using the AWS SDK, never from environment variables baked into container images. For containerized Laravel applications, use the AWS SDK PHP package or a sidecar pattern to inject secrets at startup.
// PHP/Laravel example: Fetch secret at runtime
use Aws\SecretsManager\SecretsManagerClient;
$client = new SecretsManagerClient([
'version' => 'latest',
'region' => env('AWS_REGION', 'us-east-1'),
]);
$result = $client->getSecretValue([
'SecretId' => 'prod/myapp/db-credentials',
]);
$credentials = json_decode($result['SecretString'], true);
// Use directly in config, never cache in env
config([
'database.connections.pgsql.host' => $credentials['host'],
'database.connections.pgsql.username' => $credentials['username'],
'database.connections.pgsql.password' => $credentials['password'],
]); Caching to reduce costs and latency
Each GetSecretValue call costs $0.05 per 10,000 requests. In high-traffic applications, this adds up. Implement client-side caching with TTLs aligned to your rotation window. The AWS SDK provides built-in caching; for custom implementations, cache for no longer than 5 minutes to balance cost savings against stale credential risk during rotation windows.
AWS Secrets Manager vs Parameter Store vs HashiCorp Vault
Choosing the right tool depends on compliance requirements, scale, and operational overhead. Below is a practical comparison based on production deployments across Nepal-based startups and global enterprises.
| Criteria | AWS Secrets Manager | SSM Parameter Store | HashiCorp Vault |
|---|---|---|---|
| Automatic Rotation | Native for RDS, Redshift, DocumentDB | No native rotation | Full dynamic secrets engine |
| Encryption | KMS mandatory (per-secret or shared) | KMS optional (Advanced tier) | Transit + storage encryption |
| Cross-Account Access | Native resource policies | Limited, requires RAM | Multi-cluster federation |
| Cost Model | $0.40/secret/month + API calls | Free (Standard) / $0.05 (Advanced) | Self-hosted or HCP ($$$) |
| SOC 2 / ISO 27001 | Audit logs via CloudTrail native | Requires Advanced tier for logging | Full audit backend, enterprise features |
| Best For | AWS-native apps needing rotation | Config values, non-sensitive params | Multi-cloud, dynamic creds, PKI |
Conclusion
To manage secrets with AWS Secrets Manager in production, combine Terraform-provisioned metadata, scoped IAM policies, managed rotation Lambdas, and runtime SDK retrieval with caching. This stack delivers security, compliance, and operational reliability without slowing development velocity. If your team needs help designing an audit-ready secrets architecture or migrating legacy credential stores, reach out to discuss your infrastructure requirements.