Skip to content

Cybersecurity · Secrets & Credentials

Secrets Management in 2026: Vault, Doppler, AWS Secrets Manager, and When .env Is Fine

Leaked credentials are the most preventable category of security breach. Here is an honest look at when you need a dedicated secrets manager, which tool to pick, and what to do if you're still on .env files.

Anurag Verma

Anurag Verma

10 min read

Secrets Management in 2026: Vault, Doppler, AWS Secrets Manager, and When .env Is Fine

Sponsored

Share

In February 2025, a developer at a fintech startup accidentally pushed their .env file to a public GitHub repository. The file contained API keys for their payment processor, database credentials, and an admin token for their cloud provider. By the time the push was caught — 11 minutes later — automated scanners had already harvested the credentials. The breach cost the company two weeks of incident response and a complete infrastructure rebuild.

This is not an unusual story. GitHub’s own secret scanning system detected over 39 million exposed secrets in public repositories in 2023 alone, according to their State of the Octoverse report. The category of breach “leaked credentials” shows up in virtually every annual security report as a leading initial attack vector. And it’s one of the most preventable problems in software security.

Secrets management is the discipline of handling credentials — API keys, database passwords, private certificates, OAuth secrets — in a way that doesn’t leave them sitting in files, environment variables, or source code where they can be accidentally exposed.

Here is what the options actually look like and how to pick one that fits where you are.

The .env File Reality

Let’s start here because most teams are on .env files and the advice to “never use .env” is not actionable.

.env files are not inherently dangerous. They become dangerous when:

  • They’re committed to version control (even accidentally, even briefly)
  • They’re copied between machines without access controls
  • They’re readable by everyone with shell access to the server
  • There’s no rotation process when a secret is compromised

If you’re in a solo project or a two-person team, properly used .env files with clear guardrails are an acceptable starting point:

# .gitignore — this should be the first thing in every repo
.env
.env.local
.env.*.local
*.env

# Show what variables are needed without the values
# Commit this file
.env.example:
DATABASE_URL=
STRIPE_SECRET_KEY=
SENDGRID_API_KEY=
JWT_SECRET=

The .env file that stays out of git, on machines accessed by authorized people, with clear ownership of who rotates secrets when someone leaves — that’s manageable. It’s not ideal for anything beyond small-scale, but it’s not a crisis.

The moment you need to scale past that — more team members, multiple environments, shared infrastructure, compliance requirements — you need proper secrets management.

What Proper Secrets Management Actually Provides

Before evaluating tools, know what you’re buying:

Centralized storage: Secrets live in one place with access controls, not scattered across .env files on different machines.

Access control: Define which service, which person, or which CI job can read which secret. Audit who read what and when.

Rotation: Secrets can be rotated (changed) without touching application code or redeploying. Critical for responding to a credential leak.

Versioning: Keep historical versions of secrets for rollback if a rotation breaks something.

Dynamic secrets: Some tools (Vault) can generate short-lived credentials on demand — a database password that exists for 5 minutes and then expires. Even if leaked, it’s useless.

Integration with your runtime: Inject secrets into containers, Lambda functions, or CI jobs at runtime rather than at deploy time.

HashiCorp Vault

Vault is the most feature-complete secrets manager available. It handles every use case — static secrets storage, dynamic credentials for databases and cloud providers, PKI management, encryption as a service, and SSH certificate signing. If you need something from secrets infrastructure, Vault can probably do it.

What it’s genuinely good at:

Dynamic secrets are Vault’s best feature. Instead of a static database password that’s rotated monthly, Vault generates a unique credential when a service requests it, with an automatic expiry. The service gets credentials for the lifetime of its request, and then they’re gone.

# Vault dynamic database credential example
# Enable the database secrets engine
vault secrets enable database

# Configure a postgres connection
vault write database/config/my-postgres \
  plugin_name=postgresql-database-plugin \
  connection_url="postgresql://{{username}}:{{password}}@localhost:5432/mydb" \
  allowed_roles="my-role" \
  username="vault-admin" \
  password="admin-password"

# Create a role that generates credentials
vault write database/roles/my-role \
  db_name=my-postgres \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
  default_ttl="1h" \
  max_ttl="24h"

# Application requests credentials at runtime
vault read database/creds/my-role
# Returns a username/password that expire in 1 hour

What it costs:

Vault requires meaningful operational investment. You’re running a stateful service that your entire infrastructure depends on. The Vault cluster needs high availability, backup, and monitoring. A Vault outage means applications can’t fetch new credentials — which may mean they can’t start. HCP Vault (HashiCorp’s hosted offering) removes some of this burden, but it’s not cheap.

The learning curve is real. Vault has a policy language (HCL), an auth method configuration, and a secrets engine architecture that takes time to get right. Setting up Vault correctly for a production environment is a week of work, not an afternoon.

Who it’s for: Teams with significant security requirements, compliance obligations that specify secrets management controls, or organizations already running Kubernetes who can use the Vault Secrets Operator. The Vault Secrets Operator syncs secrets into Kubernetes Secrets automatically, which removes the need for applications to know about Vault at all.

AWS Secrets Manager (and Parameter Store)

If you’re already on AWS, Secrets Manager is often the right default. It integrates with IAM for access control, CloudTrail for audit logging, and Lambda/ECS/EKS for runtime injection.

AWS Secrets Manager vs. Parameter Store:

AWS has two relevant services and the distinction matters:

Secrets ManagerParameter Store
Cost$0.40/secret/month + $0.05/10k API callsFree for Standard tier; $0.05/parameter/month for Advanced
RotationBuilt-in rotation with Lambda functionsManual
Secret sizeUp to 65KBUp to 8KB (Advanced)
Use caseCredentials, API keys, tokensConfig values, feature flags, secrets
Cross-accountYesLimited

