Encryption protects confidentiality if everything else fails. The cloud makes the cryptography easy; what you actually have to choose is who controls the keys, where they live, and how they rotate.
Two Domains: At Rest and In Transit
| At rest | In transit |
|---|---|
| Disk volumes, object storage, databases, snapshots, backups, message queues | Client-to-LB, LB-to-app, app-to-DB, app-to-app, replication links, VPN/peering |
Both should be on by default. Modern cloud services make it a single setting; older ones require a policy to enforce.
Encryption At Rest: Three Levels of Control
- Service-managed keys — provider creates and rotates the key. Zero ops. Default for most services. Good enough for most data.
- Customer-managed keys (CMK) — you create the key in KMS, define rotation, audit usage, and can revoke. Required for compliance scenarios and cross-account access control.
- Customer-supplied keys (BYOK) / external keys — you generate the key material in your own HSM and import. Provider never sees plaintext key. Heavy ops, very specific use cases.
| Cloud | KMS service | HSM service |
|---|---|---|
| AWS | KMS (CMK = "customer-managed key") | CloudHSM |
| Azure | Key Vault (Standard / Premium) | Managed HSM |
| GCP | Cloud KMS | Cloud HSM |
Envelope Encryption
You do not encrypt a 1 TB file directly with a KMS key. KMS keys are precious; the cipher does not move data. Instead:
- Generate a per-object data key (DEK) — a fresh symmetric key.
- Encrypt your data with the DEK (AES-256-GCM).
- Encrypt the DEK with the KMS key (KEK).
- Store the encrypted DEK alongside the ciphertext.
To decrypt: ask KMS to decrypt the DEK (audit-logged), then locally use the DEK to decrypt the data.
Benefits:
- KMS calls are tiny and infrequent — fast and cheap.
- Rotating the KEK does not require re-encrypting the data, only the DEKs.
- Each object can have a unique DEK — limited blast radius.
S3 SSE-KMS, Azure Storage with CMK, and GCS with CMEK all use envelope encryption transparently.
Key Policies and Access Control
A KMS key has its own resource policy plus IAM. To use a key, a principal must be permitted by both. This lets you do useful things:
- Restrict
kms:Decryptto a specific role or VPC endpoint. - Grant cross-account access through key policy without giving the consumer IAM in your account.
- Require
kms:ViaServicecondition so the key can only be used through a specific service (e.g.s3.us-east-1.amazonaws.com).
{
"Sid": "AllowAppRoleUseKey",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:role/app-prod" },
"Action": ["kms:Encrypt", "kms:Decrypt", "kms:GenerateDataKey"],
"Resource": "*",
"Condition": {
"StringEquals": { "kms:ViaService": "s3.eu-west-1.amazonaws.com" }
}
}
Key Rotation
- Service-managed keys: rotated automatically by the provider, transparent to you.
- Customer-managed (AWS): annual rotation flag — KMS keeps old key versions to decrypt existing ciphertext.
- Azure Key Vault: configurable rotation policy per key.
- GCP Cloud KMS: rotation period setting per key version.
You rarely need to re-encrypt existing data — provider keeps old versions for decryption while new writes use the new version. The exception is if a key is suspected compromised; then re-encrypt.
Encryption in Transit
- TLS 1.2 minimum, TLS 1.3 preferred. Disable weak ciphers and SSLv3 / TLS 1.0/1.1 everywhere.
- Use managed certs: AWS Certificate Manager, Azure Key Vault certificates, Google-managed SSL certs. Auto-renew.
- For internal traffic: mTLS is the gold standard, but service mesh (Istio, Linkerd, Consul, AWS App Mesh, Azure Service Mesh) makes it practical.
- HSTS for browsers; certificate pinning for mobile if your threat model justifies it.
- Database connections — enforce TLS at the server side, not just the client (require_secure_transport on MySQL, ssl=on with rejectUnauthorized on Postgres clients).
End-to-End vs Hop-by-Hop
Public Internet → ALB → App → DB. Three TLS hops. Often fine. For data subject to regulation (PHI, payments), some teams insist on end-to-end encryption: TLS terminates at the application, not the load balancer. AWS Network Load Balancer with TLS pass-through, Azure Application Gateway with end-to-end TLS, GCP Network Load Balancer all support this.
Secrets Management
Closely related: how you store API keys, DB passwords, and tokens.
| Cloud | Service |
|---|---|
| AWS | Secrets Manager (with rotation), SSM Parameter Store (cheaper, no rotation) |
| Azure | Key Vault Secrets |
| GCP | Secret Manager |
Multi-cloud: HashiCorp Vault is the dominant cross-cloud option. Whatever you pick, the rule is the same — secrets never live in source code, env vars at rest, or images.
HSMs and Compliance
For workloads that require FIPS 140-2 Level 3 / FIPS 140-3 (regulated finance, healthcare, government), use the dedicated HSM service. The keys never leave the hardware. Higher cost, more operational care, but unavoidable in some industries.
Common Mistakes
- Default unencrypted EBS / managed disks (older accounts) — flip the org-wide default.
- Encrypted bucket but bucket policy allows anonymous read — encryption does not protect a public bucket from being read.
- KMS key policy with
"Principal": "*"— accidentally lets anyone in your account use the key. - Self-signed or expired certs in production.
- Database snapshots taken before encryption was enabled — re-snapshot to encrypted.
- Cross-region replication using a different KMS key without granting access.
Encryption is mostly checkbox security if you do it well; the danger is in the small policy and lifecycle details. Audit them on every new account, every new region, every new service.