Why “What do you use for secrets?” has no single right answer
Secret-management comparison posts are everywhere, but after reading them you end up right back where you started. Feature tables give Vault an overwhelming number of checkmarks, so it feels like you should adopt Vault—except your team has maybe 30 secrets and 1.5 infrastructure people.
The problem is the comparison criteria. The real cost of choosing a tool is monthly infrastructure bill + ops labor + recovery time when something breaks, yet most comparison tables don’t even calculate the first item. If a 30-secret team stands up a 3-node Vault HA cluster, the labor spent documenting unseal procedures and rehearsing Raft snapshot recovery will dwarf the EC2 bill.
This post judges the three tools on these criteria only:
- Scenario-by-scenario monthly bills, with the formulas shown as-is
- Blast radius when an incident hits at 3 a.m.
- What evidence you can submit in an ISMS-P audit
If you want a deeper look at Kubernetes integration architecture itself, see How to Fully Manage Kubernetes Secret Security Vulnerabilities with Vault and the CSI Driver and Kubernetes Secret Management: Vault vs AWS Secrets Manager Comparison and Optimal Architecture Guide. This post focuses on money and people, not architecture.
These three are different kinds of things to begin with
First thing to get straight: SOPS is not a secret store; it is an encryption format. Vault and ASM are “servers that store secrets and serve them over an API,” while SOPS is “a CLI tool that encrypts only the value portions of YAML/JSON files.” Storage is your Git repository’s job. Miss this difference and the comparison doesn’t even hold.
| Axis | HashiCorp Vault | AWS Secrets Manager | SOPS + age |
|---|---|---|---|
| Central server | Required (self-hosted or HCP) | Managed; no server ops | No server (files + Git) |
| Dynamic secrets | Supported (DB/cloud credentials issued with TTL) | Not supported (static values + rotation) | Not supported |
| Audit logs | audit device (file/syslog/socket) | CloudTrail events | Substituted by Git commit history |
| Automatic rotation | Built-in (per-engine rotate) | Lambda-based rotation | Manual (re-encrypt then commit) |
| K8s integration | Vault Agent Injector sidecar injection / Secrets Store CSI Driver | External Secrets Operator polls and creates Secrets | kustomize-sops decrypts at build time |
| Multi-cloud | Cloud-neutral | AWS-bound | Cloud-neutral (choose KMS or age) |
The decisive axis that splits the field is dynamic secrets. If you actually need “issue a one-hour DB login at request time and auto-revoke it,” there is effectively no choice besides Vault. If you don’t have that requirement, a large share of Vault’s feature-table advantage is value that never gets billed to your team.
Monthly cost: unit prices and formulas, shown as-is
Pricing snapshot: August 2026 / region: Seoul (ap-northeast-2) / on-demand. AWS unit prices can change, so reconfirm on the official AWS pricing page before making a final decision.
The core formulas are three lines:
- AWS Secrets Manager:
secret count × $0.40 + (API calls ÷ 10,000) × $0.05 - SOPS + age: If you also use KMS,
number of keys × $1.00+ decrypt API call cost. Using age keys only, infrastructure cost is $0 - Vault self-hosted:
EC2 instance + EBS + NLB+ ops labor (hours/month × hourly rate)
Splitting ops labor into its own row is the point of this calculation. For convenience, hourly rate is set at ₩50,000 (about $36). Plug in your team’s actual labor cost and recalculate. The ops hours in the tables (8 hours/month and so on) are also illustrative assumptions, not measurements; the conclusion only holds once you replace them with your team’s own time logs.
Scenario 1: 30 secrets / 50,000 API calls / 3 developers
| Item | Vault (self-hosted, single node) | AWS Secrets Manager | SOPS + age |
|---|---|---|---|
| Infrastructure | 1× t3.small ≈ $19 + 20 GB EBS ≈ $2 | $0 | $0 |
| Secrets/API | - | 30 × $0.40 = $12 + (50,000÷10,000)×$0.05 = $0.25 → $12.25 | $0 |
| Ops labor | 8 hours/month × $36 = $288 | 1 hour/month = $36 | 1 hour/month = $36 |
| Monthly total | ≈ $309 | ≈ $48 | ≈ $36 |
At 30 secrets, Vault’s ops labor ($288) is 13× the infrastructure cost ($21). Standing up Vault in this range is clearly over-investment.
Scenario 2: 300 secrets / 2 million API calls / 15 services
| Item | Vault (HA, 3 nodes) | AWS Secrets Manager | SOPS + age |
|---|---|---|---|
| Infrastructure | 3× t3.medium ≈ $114 + EBS ≈ $9 + NLB ≈ $20 → $143 | $0 | $0 |
| Secrets/API | - | 300 × $0.40 = $120 + (2,000,000÷10,000)×$0.05 = $10 → $130 | $0 |
| Ops labor | 20 hours/month × $36 = $720 | 4 hours/month = $144 | 16 hours/month = $576 |
| Monthly total | ≈ $863 | ≈ $274 | ≈ $612 |
This is where it flips. SOPS infrastructure stays $0, but once you pass 300 secrets and 15 services, the burden of managing “who can decrypt what with which key” via creation_rules in .sops.yaml grows sharply. When a developer joins or leaves, you remove their key from the age recipient list and re-encrypt every file—and that work scales with the number of files.
There is no single break-even secret count. Set the two monthly costs equal and you get:
N × $0.40 + (monthly API calls ÷ 10,000) × $0.05 = (SOPS ops hours − ASM ops hours) × hourly rate
With Scenario 2’s assumptions (SOPS 16 h, ASM 4 h, $36/h, 2M API calls) the right side is $432 and the left is N × $0.40 + $10, so ASM stays cheaper until N ≈ 1,055. If the ops-time gap is only 2 hours a month, the right side is $72 and SOPS becomes cheaper above N ≈ 155. The answer is far more sensitive to the ops-time gap than to the secret count, so log the time you actually spend adding, removing and re-encrypting keys for a month and plug that in.
Scenario 3: 1,000 secrets / multi-region, multi-cloud
| Item | Vault (HA 3 nodes × 2 regions) | AWS Secrets Manager (replication) | SOPS + age |
|---|---|---|---|
| Infrastructure | ≈ $290 | $0 | $0 |
| Secrets/API | - | 1,000 primaries × $0.40 = $400 + 1,000 replicas × $0.40 = $400 (each replica is billed as a separate secret) + API cost → $800+ | $0 |
| Ops labor | 40 hours/month = $1,440 | 8 hours/month = $288 | Effectively unmanageable |
| Monthly total | ≈ $1,730 | ≈ $1,090+ | Not recommended |
The replica charge comes from the AWS Security Blog’s cross-Region replication post (“each replica secret is billed as a separate secret”); unit prices follow AWS Secrets Manager pricing.
In this range SOPS drops out not on cost but on operability. If you are AWS-only, ASM is still cheaper; if you are multi-cloud or dynamic credentials are mandatory, Vault’s $1,730 is justified.
Beyond money: learning curve and blast radius
| Item | Vault | AWS Secrets Manager | SOPS + age |
|---|---|---|---|
| Initial setup time | Several days for HA | Half a day (including ESO) | 30 minutes |
| Seal operations | Unseal keys must be stored separately; Auto-unseal (KMS) strongly recommended | N/A | N/A |
| Blast radius on failure | Vault seal → all new deploys and restarts stop | ESO sync fails during an AWS region outage (existing Secrets remain) | No impact on already-deployed workloads (decrypt at build time) |
| Backup & recovery | Raft snapshot save/restore rehearsal required | Managed; recoverable within the deletion waiting period | Backing up the age private key is everything (if lost, nothing is recoverable) |
| Failure mode | Operator error (seal, token expiry, policy mistakes) | Permissions/limits (IAM, throttling) | Key loss (irreversible) |
On blast radius alone, SOPS is the safest. Decryption finishes in the deploy pipeline, so there is no runtime dependency. Vault has the largest runtime dependency, which is why Auto-unseal is not optional—it is effectively mandatory. If you run with manual unseal, a 3 a.m. incident means waking three people who each hold one of three unseal key shares at the same time.
Vault’s BSL switch: when it matters and when it doesn’t
In August 2023, HashiCorp changed the license of its major products from MPL 2.0 to the BSL (Business Source License). A community fork, OpenBao, later launched under the Linux Foundation and continues development under an MPL-family license.
The decision rule is surprisingly simple.
- Doesn’t apply: You install Vault internally to manage in-house secrets for your own services → ordinary internal use is not restricted by BSL. Most startups and mid-size companies fall here.
- Needs review: You offer secret-management as a service to customers on top of Vault, or resell it as a core feature of a SaaS product → this can fall under HashiCorp’s “competitive product” interpretation, so legal review is required.
Final interpretation of the license terms must follow the original text and legal review. This section only sketches the direction; confirm against the BSL text and in-house counsel before adopting. If license risk bothers you but you still need Vault’s dynamic secrets, OpenBao is a practical alternative.
Mapping to ISMS-P cryptographic-key management controls
Evidence commonly requested in Korean certification audits is “key generation, storage, rotation, and destruction history” plus “access-control records.”
| Required evidence | Vault | AWS Secrets Manager | SOPS + age |
|---|---|---|---|
| Access records | audit device JSON logs (requester, path, timestamp) | CloudTrail events (GetSecretValue, etc.) | Git commit log (who changed what, when) — no read/access log |
| Key rotation history | Rotation logs + versions | Version stamps + rotation history | Re-encryption commit history |
| Separation of duties | policy documents | IAM policies + resource policies | .sops.yaml creation_rules |
SOPS’s weakness is clear: it cannot record who read a secret. You have change history, not access history. If an audit item requires read-audit evidence, SOPS alone is likely insufficient—check the original control language first.
On region and support, AWS Secrets Manager is available in Seoul (ap-northeast-2) and offers Korean documentation plus Korean-language response via paid support plans. Vault and SOPS are community-centric; official docs are English-first.
Decision table: five questions
| # | Question | Yes → | No → |
|---|---|---|---|
| 1 | Must DB credentials be issued with a TTL at request time? | Vault / OpenBao | Go to 2 |
| 2 | Multi-cloud or on-prem in parallel? | Vault / OpenBao | Go to 3 |
| 3 | AWS-only, and ASM comes out cheaper in the break-even formula above? | ASM + ESO | Go to 4 |
| 4 | Want manifests and secrets together in Git (GitOps)? | SOPS + age | Go to 5 |
| 5 | Is submitting read audit logs for secrets mandatory? | ASM (CloudTrail) | SOPS + age |
There is also a realistic hybrid: keep application config in Git with SOPS, and put only rotation-needed items like DB passwords in ASM. ASM charges only for the secrets stored in ASM, so this cuts cost when only part of your secrets need rotation.
Do this today: five steps to encrypt .env with SOPS
# 1. age (never commit the private key)
mkdir -p ~/.config/sops/age
age-keygen -o ~/.config/sops/age/keys.txt
# On macOS sops defaults to ~/Library/Application Support/sops/age/keys.txt, so point it at this path
export SOPS_AGE_KEY_FILE=~/.config/sops/age/keys.txt
# 2. check the public key (age1... when )
grep "public key" ~/.config/sops/age/keys.txt
# 3. .sops.yaml — multiple recipients in case a key is lost
cat > .sops.yaml <<'EOF'
creation_rules:
- path_regex: secrets/.*\.yaml$
age: >-
age1abc...A,
age1def...backup
EOF
# 4. YAML ( , )
sops -e secrets/prod.yaml > secrets/prod.enc.yaml && rm secrets/prod.yaml
# 5.
git add .sops.yaml secrets/prod.enc.yaml && git commit -m "chore: encrypt prod secrets with SOPS"Expected result: open secrets/prod.enc.yaml and the key names are readable, values have become ENC[AES256_GCM,data:...], and a sops: metadata block is appended at the bottom. If values are still plaintext, path_regex in .sops.yaml doesn’t match the actual path—fix the path pattern first.
To verify decryption: sops -d secrets/prod.enc.yaml. no matching creation rules appears when encrypting (sops -e) a path that no path_regex matches. failed to get the data key on decrypt means sops could not find the private key. The defaults are ~/.config/sops/age/keys.txt on Linux and ~/Library/Application Support/sops/age/keys.txt on macOS (when XDG_CONFIG_HOME is unset); anywhere else, set SOPS_AGE_KEY_FILE (SOPS age docs).
If you use ASM: minimal ESO YAML
external-secrets.io/v1 is available from ESO v0.16.2, and v0.17.0 stopped serving v1beta1 (v0.17.0 release notes). Older v1beta1 examples will not apply on current ESO.
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata:
name: aws-secretsmanager
namespace: prod
spec:
provider:
aws:
service: SecretsManager
region: ap-northeast-2
auth:
jwt:
serviceAccountRef:
name: external-secrets-sa
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: app-db-secret
namespace: prod
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secretsmanager
kind: SecretStore
target:
name: app-db-secret
data:
- secretKey: DB_PASSWORD
remoteRef:
key: prod/app/db
property: passwordAfter applying, if kubectl get externalsecret -n prod shows STATUS SecretSynced, you’re good. If you see SecretSyncedError, first check that the IRSA service account has secretsmanager:GetSecretValue.
Failure-path checklist (three cases)
1. Vault is sealed and deploys are fully stopped
vault status # Sealed: true check
vault operator unseal <key-share-1>
vault operator unseal <key-share-2>
vault operator unseal <key-share-3> # thresholdPrevention is switching to KMS Auto-unseal. After you configure it, a restart unseals without human intervention.
seal "awskms" {
region = "ap-northeast-2"
kms_key_id = "arn:aws:kms:ap-northeast-2:<account-id>:key/<key-id>"
}2. You lost the age private key
There is no recovery. Prevention is the only answer. Specify multiple recipients at encrypt time.
sops -e --age "age1<dev-key>,age1<backup-key>,age1<ci-key>" secrets/prod.yaml > secrets/prod.enc.yaml
# Add a recipient to an already-encrypted file: add the new public key to .sops.yaml first, then run
sops updatekeys secrets/prod.enc.yamlTo remove a recipient (someone leaving), delete the key from .sops.yaml, run sops updatekeys, then sops rotate --in-place to replace the data key (SOPS key management). Old ciphertext in Git history can still be opened with the removed key, so rotate the secret values that person could see.
3. You deleted an ASM secret and cannot recreate it under the same name
ASM schedules deletion with a recovery window (30 days by default, configurable from 7 to 30), and a name in that window cannot be reused. If the secret has replicas, remove them first. After a forced delete, aws secretsmanager describe-secret --secret-id prod/app/db returning ResourceNotFoundException confirms it (there is a short delay).
#
aws secretsmanager restore-secret --secret-id prod/app/db --region ap-northeast-2
# when after — ,
aws secretsmanager delete-secret --secret-id prod/app/db \
--force-delete-without-recovery --region ap-northeast-2FAQ
Q. At what secret count should you move to AWS Secrets Manager?
A. There is no fixed count. On infrastructure alone SOPS is always cheaper; once ops time is included, the break-even formula above decides. At 150 secrets, for example, ASM costs 150 × $0.40 = $60, so if SOPS key management and re-encryption take about 1.7 more hours a month than ASM (at $36/h), ASM is cheaper.
Q. Do we have to rip out Vault because of the BSL change? A. Internal use for running your own services is generally fine. Legal review is needed only if you provide or resell secret-management to customers on top of Vault. If you want to avoid license risk entirely, the OpenBao fork is the alternative.
Q. Can SOPS alone pass ISMS-P cryptographic-key management controls? A. You can submit change history (Git commits), but there is no read history. If a control requires access/read audit, SOPS alone may not be enough. Check the original control language and, if needed, consider pairing ASM (CloudTrail) or a Vault audit device.
Sources and checks vary by article. Only articles with a recorded check date, scope and sources below were checked, and only within that scope. For other articles, verify against the current docs for your version before applying anything, and email us about errors. Editorial policy · email us
This article has no recorded human check (date and scope) yet.
Comments
Be the first to comment.