Filter concepts by levelShowing all levels.

System Design · Section 72

Privacy and Compliance Architecture

Level
intermediate
Read
12 min
Concepts
2

A privacy-conscious architecture layers six controls, each closing a different part of the same risk: data minimization (do not collect what is not needed — a field that does not exist cannot leak), least privilege (the narrowest access, for services as much as people), audit trails (who accessed or changed data, and when, so access is reviewable after the fact), retention and deletion (a bounded lifetime), encryption (protecting against a storage or network compromise specifically, at rest and in transit respectively), and recurring access reviews (catching privilege that was correct when granted and has since gone stale). Regulations like GDPR make one of these controls a hard legal requirement with teeth: a user's right to erasure has to reach every real copy of their data — primary database, read replicas, search indexes, edge caches, backups (typically via crypto-shredding, destroying a per-user encryption key rather than editing an immutable backup directly), and any analytics export — within a defined deadline, which is only reliably achievable if a personal-data inventory already exists before the request arrives. Regional data residency layers a geography constraint on top, restricting which cloud region a database, its replicas, and any job that processes the data may run in, independent of and enforced separately from ordinary access control; financial and healthcare regulations add domain-specific minimum retention periods that can directly conflict with a deletion request, resolved per field — anonymize what is not legally mandated, keep exactly what a regulation requires.

System Design overview

What is true here

  1. Six controls (minimization, least privilege, audit trails, retention/deletion, encryption, access reviews) each close a different part of the same exposure risk — none substitutes for another.
  2. A GDPR-style erasure request must reach every copy: primary DB, replicas, search indexes, caches, backups, exports — not just the row an engineer would delete first.
  3. Backups are usually made unrecoverable via crypto-shredding (destroying a per-user encryption key), not direct editing, because backups are typically immutable.
  4. Data residency restricts which region data, its replicas, and any processing job may run in — enforced independently of and in addition to normal access control.
  5. Financial/healthcare retention minimums can directly conflict with a deletion request; the resolution is field-level — anonymize what is not mandated, keep what a regulation requires.

What you will be able to do

  • Explain the six privacy controls and the distinct risk each one closes
  • Design a deletion process that reaches every real copy of a user's data within a legal deadline
  • Explain why crypto-shredding is the standard way to fulfill an erasure request against immutable backups
  • Identify when data residency or retention-minimum requirements constrain an architecture decision that looks purely technical

The six controls

Minimization, least privilege, audit trails, retention/deletion, encryption and access reviews — each closing a different part of the same risk.

Data minimization, least privilege and audit trails

coreintermediate

A privacy-conscious architecture is built on a handful of controls that each answer a different question about the same underlying risk: data that exists and can be read is data that can leak, be subpoenaed, or be misused. Data minimization asks "do we need to collect or keep this field at all" — the cheapest privacy control is never having the data in the first place, because a field never collected cannot be breached. Least privilege asks "does this specific service or person need access to this specific field," and answers it by granting the narrowest access that lets the job get done, rather than broad access "just in case." Audit trails answer "who accessed or changed this record, and when" — not to prevent access, but to make every access accountable and reviewable after the fact, which is often a compliance requirement in its own right (e.g. who looked at a patient record). Retention and deletion (covered on their own in the prior section) bound how long the data problem exists at all. Encryption protects data both at rest and in transit so that a storage or network compromise does not automatically mean a data compromise. Access reviews are the recurring, deliberate check — quarterly, say — that current access grants still match current need, because access naturally accumulates over time (a role change, a project ending) and nobody's job is to notice and revoke it unless a review forces the question.

Think of it as

Think of a bank vault run well: it does not keep more cash on hand than the day's business requires (minimization), each teller has a key that opens only their own drawer, not the whole vault (least privilege), every door swipe is logged with a name and a timestamp (audit trail), and cash is inside a safe, not sitting on a counter, even inside the already-secured building (encryption at rest). None of that matters if nobody ever checks who still has a working key months after they changed roles — the access review is the manager walking the vault's access list every quarter and asking "does this person still need this key," which is the only mechanism that catches privilege that was correct when granted and has since gone stale.

