Store secrets with AWS Secrets Manager
Learn how to store secrets with AWS Secrets Manager in this AWS Tutorial lesson. Understand the core concepts, apply hands-on steps, and get ready for the next lesson.
Focus: store secrets with aws secrets manager
You've probably hardcoded a database password or an API key in a config file once — and then spent a sleepless night worrying about it being leaked to GitHub or a co-worker's laptop. Hardcoding secrets is the fastest way to turn a small project into a security incident. In this lesson, you'll learn how to store secrets with AWS Secrets Manager, the managed service that keeps your credentials encrypted, rotated, and audited — so you can stop fearing your own code.
The problem this lesson solves
Imagine your application needs to connect to a PostgreSQL database. The connection string includes a username and password. Where do you put that password? If you put it in config.py or a .env file, you've created a few serious problems:
- Version control leaks: The file gets committed to Git, and now your secret is in the repository history forever.
- No access control: Every developer and CI pipeline that clones the repo can read the secret — even if they shouldn't.
- No rotation: When the password changes (maybe a security policy forces it), you have to update the file manually and redeploy the app.
- No audit trail: If the secret leaks, you have no idea who accessed it or when.
These problems aren't hypothetical — they're the root cause of many real-world data breaches. The AWS way to solve this is to centralize secrets in a secure, managed store that integrates with IAM permissions, encryption, and rotation. That's exactly what AWS Secrets Manager offers.
Core concept / mental model
Think of AWS Secrets Manager as a vault with an API. Instead of embedding the secret in your code, you send it to the vault (encrypted at rest), and then your application retrieves it at runtime using AWS credentials. The vault controls who can read which secret, can rotate the secret automatically, and logs every access.
Here's a simple mental model:
- Secret: A name (like
prod/db/password) → a value (likeS3cr3t!2024). You store the reference to the secret, not the secret itself. - AWS KMS: Secrets Manager uses a Customer Master Key (CMK) to encrypt the secret at rest. You can use the default key or bring your own.
- IAM policies: Determine which IAM roles or users can call
secretsmanager:GetSecretValuefor a specific secret. - AWS SDK: Your Python code calls
boto3.client('secretsmanager').get_secret_value(SecretId='prod/db/password')to fetch the secret at runtime.
Compared to storing secrets in environment variables or a local file, Secrets Manager gives you:
- Encryption at rest with KMS
- Fine-grained access control with IAM
- Automatic rotation (optional, for supported services)
- Audit logging via CloudTrail (you can see who called
GetSecretValueand when)
This turns your secrets from static files into dynamic, controlled resources — the cloud-native way.
How it works step by step
Storing a secret in AWS Secrets Manager is a three-part flow:
- Create the secret — Either via the AWS Management Console, AWS CLI, or an SDK. You give it a meaningful name and the value(s).
- Grant IAM access — Create an IAM policy that allows only the necessary roles (e.g., your EC2 instance profile, Lambda role, or developer IAM user) to read the secret.
- Retrieve at runtime — Your application calls the AWS SDK (or CLI) to fetch the secret value when it needs it. The secret is decrypted by KMS and returned over HTTPS.
The key to a good design is that the secret never appears in your source code, config files, or build artifacts. It only exists in the Secrets Manager service, and your application gets it on demand.
Pro tip: Use the secret's ARN, not a hardcoded value, in your code. That way, rotating the secret (changing the value) doesn't require a code change or redeploy.
Hands-on walkthrough
Let's walk through a complete example: storing a database password and retrieving it from a Python script.
Step 1: Install the AWS SDK
Make sure you have boto3 installed and your AWS credentials are available (via environment variables, ~/.aws/credentials, or an IAM role).
pip install boto3
Step 2: Create a secret with the AWS CLI
You can create a secret from the console or with the CLI. Here's a quick CLI example:
aws secretsmanager create-secret \
--name prod/db/password \
--secret-string '{"username":"admin","password":"S3cr3t!2024"}'
This stores a JSON object as the secret value. The secret name is prod/db/password. You should see a JSON response with the ARN.
Step 3: Write a Python script to retrieve the secret
Here's a minimal script that fetches the secret and parses it:
import boto3
import json
sm = boto3.client('secretsmanager', region_name='us-east-1')
try:
response = sm.get_secret_value(SecretId='prod/db/password')
secret_string = response.get('SecretString', '')
secret = json.loads(secret_string)
print(f"Username: {secret['username']}")
print(f"Password: {secret['password']}")
except Exception as e:
print(f"Failed to get secret: {e}")
Expected output:
Username: admin
Password: S3cr3t!2024
That secret is now available to your app without being hardcoded.
Step 4: Use IAM to control access
Never give everyone GetSecretValue permissions. Attach a policy like this to the IAM role that your application runs with:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/db/password-*"
}
]
}
Now only that role can read that specific secret. Anyone else gets an AccessDeniedException.
Pro tip: When you create a secret, AWS appends a random suffix to the ARN (e.g.,
prod/db/password-1a2b3c). Use a wildcard in the policy as shown, or better, store the full ARN in your code and reference it directly.
Step 5: Rotate the secret (optional)
For supported services (like RDS), you can set up automatic rotation with a Lambda function. For custom secrets, you can rotate manually by calling update-secret with a new value:
aws secretsmanager update-secret \
--secret-id prod/db/password \
--secret-string '{"username":"admin","password":"NewS3cr3t!2025"}'
Your app will pick up the new value the next time it calls get_secret_value — no code change needed.
Compare options / when to choose what
| Option | Best for | Trade-offs |
|---|---|---|
| AWS Secrets Manager | Production secrets, rotation, audit, fine-grained IAM | Costs $0.40/month per secret, slight latency per call |
| SSM Parameter Store (SecureString) | Simple key-value with encryption, lower cost | No native rotation, no automatic audit (though CloudTrail still logs API calls) |
Environment variables / .env |
Local dev, non-production | No encryption, no IAM, easy to leak |
| Hardcoded string | Quick prototypes | Security disaster — never do this |
When to use Secrets Manager: If you're running production workloads on AWS and need to comply with security policies, rotate credentials automatically, or audit who accesses secrets, Secrets Manager is the right choice. It's also a natural fit if you already use AWS services like Lambda, ECS, or EC2 with IAM roles.
When to use something else: For a small personal project or a quick tutorial, SSM Parameter Store with a SecureString is cheaper and simpler. For local development, environment variables are fine as long as you never commit them.
Troubleshooting & edge cases
„Secret not found“ (ResourceNotFoundException)
- Check the secret name — it's case-sensitive. Verify you're using the full name.
- If you deleted the secret, you need to recreate it.
- Make sure you're in the same region. Secrets are regional — a secret in
us-east-1won't be visible fromeu-west-1.
AccessDeniedException
- Your IAM role/user doesn't have
secretsmanager:GetSecretValuepermission for that secret. Review your policies. - The secret ARN in the policy might be wrong (including the random suffix). Use the ARN from the
create-secretoutput.
SecretString is empty or missing
- If you created the secret as a binary (not a string),
get_secret_valuereturnsSecretBinaryinstead ofSecretString. Check which type you stored. - In the JSON response, make sure you access
SecretStringor usejson.loadsonly if the value is JSON; otherwise, it's just a plain string.
Rotation fails
- Automatic rotation requires a Lambda function with proper permissions. Common issues: missing
secretsmanager:PutSecretValueandsecretsmanager:GetSecretValueon the rotation Lambda's role, or incorrect VPC configuration. - For manual rotation, always test the new secret value before updating — you could break your app if the new value is wrong.
Cost concern
- Secrets Manager charges per secret per month (currently $0.40). If you have hundreds of secrets, consider consolidating or using SSM Parameter Store for non-critical data.
Pro tip: Use the
--secret-stringflag with a JSON object when you have multiple values (username, password, host). This avoids creating multiple secrets and simplifies your code.
What you learned & what's next
You now know how to store secrets with AWS Secrets Manager: you create a secret, secure it with IAM, retrieve it at runtime with boto3, and optionally automate rotation. You also understand when Secrets Manager beats simple environment variables or Parameter Store, and you can troubleshoot the most common pitfalls.
Next in the track: Now that you can securely manage secrets, you're ready to combine this with a compute service like Lambda or EC2. In the next lesson, you'll learn how to deploy a simple AWS Lambda function and use Secrets Manager to pass a database credential without ever exposing it in your code. This is a classic pattern for building secure, serverless backends.
Keep practicing — your secrets should never live in your code again.
Practice recap
Try creating a new secret for a fake API key with the AWS CLI, then write a Python script that retrieves it and prints its length. Next, attach an IAM policy that denies GetSecretValue for that secret and confirm your script fails with AccessDeniedException. This hands-on exercise will solidify your understanding of the retrieve-and-authorize flow.
Common mistakes
- Hardcoding secrets in source code or
.envfiles and committing them to Git — always use Secrets Manager for anything that isn't purely local and throwaway. - Forgetting that secrets are regional — you'll get
ResourceNotFoundExceptionif you look up a secret from a different AWS region. - Granting
secretsmanager:GetSecretValueto all users or roles — use the least-privilege principle and scope the policy to the specific secret ARN. - Incorrectly parsing the secret: if you stored a plain string, you don't need
json.loads, and if you stored binary data, useSecretBinaryinstead ofSecretString. - Trying to rotate a secret without setting up the required Lambda function and permissions — rotation will fail with cryptic errors.
Variations
- Use AWS SDK for Python (boto3) with
get_secret_valueto fetch secrets in your app code, or rely on service integrations (e.g., Lambda environment variables with Secrets Manager as source) for higher-level convenience. - Store secrets as JSON objects for structured data (credentials, endpoints) or as plain strings for simple tokens; each has its own parsing approach.
- Consider SSM Parameter Store with
SecureStringas a cheaper alternative if you don't need automatic rotation or fine-grained auditing.
Real-world use cases
- A Python Flask app on EC2 retrieves database credentials from Secrets Manager at startup so passwords never appear in code or configs.
- A serverless Lambda function needs an API key from a third-party service; it fetches it from Secrets Manager inside the handler, enabling key rotation without redeploying.
- A CI/CD pipeline uses Secrets Manager to inject production secrets into deployment steps, keeping them out of logs and environment variables in the pipeline configuration.
Key takeaways
- Never hardcode secrets — use AWS Secrets Manager to centralize, encrypt, and control access.
- Secrets Manager works with IAM policies to grant only the necessary roles access to specific secrets.
- Retrieve secrets at runtime with
boto3.client('secretsmanager').get_secret_value()— your code only references the secret name/ARN. - Automatic rotation is possible for supported services; for custom secrets, use
update-secretto rotate manually. - Compare cost and features with SSM Parameter Store — Secrets Manager is optimal for production secrets that need rotation and auditing.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.