Pakkit.net
← Back to blog

Security

Where Encryption Belongs in Your Stack

Disk encryption and field-level encryption both say "the data is encrypted," but they defend against completely different attackers — so the right question isn't whether to encrypt, it's which layer, against whom.

  • Security
  • Encryption
  • Threat Modeling
  • Databases

“Is the data encrypted?” is a question that sounds like it has a yes/no answer and doesn’t. I once dug into whether a system should move its encryption from the application layer down to the disk layer, expecting a performance verdict. The performance part was easy. The real answer was that the two approaches protect against different attackers, and which one is “right” depends entirely on who you’re afraid of. Encryption isn’t a checkbox you tick; it’s a layer you choose, and the layer is the whole decision.

Same word, different attackers

Take two common options. Full-disk encryption (dm-crypt/LUKS and friends) encrypts the bytes as they hit the disk. Field-level encryption encrypts specific sensitive values inside the application before they’re ever stored. Both can truthfully be described as “encrypted at rest.” Here’s what each actually stops:

ThreatDisk encryptionField-level encryption
Someone steals the physical disk or a VM snapshotProtected — ciphertext on diskProtected
Someone has valid database credentials and runs a queryNot protected — the database hands back plaintextProtected — they get ciphertext
An operator with root on the boxDepends on key custodyProtected — the value is encrypted above their layer

Read that middle row twice, because it’s the one people miss. Disk encryption does nothing against an attacker who has legitimate credentials and just asks the database nicely — the storage engine decrypts on read and serves plaintext, exactly as designed. If your threat model includes stolen credentials or a curious operator, disk encryption is not the control you think it is.

Disk encryption protects the data when the disk leaves the building. It does nothing when the attacker comes in the front door with a valid login.

Pick the layer from the threat, then accept its cost

Once you frame it as “who am I defending against,” the choice falls out:

  • If the requirement is “data at rest must be encrypted” for compliance — i.e. the threat is a lost disk or a leaked snapshot — disk encryption is the better tool. It’s nearly free on modern CPUs (hardware AES means most of the cost disappears, and cached reads never touch the cipher at all), it uses standard, audited key management, and it doesn’t distort your data model.
  • If the requirement is “even an operator must not read these values in plaintext” — the threat is someone inside the trust boundary — then you need encryption above the storage layer: application-side authenticated encryption with per-record randomness and a real key management service. Disk encryption can’t help here no matter how fast it is.

And field-level encryption isn’t free, which is the honest other half. Encrypting a column means the database only ever sees ciphertext for it — so you lose the ability to index it, range-query it, or search it. You’ve traded queryability for confidentiality on that field. Sometimes that’s exactly right; sometimes it quietly breaks half your access patterns and you find out later. Decide it on purpose.

The home-rolled-crypto trap

The thing that pushed me to write this down was seeing what happens when field-level encryption is hand-rolled instead of using a real primitive. The failure modes cluster:

  • A weak cipher mode (textbook ECB, say) that leaks patterns — identical plaintext produces identical ciphertext, so the “encrypted” column quietly reveals which rows match.
  • A key embedded in the code that runs everywhere the code runs — which means the key is now on every node and in every backup, so the encryption protects against exactly nobody who can read the code or a backup.
  • No constant-time guarantees, hand-rolled lookups, and a key-rotation story that amounts to “re-encrypt all the data and migrate the schema.”

The lesson isn’t “field-level encryption is bad” — it’s that crypto you wrote yourself usually defends against a threat model of “someone who isn’t looking.” Use vetted libraries and a real key store, or you’ve built something that reads as encrypted and behaves as obfuscation. This is the practical edge of why encryption is a threat-model question, not a feature you bolt on.

Key custody is the decision behind the decision

Whichever layer you pick, the keys have to live somewhere, and that choice is half the security. For disk encryption on a fleet, network-bound unlock (a server hands out the unlock key when a node can reach it on a trusted network) or TPM-sealed keys let machines boot unattended without a passphrase prompt on every reboot — while keeping the disk useless if it’s carried off. For field-level, the key belongs in a dedicated key management service or HSM, deliberately separated from the data and the people who can query it. A key sitting next to the data it protects — or worse, inside the code that reads it — is custody theater. The whole value of encryption collapses to wherever the key is reachable from.

So the next time someone asks “is it encrypted?”, push back with “against whom?” Stolen hardware, stolen credentials, and a privileged insider are three different adversaries, and they want three different controls. Choosing the layer is the security work; “encrypted: yes” is just the part that fits in a status field. It’s the same security-as-design thinking I keep coming back to in security is architecture, not decoration. If you’re weighing where to put encryption in your own stack, I’m happy to talk it through.