Part 9 · Security for System Designers
Encryption & Secrets Management
Unencrypted traffic “inside our network”, an unencrypted backup in a public bucket, a database password pushed to GitHub. Where to encrypt in transit and at rest, who holds the keys, how envelope encryption and KMS work, end-to-end encryption, and how to store, deliver and rotate secrets.
On this page
The Problem
Three breaches from the same imaginary company:
- An attacker gets onto the office Wi-Fi and reads the traffic between two internal services. The traffic was not encrypted, because "it is inside our network". (Encryption means scrambling data so only someone with the right key can read it.)
- A backup of the customer database is left in a storage bucket with wrong settings. The backup was not encrypted, so every name, phone number and address leaks.
- A developer pushes code to a public GitHub repository with
DB_PASSWORD=Sup3rS3cret!in a config file. Within minutes, automated bots find it and log into production (the live system).
None of these needed a genius hacker. They happened because of missing encryption and badly handled secrets. A secret is a value that must stay private, like a password or an API key. For system designers, the question is not "how does AES (a common encryption method) work in maths?". The question is where data is encrypted, who holds the keys, and how secrets are stored, delivered and rotated.
The Core Idea
Think about a bank.
- Encryption in transit protects data while it moves between computers. It is like the armoured van that moves cash between branches. Even if someone stops the van, they cannot get at the money.
- Encryption at rest protects data while it is stored on a disk. It is like the locked vault. If someone breaks into the building, the cash is still locked away.
- Keys are the vault combinations. A key is a secret value that locks and unlocks encrypted data. A vault is only as safe as its combination. If you write the combination on a note on the vault door, the vault is useless.
- Secrets management is how the bank stores, hands out, changes and tracks those combinations. Only the right people get them, only when needed. They are changed regularly, and every use is written in a log.
How It Works
Part 1: The building blocks (in plain words)
| Tool | What it does | Example use |
|---|---|---|
| Symmetric encryption (AES-256-GCM, ChaCha20-Poly1305) | The same key locks and unlocks. Very fast | Encrypting files, database fields, TLS session data |
| Asymmetric encryption (RSA, elliptic curves) | A public key locks (anyone may have it), and a private key unlocks (only the owner has it). Slower | Key exchange in TLS, encrypting a key for someone |
| Digital signatures (ECDSA, Ed25519, RSA) | The private key signs, and the public key checks the signature. This proves who made the data and that it was not changed | JWTs (post 49), software updates, certificates |
| Hashing (SHA-256) | A one-way fingerprint of data. It cannot be reversed | Checksums, file integrity |
| Password hashing (Argon2id, bcrypt) | Hashing that is slow on purpose and uses a random salt (extra random data added to each password) | Storing passwords (post 49) |
| HMAC | A hash that also uses a secret key. It proves the message was not changed and came from someone who has the key | Webhook signatures (post 34), API request signing |
Key point: encoding ≠ encryption ≠ hashing.
- Base64 is encoding. Encoding only changes how data is written. Anyone can decode it, so it is not security.
- Encryption can be reversed with the key. The scrambled result is called ciphertext.
- Hashing can't be reversed at all.
Use authenticated encryption (like AES-GCM). It protects both secrecy (nobody can read the data) and integrity (nobody can change it without being noticed).
Do not invent your own cryptography. Use well-reviewed libraries (like libsodium or Google Tink, or your platform's standard crypto library) and managed services. Most real failures come from misuse: reusing a nonce (a number that must be used only once), weak random numbers, keys written in the code, or home-made methods. Very few come from breaking the algorithms.
Part 2: Encryption in transit
Use TLS everywhere. TLS is the protocol that encrypts data on the network. It is what makes HTTPS secure. Use it not only between users and your load balancer (post 3), but also:
- between the load balancer and app servers (re-encryption),
- between services,
- between apps and databases, caches and message brokers,
- between data centres and clouds.
The old idea "it is inside our network, so it is safe" has been replaced by zero trust. Zero trust means you assume the internal network may already be hacked, so you check who is calling and encrypt every connection.
mTLS (mutual TLS). With normal TLS, only the server proves who it is. With mTLS, both sides show a certificate. A certificate is a digital ID card signed by a trusted authority. So service A knows it is really talking to service B, and B knows the caller is really A.
- •Client asks “who are you?”
- •Server shows its certificate ✅
- −The server can't cryptographically tell which client is calling
- •Client shows a certificate ✅
- •Server shows a certificate ✅
- +Both sides authenticated and encrypted
Managing certificates for hundreds of services by hand is painful, so:
- service meshes (Istio, Linkerd) give each service a certificate automatically, replace it often (rotate it), and force mTLS between sidecars. A sidecar is a small helper program that runs next to each service (post 13),
- workload identity systems (like SPIFFE/SPIRE) give services short-lived identities, so you do not manage keys by hand.
Certificate management:
- renew certificates automatically (ACME is the protocol for this, and Let's Encrypt is a free service that uses it; cloud certificate managers do it too),
- watch the expiry dates. An expired certificate is a classic cause of outages (post 40),
- use modern TLS versions (TLS 1.2 at least, TLS 1.3 preferred) and turn off old, weak ones.
Part 3: Encryption at rest
Layers of encryption at rest:
- Disk, volume and bucket encryption is usually on by default in the major clouds today. A volume is a virtual disk, and a bucket is a place to store files in the cloud. This protects against stolen or thrown-away hardware and some wrong settings.
- Database Transparent Data Encryption (TDE) encrypts database files and backups automatically. "Transparent" means your app does not notice it.
- Application-level (field-level) encryption means the app encrypts sensitive fields before saving them, so the database only ever sees ciphertext (the scrambled data).
Important: disk, volume and database encryption are transparent. Anyone who can query the database sees decrypted data. This includes an attacker with stolen app credentials, or an attacker who uses SQL injection (post 52). SQL injection means sending SQL commands through a form field. They mainly protect against physical theft and some storage leaks. For the most sensitive data, add field-level encryption, tokenisation, and strict access control.
Tokenisation replaces sensitive data (like a card number) with a meaningless token such as tok_9f3a…. The real value is kept in a separate, highly protected vault. Most of your systems handle only tokens, so if they are breached, nothing useful leaks. This is how payment providers keep merchants out of the scope of the card-data rules (PCI DSS, the security standard for card payments).
Backups must be encrypted too (post 45). Their keys must be available during a disaster, but not to an attacker.
Part 4: Key management and envelope encryption
Encryption changes the problem from "protect the data" to "protect the keys". Keys should:
- never be written directly in the source code,
- be stored in a Key Management Service (KMS), a service that keeps keys safe and does the encrypting for you, or in a Hardware Security Module (HSM), which is special hardware built so that keys cannot be copied out,
- have strict access control and audit logs of every use,
- be rotated regularly.
Envelope encryption means you encrypt your data with a data key, and then you encrypt that data key with a master key. It is how KMS systems (AWS KMS, Google Cloud KMS, Azure Key Vault, HashiCorp Vault) work at scale. Think of a letter (the data) in a locked box (the data key), and the box key is kept in a bank safe (the master key):
- ↻ generate a random data key (DEK)
- ↻ encrypt the record with the DEK (AES-GCM)
- encrypt this DEK with the master key
- encrypted DEK
- store encrypted data + encrypted DEK
- To read — send the encrypted DEK to KMS, which checks permissions and logs the request
- decrypt DEK
- plain DEKused once in memory, then discarded
- 1KMS / HSMmaster key — never leaves, every use audited
- 2Each recordencrypted_data + encrypted_DEK, stored together
- 3Rotationre-wrap data keys with a new master key — no need to re-encrypt terabytes
Why it's clever:
- Huge data never goes to KMS, only tiny keys, so it's fast and cheap.
- Rotating the master key means re-encrypting the small DEKs, not all your data.
- Access to KMS is controlled and logged, so you can see exactly which service decrypted what, and cut off access instantly.
- Crypto-shredding: if you delete the key, the data encrypted with it becomes unreadable. This is useful for "delete my data" requests and for retiring old backups.
Part 5: End-to-end encryption (E2EE)
With end-to-end encryption, data is encrypted on the sender's device and is decrypted only on the recipient's device. The server in the middle can't read it at all.
- •Phone A ═TLS═► Server ═TLS═► Phone B
- −The server can read every message
- •Phone A ═══ encrypted blob ═══► Phone B
- +The server only relays what it can't read
- −No server-side search, moderation or easy multi-device recovery
- ✅ The strongest privacy. Even the service provider, or anyone who breaches it, can't read messages.
- ❌ Server-side features become hard: search, spam filtering, content moderation (checking content for abuse), backups and multi-device sync all need special designs.
- ❌ Key management moves to the users' devices. If a user loses all their devices and backups, their messages may be lost for ever.
Part 6: Secrets management
What counts as a secret:
- database passwords,
- API keys (payment, SMS and email providers),
- OAuth client secrets (post 50),
- JWT signing keys (post 49),
- TLS private keys,
- encryption keys,
- webhook signing secrets,
- cloud access keys.
Anti-patterns (all very common):
- ❌ secrets in source code or committed config files (even in private repos),
- ❌ secrets baked into Docker images,
- ❌ secrets printed in logs, CI output or error messages,
- ❌ secrets shared over chat or email,
- ❌ one shared admin key used by every service and every engineer,
- ❌ long-lived secrets that are never rotated.
Better: a secrets manager. Store secrets in a dedicated, encrypted, access-controlled, audited system:
- HashiCorp Vault (or its open-source fork OpenBao),
- AWS Secrets Manager / Parameter Store, Google Secret Manager, Azure Key Vault,
- Kubernetes Secrets. ⚠️ By default, these are only base64-encoded in etcd (the database where Kubernetes keeps its data), not encrypted. Turn on encryption at rest for etcd and limit access with RBAC (role-based access control, post 49). You can also use the External Secrets Operator (it copies secrets from a cloud secrets manager), Sealed Secrets or SOPS (tools that let you store encrypted secrets in Git).
Apps get secrets at runtime, which means when they run. The platform puts them in as files or environment variables, or the app reads them through the secrets manager's API.
Best: avoid long-lived secrets entirely.
- Workload identity / IAM roles: your service runs with an identity that the platform gives it (like an AWS IAM role for a pod or VM). A pod is a running unit in Kubernetes, and a VM is a virtual machine. The service gets short-lived credentials automatically, so there are no keys in the configuration at all.
- Dynamic secrets: tools like Vault can create a new database username and password for each app instance. The login works for an hour, and then Vault deletes it.
- OIDC federation from CI/CD: CI/CD is the automatic pipeline that builds and releases your code. Instead of storing cloud keys in GitHub Actions or GitLab, the job shows a short-lived OIDC token (post 50), and the cloud swaps it for temporary credentials.
Rotation and revocation.
- Rotate secrets regularly, and immediately when someone leaves or a leak is suspected.
- Design apps so rotation causes no downtime. For example, accept both the old and the new key during a short change-over period, and reload secrets without restarting.
- Keep an inventory: which secrets exist, who owns them, what uses them, and when they were last rotated.
Detect leaks early.
- Pre-commit hooks and CI scanners (gitleaks, trufflehog, detect-secrets) check your code and block commits that contain secrets. A pre-commit hook is a script that runs before each commit.
- GitHub secret scanning and push protection detect known key formats and can block pushes. Many providers (like cloud and payment companies) automatically cancel their keys when they find them in public repositories.
If a secret leaks, respond in this order:
- Revoke or rotate it immediately. Deleting the commit is not enough. The secret is still in the Git history and in the copies that bots already made.
- Check logs for any use of the leaked secret.
- Assess and contain any damage.
- Clean up the repository history if needed.
- Do a blameless postmortem (post 48) and add the controls that would have prevented it.
Trade-offs
- Encryption everywhere: strong protection, at a small cost in CPU and latency (time). The cost is usually tiny with modern hardware and TLS 1.3. You also have extra work to manage certificates and keys.
- Field-level encryption: protects the most sensitive data even from database access, but makes searching, sorting and indexing those fields hard, and adds complexity.
- End-to-end encryption: maximum privacy, but limits server-side features and makes account recovery harder.
- Managed KMS and secrets managers: secure, audited and convenient, but cost money and add a dependency. Cache secrets and data keys carefully (keep a short-lived copy in memory), so a short KMS outage does not take you down.
- Short-lived, dynamic credentials: a tiny window for attackers, but more moving parts, and they require platform support.
In the Real World
Uber (2016). Attackers found cloud access credentials in a private code repository used by Uber engineers. They used them to reach stored data of tens of millions of riders and drivers. The incident, and the way the company handled it, led to large fines and legal action. It is the standard example for never storing secrets in code, even in private repositories.
Toyota (2022). Toyota disclosed that an access key for a customer-data server had been publicly visible on GitHub for about five years, after a contractor accidentally published source code. It shows why automated secret scanning matters.
Heartbleed (2014). A bug in OpenSSL (a widely used library for TLS) let attackers read pieces of server memory, potentially including private TLS keys and passwords. Huge numbers of websites had to patch, revoke and reissue certificates, and rotate secrets. It showed how important key rotation and dependency updates are (post 52).
WhatsApp and Signal. WhatsApp finished adding end-to-end encryption for all messages in 2016. It uses the Signal Protocol, which was created by the team behind the Signal messaging app. Billions of people now use E2EE every day without noticing.
Payment tokenisation. When an online store saves "your card ending in 4242", it usually stores a token from its payment provider, not the card number. The provider holds the real data in a highly secured vault, which keeps the store's systems out of most card-security audits.
Interview Questions
Q1Why encrypt traffic inside your own network?
Because “inside” isn't safe: compromised hosts, misconfigured networks, shared cloud infrastructure and insiders can all read plaintext. Zero-trust networking encrypts and authenticates every hop, typically with mTLS between services.
Q2What is envelope encryption?
Data is encrypted locally with a random data key; the data key is then encrypted by a master key held in a KMS or HSM, and stored alongside the data. The master key never leaves the KMS, access to it is permissioned and audited, and rotation only re-wraps small keys.
Q3When do you need field-level encryption on top of disk encryption?
When some fields are sensitive enough that database admins, backups, analytics copies or a SQL-injection dump must not reveal them — national IDs, card numbers, health data. Disk and database encryption only protect against stolen media.
Q4Where should application secrets live?
In a secrets manager (Vault, AWS Secrets Manager, GCP Secret Manager), delivered at runtime to authorised workloads via their platform identity — never in code, images or git. Prefer short-lived, dynamically generated credentials, rotate regularly, and audit access.
Q5A secret was pushed to a public repository. What do you do?
Treat it as compromised immediately: revoke and rotate it first (deleting the commit isn't enough — bots scan within minutes), check audit logs for misuse, then remove it from history and add pre-commit and CI secret scanning.
Q6What's the trade-off of end-to-end encryption?
The server can't read messages, which protects users against server breaches and insiders — but it also can't search, moderate, back up or sync content in plaintext, so multi-device support and key recovery need careful protocol design.
Key Takeaways
- Use the right tool: AES-GCM for data, public-key crypto for key exchange and signatures, HMAC for message integrity, and Argon2id/bcrypt for passwords. Base64 is not encryption, and don't roll your own crypto.
- Encrypt in transit everywhere (TLS, mTLS between services, zero trust) and automate certificate renewal and monitoring.
- Encrypt at rest in layers. Transparent disk and database encryption doesn't stop someone who can query the database, so add field-level encryption or tokenisation for sensitive data.
- Protect keys with KMS/HSM and envelope encryption, which gives cheap rotation, audit logs and crypto-shredding.
- Keep secrets out of code, images and logs. Use a secrets manager, prefer workload identity and short-lived credentials, rotate regularly, scan for leaks, and revoke immediately if one leaks.
Further Reading
- OWASP Cheat Sheet Series: Cryptographic Storage, Transport Layer Security, Secrets Management, and Key Management cheat sheets
- The AWS KMS documentation on envelope encryption, and Google Cloud's "Encryption at rest" documentation
- The HashiCorp Vault documentation
- The Kubernetes documentation "Good practices for Kubernetes Secrets"
- Serious Cryptography (2nd edition) by Jean-Philippe Aumasson
- The Signal Protocol technical documentation
- The gitleaks and SOPS projects on GitHub
Published by Jainik · Last updated · How these lessons are made
Keep learning
Related series