Encryption at Rest
debt(d7/e7/b7/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints list semgrep and trufflehog, but automated detection is explicitly marked 'no'. These tools can spot plaintext sensitive columns or keys co-located with data in some patterns, but reliably identifying missing or misconfigured encryption-at-rest (e.g., unencrypted backups, keys stored in the same DB, no key rotation) requires careful manual code and infrastructure review rather than routine automated scanning.
Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix mentions AES-256-GCM with a secrets manager and annual key rotation, but the common_mistakes reveal that correct remediation touches DB schema (column-level encryption), application code (encrypt/decrypt at write/read), backup pipelines, key management infrastructure, and key rotation logic. This is not a single-component fix — it spans multiple layers and services, making it a cross-cutting refactor.
Closest to 'strong gravitational pull' (b7). Encryption at rest applies to web, CLI, and queue-worker contexts. Every new feature that handles sensitive data must integrate with the encryption/decryption path and the secrets manager. Key rotation, per-row key strategies, and backup encryption policies impose an ongoing productivity tax across many work streams. The choice shapes how every data-handling component is written going forward.
Closest to 'serious trap — contradicts how a similar concept works elsewhere' (t7). The canonical misconception is that TDE (database-level encryption) is sufficient for compliance. Developers who understand disk-encryption as the threat model naturally assume TDE covers all bases, but TDE does not protect against a compromised database user. Column-level application encryption is required for sensitive fields — the 'obvious' assumption that enabling TDE satisfies GDPR/PCI-DSS/HIPAA is wrong in the most common threat scenario.
Also Known As
TL;DR
Explanation
Encryption at rest operates at different layers: full-disk encryption (LUKS, BitLocker), filesystem encryption, database-level transparent data encryption (TDE), and application-level column encryption. Each layer protects against different threats. Full-disk encryption protects against physical drive theft but not against a running compromised server. Application-level encryption protects specific sensitive columns even if the database itself is compromised. Key management is the hard part — encrypted data is only as secure as its key storage.
Diagram
flowchart TD
DATA[Sensitive data] --> ENCRYPT{Encryption layer}
subgraph Options
DISK[Disk encryption<br/>LUKS FileVault<br/>transparent to app]
DB[DB column encryption<br/>app controls keys]
APP2[Application-level<br/>encrypt before storing]
end
ENCRYPT --> DISK & DB & APP2
subgraph Key_Management
KMS[KMS - Key Management Service<br/>AWS KMS HashiCorp Vault]
ROTATE[Key rotation<br/>without re-encrypting all data]
KMS --> ROTATE
end
style DISK fill:#1f6feb,color:#fff
style DB fill:#238636,color:#fff
style APP2 fill:#6e40c9,color:#fff
style KMS fill:#d29922,color:#fff
Common Misconception
Why It Matters
Common Mistakes
- Storing encryption keys next to the encrypted data in the same database — a database breach exposes both.
- Using application-level encryption without key rotation — a compromised old key means all historical data is exposed.
- Not encrypting backups — encrypted primary storage with unencrypted backups negates the protection.
- Using the same key for all rows — individual key compromise exposes all data; consider per-row or per-user keys for sensitive fields.
Code Examples
-- Storing sensitive data unencrypted + key in same table:
CREATE TABLE user_payment_methods (
id INT PRIMARY KEY,
user_id INT,
card_number VARCHAR(16), -- Plaintext PAN — PCI violation
card_cvv VARCHAR(4), -- Should never be stored
encryption_key VARCHAR(64) -- Key next to data — defeats purpose
);
-- Application-level column encryption:
CREATE TABLE user_payment_methods (
id INT PRIMARY KEY,
user_id INT,
card_number_encrypted BYTEA NOT NULL, -- AES-256-GCM encrypted
card_number_last4 CHAR(4) NOT NULL, -- For display only
key_version INT NOT NULL -- Enables key rotation
);
-- Keys stored in HSM or secrets manager (Vault, AWS KMS)
-- Never in the same database