Vault vs AWS Secrets Manager vs Doppler: Secrets Management Compared

go dev.to

Hardcoded credentials in source code remain one of the leading causes of cloud breaches. The fix sounds simple — use a secrets manager — but picking between Vault, AWS Secrets Manager, and Doppler involves real trade-offs in operational complexity, cost, and developer workflow friction.

What You're Actually Comparing

These three tools represent different philosophies, not just different implementations:

  • HashiCorp Vault: open-source, self-hosted (or managed via HCP Vault), feature-rich, with a steep operational learning curve.
  • AWS Secrets Manager: fully managed, deeply integrated with IAM, priced per secret and per API call.
  • Doppler: developer-focused SaaS that treats secrets like environment variables with proper access control.

Comparing them on price alone misses the point. The real questions are: who manages the infrastructure, how granular is your access control, and how painful is onboarding a new developer?

Developer Experience and Setup

Vault requires the most upfront work. You spin up a server (or use vault server -dev locally), choose an auth method (AppRole, Kubernetes, AWS IAM, LDAP...), write policies, and define secret mounts. For teams with dedicated infrastructure engineers, this is manageable. For a three-person startup, it's often overkill.

AWS Secrets Manager has near-zero setup if you're already on AWS. You create a secret via the console or CLI, attach an IAM policy to your service role, and start reading. The friction is the IAM complexity you already have — not something Secrets Manager adds.

Doppler's pitch is "you shouldn't need to read documentation." You sign up, create a project, add secrets in a UI that looks like a spreadsheet, and inject them into your process with doppler run -- python app.py. Secrets are scoped by environment (dev/staging/prod) by default.

Here's how fetching a secret looks in Python for each:

# Vault — using hvac
import hvac, os

client = hvac.Client(url=os.environ["VAULT_ADDR"], token=os.environ["VAULT_TOKEN"])
secret = client.secrets.kv.v2.read_secret_version(path="myapp/db", mount_point="secret")
password = secret["data"]["data"]["password"]
Enter fullscreen mode Exit fullscreen mode
# AWS Secrets Manager — using boto3
import boto3, json

def get_secret(name: str, region: str = "eu-west-1") -> dict:
    client = boto3.client("secretsmanager", region_name=region)
    return json.loads(client.get_secret_value(SecretId=name)["SecretString"])

password = get_secret("prod/myapp/db")["password"]
Enter fullscreen mode Exit fullscreen mode
# Doppler — environment variables injected by the CLI
import os
password = os.environ["DB_PASSWORD"]

# Or programmatically via the REST API
import httpx

def get_doppler_secret(name: str, token: str) -> str:
    resp = httpx.get(
        "https://api.doppler.com/v3/configs/config/secret",
        params={"name": name},
        headers={"authorization": f"Bearer {token}"},
    )
    resp.raise_for_status()
    return resp.json()["secret"]["value"]["raw"]
Enter fullscreen mode Exit fullscreen mode

Secret Rotation and Dynamic Credentials

This is where Vault separates itself from the pack. Vault supports dynamic secrets — instead of storing a fixed password for your database, Vault generates fresh credentials on demand with a configurable TTL. When the lease expires, Vault revokes them automatically. There's no rotation job to write or schedule.

Here's how you'd request dynamic database credentials in Go:

package main

import (
    "context"
    "os"

    vault "github.com/hashicorp/vault-client-go"
)

func getDBCredentials(ctx context.Context) (string, string, error) {
    client, err := vault.New(
        vault.WithAddress(os.Getenv("VAULT_ADDR")),
    )
    if err != nil {
        return "", "", err
    }
    client.SetToken(os.Getenv("VAULT_TOKEN"))

    resp, err := client.Secrets.DatabaseGenerateCredentials(
        ctx,
        "myapp-role",
        vault.WithMountPath("database"),
    )
    if err != nil {
        return "", "", err
    }

    return resp.Data["username"].(string), resp.Data["password"].(string), nil
}
Enter fullscreen mode Exit fullscreen mode

AWS Secrets Manager supports automatic rotation via Lambda. AWS provides ready-made templates for RDS, Redshift, and DocumentDB. It works well within the AWS ecosystem, but rotation is schedule-based rather than on-demand — your app still caches a long-lived secret between rotation events and must handle the brief window when old credentials expire.

Doppler has no built-in rotation mechanism. You update secrets manually or via API, and Doppler syncs the new value to connected integrations (GitHub Actions secrets, Kubernetes Secrets, Vercel env vars, etc.). For static API keys that change infrequently, this is fine. For database passwords or short-lived tokens, you need a rotation layer upstream.

Cost and Operational Overhead

Vault (self-hosted) AWS Secrets Manager Doppler
Base infrastructure Your servers None SaaS (~$6/user/month)
Per-secret cost None $0.40/secret/month None
Per-call cost None $0.05/10k API calls None
Operational burden High Low None
Cross-cloud Yes AWS only Yes
Dynamic secrets Yes No No
Audit logs Yes (audit device) CloudTrail Yes (paid tier)

At 100 secrets and 2M API calls per month on AWS Secrets Manager, you're looking at roughly $50/month before Lambda rotation costs. Self-hosted Vault with HA adds on-call burden for upgrades, unsealing, and disaster recovery on top of your infra bill. Doppler is predictable flat-rate SaaS.

One often-overlooked cost with Vault is the unsealing ceremony after a restart. Without auto-unseal (via AWS KMS, GCP Cloud KMS, or Azure Key Vault), every Vault restart requires quorum from key holders. At 2 AM during an incident, this is painful.

When to Use Each

Choose Vault when:

  • You need dynamic secrets for databases, PKI, or cloud IAM roles
  • You operate multi-cloud or on-premises with strict data residency requirements
  • You have an infrastructure team that can own upgrades, HA, and disaster recovery

Choose AWS Secrets Manager when:

  • Your stack is 100% AWS
  • You want automatic RDS password rotation with no code to maintain
  • Operational simplicity matters more than cost at your secret count

Choose Doppler when:

  • Developer experience is the bottleneck (secrets in .env files, Slack DMs, or worse)
  • You want to sync secrets across environments, CI/CD, and Kubernetes without writing glue code
  • You're a small team and the SaaS operational model is worth the monthly cost

In practice, these tools compose well. Many teams run Vault or Secrets Manager at the infrastructure layer and use Doppler for developer and CI/CD workflows. The environments stay consistent without anyone pasting secrets into config files.

Whatever tool you pick, the fundamentals don't change: least privilege access, audit logging enabled, and a documented rotation schedule. We maintain free security hardening checklists covering secrets management and related controls — useful for validating your setup against concrete criteria.

The Takeaway

Vault is the most powerful option, but power comes with a real operational tax. AWS Secrets Manager is the pragmatic default for AWS-native teams. Doppler is the fastest path to eliminating secrets from .env files without investing in infrastructure.

If you're starting from scratch: Doppler for developer workflows today, with a plan to add Vault or Secrets Manager when dynamic credentials or compliance requirements demand it. Getting secrets out of your codebase matters more than picking the optimal tool on day one.


I run AYI NEDJIMI Consultants, a cybersecurity consulting firm. We publish free security hardening checklists — PDF and Excel.

Source: dev.to

arrow_back Back to Tutorials