Skip to main content

Envelope encryption in Skapp

Type: ExplanationCreated: Team: Security
draft

The decision​

Skapp encrypts its sensitive data at rest with envelope encryption, using a single application-level data key (DEK) wrapped by a customer-managed key in AWS KMS. One DEK protects the sensitive fields across every tenant: the application unwraps it once at startup, holds it in memory, and uses it for all field-level encryption and decryption. This is the one key for everything model — and for Skapp it is a deliberate choice over per-user and per-tenant keys, not a fallback.

Why a single key is the right fit​

Per-user and per-tenant keys solve problems Skapp either doesn't have or already solves another way. A single key is the simplest design that fully meets our obligations — and given our architecture, it gives up nothing that matters.

  • Tenant isolation is already handled where it counts. Skapp runs database-per-tenant, so each client's data already lives in its own database. Offboarding a client is a clean database drop — immediate for live data and replicas. The isolation a per-tenant key would add is largely already there at the data layer; the encryption key doesn't need to duplicate it.
  • It fully satisfies the security obligation. Field-level encryption of the sensitive columns makes a stolen database dump useless ciphertext — exactly what Article 32 (security of processing) asks for. One key or many, that protection is identical.
  • Per-tenant keys couldn't deliver their headline benefit here anyway. The reason to reach for per-tenant keys is instant, backup-inclusive erasure by destroying a key — which depends on having a per-tenant backup to destroy. Skapp's automated backups are whole-instance RDS snapshots, with every tenant in one shared blob under a single instance key. There is nothing per-tenant to shred, so per-tenant keys would add a key table, per-row key resolution, and a migration for a benefit we could never collect (see what crypto-shredding actually erases).
  • Individual erasure is a deletion problem, and a solved one. Deleting one employee never needed per-user or per-tenant keys; it is handled by deleting the data and letting backups cycle out — the approach in erasure under a single key.
  • Simpler is more reliable. No key table, no per-row key lookups on the hot path, no multi-key migration — fewer moving parts, fewer failure modes. And we keep every envelope-encryption benefit regardless: no plaintext master key at rest, central KEK rotation, and a CloudTrail record of every unwrap.

What we encrypt​

Field-level encryption with AES-256-GCM on the special-category columns — examples in general world - national ID, salary, and health data — under the DEK. Ordinary columns such as names, emails, and dates stay as queryable plaintext. That keeps the highest-risk data protected against a dump or backup theft while leaving everything else fully indexable and searchable.

Erasure in practice​

Deleting an individual. Hard-delete or anonymize the employee's rows; the change propagates to read replicas immediately. The whole-instance snapshots age out on their retention window, and a small suppression log re-deletes the subject if a snapshot is ever restored.

Offboarding a tenant. Drop the client's database — instant for live data and replicas — then let the shared snapshots age out under the same retention window. The honest, auditable promise to a departing client is then: live data destroyed immediately; the only residue is time-limited system snapshots that are never restored without re-deletion and that expire within the retention window.

note

The retention window length, and which records carry mandatory retention (example in general - payroll, tax, employment), are compliance and DPO calls, not technical ones. The retention versus erasure section covers the classification approach the implementation honours.

Operational secrets are separate​

This decision is about tenant data. Skapp's operational secrets — AWS credentials, inter-service API keys, app-level integration credentials — are platform-owned, not tenant data, so they sit outside this scheme entirely. They belong in the secrets-management layer (AWS Secrets Manager / SSM) under their own app-level KMS key, with separate least-privilege credentials per service and independent rotation. The principle is that key scope follows ownership: this doc decides only how Skapp encrypts tenant data at rest.

The upgrade path​

Single key is the right call now, and it doesn't paint us into a corner. If a client contract or a regulator ever requires the most sensitive fields to be destroyed instantly even inside backups, we can introduce per-tenant DEKs for just those columns later, without rearchitecting. The application already resolves the current tenant on every request — it has to, to route to the right database — so selecting a per-tenant key would be the same lookup it already performs. We start simple, and the door to stronger isolation stays open.