# Why is keeping the key in .env risky when encrypting sensitive financial data — what do KMS/Vault give you?

> Take the key out of .env, keep it in KMS or Vault and use envelope encryption; for national IDs and card data, prefer tokenization wherever you can.

- Asked: 2026-06-09
- Answered: 2026-06-12
- Asked by: Çağrı
- Tags: veritabani, guvenlik, altyapi
- Source: https://muhammetsafak.com/just-ask/encrypting-sensitive-financial-data-at-rest-and-key-management/
- Language: en-US
- Author: Muhammet Şafak

---
**Question:** We have to keep users' national ID numbers or credit card tokens in the DB encrypted for KVKK/GDPR; an attacker who breaches the DB must not be able to read this data. When using symmetric encryption (AES-256) at the application layer, what are the risks of keeping the encryption key in a `.env` file on the app server?

How does integrating AWS KMS or HashiCorp Vault make the architecture secure?


Short answer: encrypting the field with AES-256 is right, but if the key sits in the `.env` *next to* the app, an attacker who reaches the server gets both the data and the key — the encryption buys you almost nothing. The whole point of KMS/Vault is to separate the key from the data.

## Short answer

The core of the problem: if the encrypted data and the key that opens it sit in the same place, the two are effectively one secret. Security comes from physically/permission-wise decoupling the key from the data. The same "where does the secret live" question shows up in signature verification too; I covered the HMAC and idempotency side of webhooks in [a separate record](/just-ask/webhook-idempotency-and-hmac-for-duplicate-payment-notifications/).

## Why

1. **The key in `.env` is risk concentrated in one spot.** An attacker who takes the server (or causes a backup/`.env` leak) gets the encrypted DB and the key at the same time. The key also sits in plaintext in the file, it's hard to rotate, and there's no trace of who decrypted what and when.

2. **KMS/Vault never hand the master key to the app.** So compromising the DB or a backup doesn't hand over plaintext, because the master key was never there. A compromised app server may still be able to ask KMS to decrypt while the compromise lasts; that is what access scoping and audit logs are for.

3. **"Which service decrypted which data, and when?" becomes answerable.** That's what a compliance (KVKK/GDPR) audit actually asks for; in the `.env` model there is no answer to that question.

## What to do

1. **Move to envelope encryption.** Have the app call KMS to encrypt/decrypt: the master key stays in KMS and encrypts a separate data key per record. What the app stores is only the encrypted data key; when it needs the plaintext, it asks KMS to decrypt it.

2. **Centralize rotation and auditing.** KMS/Vault **rotate** the key centrally, write every decrypt to an **audit** log, and scope access via IAM/policy; turn all three on from day one.

3. **Prefer tokenization for national IDs/card data.** Where possible, don't hold the sensitive value at all: keep the real value in a vault/provider and pass only a **token** around the system. Then the vast majority of the system never sees the sensitive data — even if it leaks, what's taken is a meaningless token.

**Bottom line:** envelope encryption via KMS or Vault; the key never in `.env`, but somewhere that's rotated + audited. Tokenize wherever you can. One more note: full-disk encryption or `pgcrypto` alone isn't enough — a live DB connection still reads plaintext. The real protection comes from separating the key from the data and never giving the app the master key.

## Related Reading

- [How do I set up secretless AWS access in CI/CD with OIDC and IAM roles?](https://muhammetsafak.com/just-ask/secretless-ci-cd-with-aws-iam-roles-and-oidc/) — Just Ask
- [Disaster recovery: how do I design an active-passive scenario around RTO and RPO?](https://muhammetsafak.com/just-ask/disaster-recovery-strategy-setting-rto-and-rpo/) — Just Ask
- [When should I switch to a covering index with INCLUDE to get an index-only scan?](https://muhammetsafak.com/just-ask/switch-covering-index-include-get-index-only-scan/) — Just Ask