text
# A field-level design checklist run before adding
# any new personal-data field to a schema:
1. Do we actually need this field for a real use case?
   (if no -> don't collect it: data minimization)
2. Which specific services/roles need to read it?
   (grant only those: least privilege)
3. Is every read/write of it logged with who + when?
   (audit trail)
4. How long is it kept, and how does it get deleted?
   (retention + deletion)
5. Is it encrypted at rest and in transit?
6. Is access to it reviewed on a schedule?

What we're doing: Apply the six controls to one new field being added to a signup form.

new-field-review.txttext
Proposed field: date_of_birth, added "in case we
need it for age verification later"

Review:
1. Minimization: no current feature uses it -> DO NOT
   COLLECT until a real feature needs it
2. (if collected) Least privilege: only the
   age-verification service reads it, not the whole
   user-profile service
3. Audit trail: every read logged with service + user ID
4. Retention: deleted if the account is deleted; not
   copied into analytics exports
5. Encryption: stored in an encrypted column, not plaintext
6. Access review: quarterly check of which services still
   hold a grant to read it
3
The correct outcome of the review is often "do not collect it yet" — data minimization is the control that gets applied before any of the other five even become relevant, because a field that does not exist has nothing to secure.
6
Least privilege here is deliberately narrower than "the user-profile service can see it" — scoping access to the one service that has an actual need for the field, not the service that happens to already own the surrounding record.

Why this works: Most fields added "in case we need it later" never get the other five controls retrofitted once a real use case does appear, because by then the field is already collected, already replicated into backups and analytics exports, and already read by more services than the original use case required — minimization is cheapest exactly at the moment before collection starts, which is also the moment it is easiest to skip.

Granting a service broad table access because it is convenient, not because it needs it

Wrong

sql
-- Order-status service given full read access to
-- the customers table "since it's already
-- joining on customer_id anyway"
GRANT SELECT ON customers TO order_status_service;

Better

sql
-- Grant only the columns the service actually uses
GRANT SELECT (customer_id, shipping_address)
  ON customers TO order_status_service;

What you see: A vulnerability in the order-status service (which only ever needed a shipping address) is later found to have exposed customers' payment details and full purchase history, because the service's database credential could read the entire customers table, not just the two columns it used.

Why: Column-level or row-level grants take more setup than a blanket table grant, so under time pressure teams default to the broad grant "since it is already joining on customer_id anyway" — the convenience is real, but it means every service's blast radius on compromise is the whole table rather than the columns it actually needed.

Six privacy controls, one shared goal

Minimize

only collect what is needed

Least privilege

narrowest access that works

Audit trail

who accessed, when

Retention

bounded lifetime

Encryption

at rest and in transit

Access review

recurring re-check

  • Minimize — only collect what is needed
  • Least privilege — narrowest access that works
  • Audit trail — who accessed, when
  • Retention — bounded lifetime
  • Encryption — at rest and in transit
  • Access review — recurring re-check

Six controls and the specific risk each one closes

Six controls and the specific risk each one closes
ControlQuestion it answersRisk it closes
Data minimizationDo we need to collect/keep this at all?Data that does not exist cannot leak
Least privilegeWho/what actually needs access to this?A compromised account/service exposes less
Audit trailsWho accessed or changed this, and when?Makes access accountable and reviewable after the fact
Retention & deletionHow long must this exist at all?Bounds how long the exposure risk exists
EncryptionIs this readable if storage/network is compromised?A stolen disk or intercepted packet is not automatically a breach
Access reviewsDoes current access still match current need?Catches privilege that went stale after it was correctly granted

Remember: Six controls close six different parts of the same risk: minimization (do not collect what is not needed), least privilege (narrowest access that works), audit trails (accountability after the fact), retention/deletion (bounded lifetime), encryption (protects against storage/network compromise), and access reviews (catch stale grants). None of them substitutes for another — a real privacy architecture runs all six together.

See also: transit vs at rest · secrets audit logs and key rotation · hot warm cold and retention policies

Advertisement

Regulation with teeth

What a real GDPR-style deletion has to reach, and how data residency and financial/healthcare retention minimums constrain architecture on top of it.

GDPR-style deletion and regional residency

coreintermediate

Regulations like the EU's GDPR give a user a legal "right to erasure" — a deletion request that a system must actually be able to fulfill, completely, within a defined time window (commonly 30 days). That sounds like a single DELETE statement until the data has been replicated to read replicas, copied into a search index, cached at the edge, exported into an analytics warehouse, and backed up nightly for a year — a genuine deletion has to reach every one of those copies, not just the primary database row, or the "delete" is legally incomplete even though the original record is gone. Regional residency (or "data residency") is a related but separate requirement: some regulations and some contracts require that a specific category of data (EU citizens' personal data, healthcare records in certain jurisdictions) physically stay within a specific geographic or legal boundary — never replicated to a data center outside it, never processed by a service hosted elsewhere — which directly constrains architecture decisions like which region a database lives in and which cloud regions a background job is allowed to run in. Financial and healthcare data add domain-specific rules on top of both: specific minimum retention periods (which can directly conflict with a deletion request — a bank often cannot delete transaction records early even if asked, because a longer regulation requires keeping them), and stricter access-logging and encryption requirements than the general baseline.

Think of it as

Think of "delete this" as a request that fans out like a broadcast, not a single pointer being removed: the primary copy, every read replica, the search index, the CDN cache, the nightly backup tape, the analytics warehouse extract, and any support ticket that pasted the data in as plaintext are all separate places the same fact now lives, and a real deletion has to track down and clear every one of them, on a deadline. Regional residency is a fence drawn on a map: some data is legally not allowed to cross it, which means a load balancer routing to "whichever region is fastest" or a backup job replicating "everywhere for redundancy" can turn a performance or reliability decision into a compliance violation if it is not aware the fence exists. Financial/healthcare retention rules are a second, sometimes contradictory instruction taped over the first: "keep this exact record for 7 years no matter what" can override "the user asked us to delete it," and resolving the conflict is a legal judgment call, not an engineering one — the system just needs to be built so that call can actually be made and enforced per field.

