AWS Secrets Manager vs Parameter Store vs Environment Variables: When to Use Which

· 8 min read ·
AWSSecurityDevOps

Not every secret belongs in Secrets Manager, and not every config value belongs in an environment variable. The three options— environment variables, SSM Parameter Store, and AWS Secrets Manager sit at different points on a spectrum of cost, operational overhead, and capability. Picking the wrong one either costs more than necessary or leaves a gap in rotation and audit that becomes a compliance problem later.


Environment Variables

Environment variables are the path of least resistance. They’re supported everywhere— Lambda, ECS, EC2, containers, and local dev; which require no AWS setup. For non-sensitive configuration like port numbers, feature flags, log levels, or region identifiers, they’re often the right call.

The problem starts when teams use them for secrets. Environment variables have several failure modes that make them unsuitable for sensitive values:

When Environment Variables Are the Right Choice

If the value would cause harm if leaked— a database password, an API key, a private certificate, then it does not belong in an environment variable.


SSM Parameter Store

SSM Parameter Store is a key-value store with two tiers and two value types.

Tiers:

Value types:

The hierarchical naming convention is Parameter Store’s most useful feature for managing config across environments:

/myapp/production/db-password
/myapp/production/api-key
/myapp/staging/db-password
/myapp/staging/api-key

IAM policies can grant access to an entire path prefix (/myapp/production/*), so a production Lambda only has access to production parameters. Access is logged in CloudTrail, giving an audit trail of who retrieved what and when.

What Parameter Store Doesn’t Do

Parameter Store has no built-in secret rotation. A SecureString parameter is encrypted at rest and access-controlled, but nothing in AWS will automatically rotate it and update the downstream application. Rotation is a manual process or something you build yourself with a Lambda and a scheduled EventBridge rule.

Cross-account access is also limited. Parameter Store doesn’t support resource-based policies, so sharing a parameter with another AWS account requires IAM role assumption— workable, but not clean.

When Parameter Store Is the Right Choice


AWS Secrets Manager

Secrets Manager is purpose-built for secrets that need to rotate. The core capability that distinguishes it from Parameter Store is automatic rotation: Secrets Manager can invoke a Lambda function on a schedule to generate a new secret value, update the downstream resource (an RDS database, a Redshift cluster, a Documentdb instance), and swap the active version— all without application downtime, using staging labels (AWSCURRENT, AWSPENDING, AWSPREVIOUS) to manage the transition.

AWS provides managed rotation Lambda functions for several services out of the box: RDS MySQL, RDS PostgreSQL, RDS Oracle, RDS SQL Server, Amazon Redshift, and Amazon DocumentDB. For other secret types, you write a custom rotation Lambda.

Cost:

Ten secrets cost $4/month before API call charges. At scale — hundreds of secrets — this adds up. For secrets that genuinely need rotation, it’s worth it. For static config values that rarely change, it’s waste.

Cross-Account Access

Unlike Parameter Store, Secrets Manager supports resource-based policies. A secret in Account A can grant access directly to a role in Account B without the consuming account needing to assume a role across the boundary first. This makes Secrets Manager the cleaner option when secrets need to be shared across AWS accounts.

Versioning

Every update to a secret creates a new version. Secrets Manager tracks versions with staging labels:

Applications that retrieve the secret by name always get AWSCURRENT. If rotation produces a bad value, the previous version is still available.

When Secrets Manager Is the Right Choice


Side-by-Side Comparison

DimensionEnvironment VariablesParameter Store (SecureString)Secrets Manager
CostFreeFree (Standard tier)$0.40/secret/month + API calls
Encryption at restNoYes (KMS)Yes (KMS)
Audit trailNoCloudTrailCloudTrail
Automatic rotationNoNoYes (built-in for RDS, custom Lambda)
VersioningNoNo (Advanced tier: parameter policy)Yes (AWSCURRENT/AWSPENDING/AWSPREVIOUS)
Cross-account sharingN/ARole assumption onlyResource-based policy
Console visibilityPlain textMasked (SecureString)Masked
Right forNon-sensitive config, local devStatic secrets, per-env configRotating credentials, compliance

Decision Framework

Does the value contain anything sensitive (password, token, key)?

Does it need to rotate automatically?

Does it need to be shared across AWS accounts?

How many secrets, and how often are they read?

Is there a compliance requirement for rotation audit?


A Common Mistake

Storing database passwords as Lambda environment variables is the most common mistake. It works until the password needs to change— then it’s a redeployment. It works until someone with Lambda console access reads the value. It works until a misconfigured logger writes the environment to CloudWatch.

Database credentials belong in Secrets Manager if they need to rotate, or Parameter Store SecureString if rotation is manual and infrequent. The Lambda retrieves the secret at runtime via the SDK, not from an environment variable. The cost is a few hundred milliseconds on cold start, which is almost always worth the trade.


Closing Thoughts

The practical split: environment variables for non-sensitive config, Parameter Store SecureString for sensitive values that don’t rotate, Secrets Manager for credentials that must rotate or cross account boundaries. The upgrade path is one-way— once compliance asks for rotation audit trails, Parameter Store can’t retrofit that. Starting with Secrets Manager for database credentials from the beginning avoids that migration later.


Further Reading