System designDeep dive11 min
Encryption in transit & at rest
Encryption in transit keeps data private while it moves; encryption at rest keeps it private while it sits on disks and backups. Each protects against specific attackers and not others, and both are only as strong as the handling of their keys.
1 · The map
Data is exposed while it moves, while it is stored and while it is used
A private journaling app has 2 million users writing daily entries, some with photos. One entry travels from a phone, through a load balancer, to an API server, into a database and object storage, and from there into nightly backups. Along that path it can be read in three different states:
In transit, every hop is a separate encrypted connection. At rest, disks and backups hold ciphertext. In use, the API server must see the entry in plaintext to work with it, and storage or transport encryption can't help there.
Each kind of encryption answers a specific attacker, and none answers all of them:
Attacker | Example | What stops them |
|---|---|---|
Someone on the network | Public Wi-Fi, a tapped link between data centers | Encryption in transit (TLS) |
Someone holding the hardware | A disk pulled during maintenance, a lost backup | Encryption at rest |
Someone with the app's access | A stolen admin login, an injection bug in the API | Not encryption at rest: the app decrypts for them. Access control (Authentication & authorization), field-level or end-to-end encryption |
2 · In transit
TLS proves who the server is, then hides and seals everything after
TLS (Transport Layer Security), the S in HTTPS, gives a connection three properties:
- Authentication: the server always proves its identity with a certificate; the client can too, but usually doesn't.
- Confidentiality: only the two ends can read the data.
- Integrity: any change in transit is detected.
TLS 1.3, the current version, completes its handshake in one round trip:
Each side contributes a fresh key share, and both derive the same session keys from them. Everything after ServerHello, including the certificate, is already encrypted.
Those key shares are generated fresh for every connection and thrown away afterward. That gives TLS 1.3 forward secrecy: if someone records the journal app's traffic today and steals the server's private key next year, the recordings stay unreadable, because the key never decrypted traffic, it only proved identity. TLS 1.3 removed static RSA and static Diffie-Hellman, so every full handshake has forward secrecy; resuming a session from a pre-shared key without a fresh key share, and 0-RTT early data, don't.
Two details deserve care:
- 0-RTT resumption lets a returning client send data in its very first message, but that early data can be replayed by an attacker. Allow it only for requests that are safe to repeat (Idempotency).
- Downgrade to plain HTTP. An attacker on the network can try to keep a user on unencrypted HTTP. The
Strict-Transport-Security(HSTS) header tells browsers to use only HTTPS for the site from then on.
A certificate is a statement, signed by a certificate authority, that a public key belongs to a domain. Certificates now expire faster on purpose, which limits how long a stolen key stays useful and makes manual renewal impossible:
The browser and CA industry voted in 2025 to cut the maximum lifetime of public TLS certificates in steps: 200 days from March 2026, 100 from March 2027 and 47 from March 2029. At that pace, only automated renewal (the ACME protocol) is realistic.
3 · Inside
Encrypt inside the data center too, and let services prove who they are
A common setup ends TLS at the load balancer and sends plain HTTP to the servers behind it, on the theory that the internal network is trusted. That theory fails whenever anything inside is compromised, misconfigured or shared with other tenants, and the traffic between data centers often crosses links you don't own. The current practice, part of what's called zero trust (Network segmentation & zero trust), is to encrypt every hop and authenticate both ends.
Between services, that means mutual TLS (mTLS): both sides present certificates. When the API server calls the database proxy, each learns the other's identity cryptographically, not from an IP address that changes with every deploy (Service discovery & registration). Systems such as SPIFFE give each workload an identity like spiffe://journal.example/api and issue it short-lived certificates that rotate automatically.
Hop | Encryption | Identity checked |
|---|---|---|
Phone → load balancer | TLS with a public certificate | Server only; the user authenticates inside the connection with a token |
Load balancer → API server | mTLS with internal certificates | Both: only the balancer may call the API this way |
API server → database | TLS, often mTLS | The database knows which service is connecting, not just which password |
Region → region | TLS or an encrypted network link | Both ends of the link |
Doing this by hand in every service is error-prone, which is one reason service meshes exist: a proxy beside each service performs mTLS and rotates the certificates, and the application talks plain HTTP to localhost. Either way, the certificates must be renewed automatically: an internal certificate that expires unnoticed breaks every call that depends on it.
4 · At rest
Envelope encryption keeps the master key inside a vault
Stored data is encrypted with a symmetric cipher, commonly AES-256 in GCM mode, which also detects tampering. The hard part is the key. If every journal entry were encrypted with one key stored next to the database, stealing the database would mean stealing the key too. And sending every entry to a key vault to be encrypted would be slow and limited by the vault's capacity.
Envelope encryption solves both. Each object or partition gets its own data key (DEK), which encrypts the data locally. The data key is itself encrypted ("wrapped") by a key encryption key (KEK) that lives in a key management service (KMS) backed by hardware security modules and never leaves it in plaintext:
The wrapped key is stored right beside the data; it is useless without the KEK. Every unwrap is a request the key service can refuse and record.
The design pays off in operations:
- Rotation is cheap. A new KEK means re-wrapping small data keys, not re-encrypting terabytes.
- Access is auditable. Reading data requires a logged call to the key service, which can be restricted to specific services.
- Deleting a key deletes data. Destroying the key that wraps one user's data keys makes that data unrecoverable everywhere, backups included: crypto-shredding. Because that is irreversible, AWS KMS, for example, enforces a waiting period of 7 to 30 days before a deletion takes effect.
5 · The catch
Transparent encryption at rest stops thieves of disks, not thieves of access
Most cloud storage and managed databases now encrypt everything at rest by default, transparently: data is encrypted on its way to disk and decrypted on its way back. That defeats someone who walks off with a drive. It does nothing against someone who queries the database through the application, because the database decrypts for any authorized query, including one from an attacker holding stolen credentials. The deeper the encryption sits in the application, the more it protects and the more it costs:
Layer | Who can read plaintext | Protects against | Costs |
|---|---|---|---|
Disk or volume | Anything running on the server | Stolen or discarded hardware | Almost nothing; on by default |
Database (transparent) | Anyone who can query | Stolen data files and backups | Little |
Field-level (the app encrypts chosen columns) | Only code holding the key | Database dumps, curious administrators | Little or no searching and sorting on those fields |
End-to-end (the phone encrypts) | Only the user's devices | The provider itself, and anyone who breaches it | No server-side search or processing; lost keys mean lost data |
The journal app has to choose for entries. End-to-end encryption means a breach of its servers exposes nothing readable, but it also means no server-side search, no recovery if a user loses every device and recovery key, and more work to share an entry. Apple's Advanced Data Protection shows the trade in practice: it end-to-end encrypts 25 categories of iCloud data and makes users set up a recovery contact or key first, while Mail, Contacts and Calendars stay outside it because the standards they must interoperate with don't support it.
A common middle ground is field-level encryption of the entry text with per-user data keys, plus transparent encryption for everything else. Entries stay unreadable in database dumps and to administrators, and deleting a user's key erases their journal, including every copy in backups (Disaster recovery & backups).
6 · In practice
The keys are the real security boundary
Encryption converts a data-protection problem into a key-protection problem. The rules that keep it solved:
- Never put keys in code, images or config repositories. Keep them in a KMS or secrets manager and fetch them with the service's own identity.
- Least privilege on decryption. Only the journal API may unwrap journal keys; analytics jobs get none.
- Separate keys per environment, per region and, where it matters, per tenant or user.
- Rotate on a schedule, and immediately on suspicion.
- Plan for key loss as for data loss. Backups encrypted with keys that didn't survive the disaster are useless.
One threat changes the timeline. An attacker can record encrypted traffic today and wait for a quantum computer able to break today's key exchange: harvest now, decrypt later. Journal entries must stay private for decades, so this matters now.
The response is hybrid key exchange, which combines classic X25519 with the post-quantum ML-KEM, standardized as FIPS 203 in August 2024. By late October 2025, more than half of the human-initiated traffic Cloudflare sees already used it. Post-quantum certificates and signatures are less urgent and less mature, since forging a signature later can't reach back into recorded traffic.
- In transit
TLS 1.3 everywhere, internal hops included; HSTS on public sites; automated certificate renewal; hybrid post-quantum key exchange where the stack supports it.
- At rest
Default encryption on every disk, bucket, database and backup; envelope encryption with keys in a KMS.
- For the crown jewels
Field-level or end-to-end encryption for the data a breach must never expose, accepting what it costs.
- Keys
Least-privilege access, audit logs on every use, rotation, and a recovery plan for the keys themselves.
Check yourself
4 questions
Takeaways
Remember this
- Encryption in transit stops network eavesdroppers, encryption at rest stops hardware thieves, and neither stops someone using the application's own access.
- TLS 1.3 authenticates the server, encrypts and seals traffic, and gives forward secrecy; use it on every hop, with mTLS between services.
- Envelope encryption encrypts data with local data keys wrapped by a key that never leaves a KMS, making rotation, auditing and crypto-shredding practical.
- Field-level and end-to-end encryption protect against breaches of the provider itself, at the cost of search, processing and key recovery.
- Keys are the real boundary: keep them out of code, limit who can decrypt, rotate them, and start moving to hybrid post-quantum key exchange.