For most teams on AWS, use Parameter Store for configuration and Secrets Manager for actual credentials that need rotation.

# boto3: fetch secret at application startup
import boto3
import json

def get_secret(secret_name: str) -> dict:
    client = boto3.client('secretsmanager', region_name='us-east-1')
    response = client.get_secret_value(SecretId=secret_name)
    return json.loads(response['SecretString'])

# In practice, cache this at startup — don't call on every request
db_creds = get_secret('production/myapp/database')
DATABASE_URL = f"postgresql://{db_creds['username']}:{db_creds['password']}@{db_creds['host']}/mydb"

For ECS and Lambda, you can inject Secrets Manager values directly into environment variables at task/function definition time, so application code doesn’t need to know about Secrets Manager at all:

{
  "containerDefinitions": [{
    "name": "api",
    "secrets": [
      {
        "name": "STRIPE_SECRET_KEY",
        "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789:secret:production/stripe-key"
      }
    ]
  }]
}

What it costs: Financially modest for most scales. Operationally, much lighter than Vault — AWS manages the infrastructure. The main downside is AWS lock-in. If you move clouds, Secrets Manager doesn’t come with you.

GCP has Secret Manager and Azure has Key Vault with nearly identical capabilities for their respective ecosystems.

Doppler

Doppler is a developer-experience-first secrets management SaaS. Where Vault prioritizes capability and AWS Secrets Manager prioritizes AWS integration, Doppler prioritizes making secrets management not annoying.

The core model: you define secrets in the Doppler dashboard, organized by project and environment (dev/staging/production). Applications fetch their secrets via the Doppler CLI or SDK. The CLI can inject secrets as environment variables at process startup, so existing applications work without code changes:

# Run your app with secrets injected as environment variables
doppler run -- node server.js

# Or generate a .env file for local development (not committed to git)
doppler secrets download --no-file --format env > .env

Doppler handles CI/CD integration natively — there are official GitHub Actions, GitLab integrations, and plugins for CircleCI, Jenkins, and most other CI systems. Rotating a secret means updating it in Doppler; the next deployment or process restart picks up the new value.

The tradeoff: Doppler is a third-party SaaS dependency. Your secrets are stored in Doppler’s infrastructure. For most teams this is acceptable — Doppler is SOC 2 Type II certified and has good uptime history — but it’s a meaningful consideration for organizations with strict data residency requirements.

Who it’s for: Teams that want a significant improvement over .env files with minimal operational overhead. Good default for startups and agencies managing multiple client projects, since the project/environment model maps well to multi-tenant workflows.

The Kubernetes-Specific Path

If you’re on Kubernetes, a few additional options are worth knowing:

External Secrets Operator (ESO): Syncs secrets from any secrets manager (Vault, AWS Secrets Manager, GCP Secret Manager, Doppler, and more) into Kubernetes Secrets. Applications read standard Kubernetes Secrets; ESO handles the syncing from the backend.

# ESO: sync an AWS Secrets Manager secret into a Kubernetes Secret
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: database-credentials
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: ClusterSecretStore
  target:
    name: database-credentials
  data:
  - secretKey: DATABASE_URL
    remoteRef:
      key: production/myapp/database
      property: url

Sealed Secrets: Encrypts secrets using a cluster-specific key so the encrypted form can be committed to git safely. Good for GitOps workflows where you want secrets in the same repository as the rest of your Kubernetes manifests.

Picking a Tool

If you're a solo developer or two-person team:
  → .env with proper .gitignore + secret scanning on your repo
    (GitHub has this built-in; enable it in repo Settings > Code security)

If you're a small team (3-15 people) moving beyond .env:
  → Doppler (fastest to adopt, reasonable cost, good DX)
  → AWS/GCP/Azure Secrets Manager if you're already deep in that cloud

If you're running on Kubernetes:
  → External Secrets Operator + whichever backend fits
  → Vault Secrets Operator if you need dynamic credentials

If you have compliance requirements (SOC 2, HIPAA, PCI):
  → AWS Secrets Manager or Vault with audit logging configured
  → Your compliance framework may specify requirements; check before picking

If you need dynamic credentials or advanced PKI:
  → Vault is the only real answer

Baseline Hygiene Regardless of Tool

Whatever you’re using, these practices apply universally:

Enable secret scanning. GitHub, GitLab, and most CI platforms will scan commits for known secret formats (AWS keys, Stripe keys, etc.). Turn this on. It’s free and catches the “accidental commit” scenario before it’s a breach.

Use service accounts, not personal credentials. Applications should authenticate with a service account or IAM role, not a developer’s personal API key. When that developer leaves, you don’t have to hunt down where their credentials are used.

Set expiry dates. API keys and tokens that don’t expire become permanent attack surface. Audit your existing secrets — you’ll find credentials that haven’t been rotated in years.

Document the rotation procedure. When a credential is compromised, you want to rotate it in under an hour. That’s only possible if the procedure is documented and practiced before the emergency.

Secrets management is a process problem as much as a tooling problem. The best secrets manager in the world doesn’t help if developers work around it because it’s inconvenient. Pick something your team will actually use, and make it the path of least resistance.

Sponsored

Enjoyed it? Pass it on.

Share this article.

Sponsored

The dispatch

Working notes from
the studio.

A short letter twice a month — what we shipped, what broke, and the AI tools earning their keep.

No spam, ever. Unsubscribe anytime.

Discussion

Join the conversation.

Comments are powered by GitHub Discussions. Sign in with your GitHub account to leave a comment.

Sponsored