text
# A personal-data inventory: the prerequisite for
# meeting a 30-day deletion deadline reliably.
# For each field, track every place it lives:
field: user.email
  - primary DB (customers table)
  - read replicas (3, auto-propagated)
  - search index (Elasticsearch, re-indexed nightly)
  - CDN edge cache (TTL 5 min, expires on its own)
  - nightly backups (encrypted per-user; key deleted
    on erasure request -> crypto-shredding)
  - analytics warehouse (anonymized on export, no
    raw email ever lands here)

What we're doing: Trace a single erasure request across a system with replicas, a search index and backups.

erasure-request-trace.txttext
Request: user #4821 exercises GDPR right to erasure

1. Delete row from primary customers table
2. Deletion propagates to 3 read replicas (async,
   within seconds)
3. Re-index search: remove user #4821's document
4. Delete user #4821's per-user encryption key
   (backups from before this point become
   unrecoverable for this user's data - never
   touched directly)
5. Check support-ticket system for any ticket where
   an agent pasted the user's data as plaintext
6. Confirm no raw copy of this user's data exists in
   the analytics warehouse (it was anonymized at
   ingest, so there is nothing to delete there)
4
This is the step that makes the backups compliant without a custom per-backup deletion process — because each backup was encrypted with a key unique to this user, destroying only the key renders every past backup containing this user's data permanently unreadable.
5
This is the step most designs miss entirely: personal data copied into a support ticket, a Slack message, or a debug log is a real copy just as much as a database row, and a genuine erasure process has to have a documented answer for it, even if that answer is "policy forbids pasting raw personal data into tickets in the first place."

Why this works: Steps 1 through 3 are the ones every engineer immediately thinks of; steps 4 through 6 are the ones that determine whether the erasure is actually legally complete — a system that only implements the obvious three steps has fulfilled the easy 80% of the request and left the hard 20% (backups, and any place a human copy-pasted the data) unresolved.

Treating "delete the row" as equivalent to "erase the user's data"

Wrong

sql
-- "Handling" a GDPR erasure request
DELETE FROM customers WHERE id = 4821;
-- ticket closed

Better

text
-- A real erasure checklist, tracked per-field
-- against the data inventory:
[ ] primary row deleted
[ ] replicas confirmed propagated
[ ] search index re-indexed
[ ] per-user backup key destroyed (crypto-shredding)
[ ] analytics/warehouse copies confirmed absent
      or anonymized
[ ] support-ticket / log copies checked
[ ] confirmation sent to user within the legal
      deadline

What you see: A user who exercised their right to erasure still appears in a search result months later, or their data surfaces in an old backup restored for an unrelated incident, because the original "deletion" only ever touched the primary database row.

Why: A single DELETE statement is a complete fix for the mental model of "the data lives in one table," which is true of almost no real production system — personal data fans out to replicas, indexes, caches, backups and exports as a normal part of running the system, and a deletion process that was never designed against an inventory of those copies will structurally miss most of them.

A deletion request has to reach every copy
User
App
Primary DB
Backups
Analytics
  1. 1. Request erasure
  2. 2. Delete row
  3. 3. Delete per-user encryption keycrypto-shredding — backup itself is never touched
  4. 4. Confirm no raw copy was ever exportedanonymized at export time, nothing to delete here
  5. 5. Confirm erasure complete
  1. User → App: Request erasure
  2. App → Primary DB: Delete row
  3. App → Backups: Delete per-user encryption key (crypto-shredding — backup itself is never touched)
  4. App → Analytics: Confirm no raw copy was ever exported (anonymized at export time, nothing to delete here)
  5. App → User: Confirm erasure complete

Three compliance requirements and what each one constrains

Three compliance requirements and what each one constrains
RequirementWhat it constrainsTypical conflict
GDPR-style deletionEvery copy of a user's personal dataCannot reach immutable backups directly — needs crypto-shredding
Regional residencyWhich physical region/jurisdiction data may live or be processed inGlobal load balancing / cross-region replication for performance or DR
Financial/healthcare retentionMinimum time specific records must be keptDirectly conflicts with a user deletion request for the same record

Remember: A GDPR-style deletion request has to reach every copy of the data — replicas, indexes, caches, backups (via crypto-shredding, since backups usually cannot be edited directly) and exports — not just the primary row, and doing that reliably within a legal deadline requires an inventory of where personal data lives before the request arrives. Regional residency and financial/healthcare retention minimums are separate constraints layered on top, and they can directly conflict with deletion — resolve the conflict per field (anonymize what is not mandated, keep what a regulation requires), not per record.

See also: data minimization and access reviews · key management · hot warm cold and retention policies · reasons to go multi region

Advertisement