Data residency, and the dependency audit

What it is

Two constraints that decide whether a multi-region design is actually deployable.

Data residency is a legal or contractual requirement that specific data stays in, or is processed in, a specific jurisdiction. It turns region placement from a latency decision into a correctness one.

The technical shape it forces:

  a user has a HOME REGION, recorded at signup
  their personal data lives only there
  requests are routed there
  and the region becomes part of the identity: it is in the
  key, the token, and the URL, not looked up on every request

The dependency audit is the question nobody asks until the failover fails: what does your failover itself depend on, and is any of it in the region you just lost?

Failing over needs, at minimum:
  DNS or the global load balancer's control plane
  the identity provider (to log in and to authorise the
    action)
  the secrets manager (to start anything)
  the container registry (to pull images)
  CI/CD (if the runbook deploys)
  the certificate authority or cert store
  the config and feature-flag service
  observability (to verify the failover worked)

If any of those is single-region and that region is the one
that failed, the runbook stops at the step that needs it.

What this is confused with: residency and encryption. Encrypting data does not make it resident. Most residency regimes are about where data is stored and processed, and an encrypted copy in another jurisdiction is still a copy there, though key location and access control matter for some regimes and for contractual commitments.

Also confused: a dependency audit and an architecture diagram. The diagram shows the request path. The audit asks what the recovery path needs, which includes things the request path never touches: the registry, CI, the console you log into.

The problem it solves

Residency retrofitted is a rewrite; residency designed in is a routing rule.

A system with a global user table, a single primary in
us-east-1, and a European customer requiring EU residency.

Retrofit cost:
  - split the user table by region, which means every foreign
    key crossing that boundary is now a cross-region reference
  - every query that joins users to anything else
  - every background job that iterates all users
  - every report
  - the id scheme, if ids do not encode the region
  - and a backfill that must run while the system is live

Observed shape: two to four quarters, and it competes with
everything else.

Designed in from the start: a home_region column, a routing
rule, and region-scoped ids. Weeks.

And the dependency failure is the one that turns a rehearsed failover into a stuck one:

Region A fails.
Step 1 of the runbook: log into the cloud console.
The SSO identity provider runs in region A.

Nobody can log in to perform the failover that would restore
the identity provider.

This is a circular dependency and it is extremely common,
because the identity provider was deployed like any other
service, by a team that was not thinking about the recovery
path.

Mechanics

Residency: what the regimes actually require

GDPR (EU/EEA)
  Does NOT require storage in the EU. It restricts TRANSFER to
  third countries without an adequacy decision or appropriate
  safeguards (standard contractual clauses, and since the
  Schrems II judgment, a transfer impact assessment).
  So "GDPR requires EU data residency" is wrong as stated, and
  EU residency is nonetheless what many EU customers demand
  contractually, which produces the same engineering
  requirement by a different route.

CANADA
  PIPEDA is federal and does not mandate residency. Some
  PROVINCIAL public-sector legislation does: British
  Columbia's FIPPA and Nova Scotia's PIIDPA have historically
  restricted storage and access of personal information held
  by public bodies to within Canada, with amendments over
  time. For a Toronto company selling to provincial public
  sector, this is the requirement that appears in the
  procurement questionnaire.

OTHERS worth knowing by name
  China's PIPL and the Cybersecurity Law: localisation for
    certain operators and data categories, with a security
    assessment for cross-border transfer.
  India's DPDP Act: transfer permitted except to
    government-notified restricted countries.
  Russia: localisation of citizens' personal data.
  Sector-specific: financial regulators and health regimes
    frequently impose their own, independent of general
    privacy law.

THE PRACTICAL POINT: the requirement usually arrives as a
CONTRACT CLAUSE from a customer, not as a statute you read.
Design for the capability, and let sales tell you which
regions.

Implementing residency

1. HOME REGION AS IDENTITY, not as a lookup.

   Put the region in the identifier:
     user id:  eu1_01HQ8Z... (region prefix + UUIDv7)
     or a token claim: {"sub": "...", "hr": "eu1"}

   Why: every service that receives an id can route without a
   lookup, and a lookup is itself a cross-region dependency
   that will be in the request path forever.

2. ROUTE AT THE EDGE, once.

   The edge resolves the home region from the token or the id
   prefix and forwards to that region. Downstream services
   never make the decision, so they cannot disagree.

   Unauthenticated requests (signup, login) route by a
   different rule: signup uses the user's stated country;
   login has to find the account, which means a small GLOBAL
   directory of (identifier -> home region) and nothing else.

3. THE GLOBAL DIRECTORY IS THE ONLY GLOBAL PERSONAL DATA, and
   it must be minimal: an email hash or a username hash mapped
   to a region. Not the email, not the name. Replicated
   everywhere, tiny, and defensible because a hash of a
   login identifier is the minimum needed to route.

4. SPLIT THE DATA MODEL EXPLICITLY.

   PERSONAL (region-pinned): users, orders, addresses,
     messages, uploads, audit logs referencing a person
   SHARED (replicated everywhere): the product catalogue,
     pricing rules, feature flags, configuration, ML model
     artifacts
   DERIVED (needs a decision): aggregates and analytics.
     Anonymised or aggregated above a threshold can usually
     move; per-user rows cannot.

5. CROSS-REGION FEATURES need a designed answer, not an
   accident:
     global search   -> search within the user's region only,
                        or a global index of shared data only
     admin tooling   -> an operator in one region viewing
                        another region's personal data IS a
                        transfer. Route the operator instead of
                        the data, and log it.
     reporting       -> aggregate per region, combine the
                        aggregates centrally
     a user moving   -> a documented migration, not an UPDATE.
                        Export, import, verify, delete, with an
                        audit record.

The admin-tooling case is the one that gets missed, because an internal tool feels like it is outside the system, and an operator in Toronto opening an EU customer's record is a cross-border transfer regardless of how the tool is built.

The alternative when full pinning is too expensive:

TOKENISATION / PSEUDONYMISATION

  Keep the identifying fields in the resident region behind a
  token vault; ship only tokens to the global system.

    EU region:    vault { tok_9f3 -> "ada@example.com", name,
                          address }
    Global system: order { customer: tok_9f3, sku, amount }

  The global system can compute, report and aggregate without
  holding personal data, and re-identification requires a call
  into the resident region.

  Cost: every display path needs a resolve call, and the
  vault is a single point of failure for anything
  user-facing.
  Right when: the personal data is a small fraction of the
  model and the processing is mostly non-personal.

The dependency audit

Enumerate what the recovery path needs, then check each item's own regional posture.

THE CHECKLIST, and each line has produced a real stuck
failover somewhere:

  IDENTITY
    [ ] Can you authenticate to the cloud console if the
        primary region is down? (SSO provider location)
    [ ] Is there a break-glass account with MFA that does NOT
        depend on the SSO provider, stored where you can reach
        it?
    [ ] Do your services' machine identities (tokens, certs)
        issue from a multi-region authority?

  DNS AND ROUTING
    [ ] Is your DNS provider multi-region? (Nearly all managed
        ones are anycast; a self-hosted one may not be.)
    [ ] Is the global load balancer's control plane
        independent of the failed region?

  SECRETS
    [ ] Is the secrets manager replicated? Can services in
        region B start without region A?
    [ ] Are the DR credentials themselves in the secrets
        manager you might not be able to reach? (circular)

  ARTIFACTS
    [ ] Is the container registry replicated, or does region B
        pull from a registry in region A?
    [ ] Are images CACHED in region B, so a registry outage
        does not block a scale-up?

  BUILD AND DEPLOY
    [ ] Does the runbook require CI/CD? Is CI single-region?
    [ ] Can you deploy without it, from a laptop, with
        credentials you can reach?

  CONFIG AND FLAGS
    [ ] Does the flag service have a regional cache and a
        safe default if it is unreachable, or does an
        unreachable flag service mean an unstartable service?

  CERTIFICATES
    [ ] Where does TLS issuance happen? Can region B renew
        without region A?
    [ ] What is the expiry horizon? A cert expiring during a
        multi-day incident is a documented compound failure.

  OBSERVABILITY
    [ ] If your metrics and logs pipeline is in the failed
        region, you are failing over blind.

  STATE YOU FORGOT
    [ ] Message queues, and whether in-flight messages are
        lost or replicated
    [ ] Scheduled jobs and cron: do they run in both regions,
        neither, or twice?
    [ ] Object storage: cross-region replication configured,
        and is it one-way?
    [ ] Third-party SaaS in the critical path (payment
        gateway, email, SMS): what is THEIR regional posture,
        and do you have a documented answer if they are down?

Run it as a tabletop, not as a form. Walk the runbook step by step and ask "what does this step need, and where does that thing live", because the checklist finds known dependencies and the walkthrough finds the ones nobody listed.

And the specific pattern to look for:

CIRCULAR DEPENDENCY: the recovery of X requires Y, and Y
requires X.

  the SSO provider you need to log in to fix the SSO provider
  the secrets manager holding the credentials for the secrets
    manager's own failover
  the deploy pipeline that deploys the deploy pipeline
  the observability stack you need to verify the fix to the
    observability stack

The fix is always the same shape: a BREAK-GLASS PATH that
depends on nothing in the loop. A local credential, a
pre-pulled image, a static configuration file, a documented
manual procedure. Stored somewhere reachable without the thing
it is breaking glass on, tested quarterly, and with its use
alerting loudly.

A worked example: an audit that found three stuck steps

A B2B SaaS company, two regions, a rehearsed failover runbook, and a residency requirement arriving with a European enterprise deal.

The dependency tabletop, run as a two-hour walkthrough of the existing runbook:

STEP: "Log into the AWS console and promote the replica."
  Needs: Okta SSO -> deployed in us-east-1 only.
  STUCK. If us-east-1 is the failed region, nobody can log in.
  Nobody had noticed because every game day had failed over
  us-west-2, the standby, which nobody logs in through.

STEP: "Scale up the us-west-2 deployment."
  Needs: pulls images from ECR in us-east-1.
  Cross-region replication was configured for the production
  repository and NOT for the three internal base images.
  STUCK on a scale-up requiring a fresh pull.
  Cached images on running nodes meant this had never
  surfaced: it only fails when a new node joins, which is
  exactly what a scale-up does.

STEP: "Verify with the dashboards."
  Needs: the observability stack, single-region, us-east-1.
  NOT STUCK, but blind: the failover would proceed with no
  way to confirm it had worked.

STEP: "Rotate the compromised credential."
  Needs: the secrets manager, replicated, fine.
  But the break-glass admin credential for the secrets manager
  was stored IN the secrets manager.
  Circular, and it had been that way for two years.

Three stuck or blind steps in a runbook that had been rehearsed four times, because every rehearsal failed over in the direction that did not exercise the dependencies.

"Every game day failed over in the same direction" is the finding worth generalising: a rehearsal that always moves from A to B never tests the dependencies that live in A.

The fixes:

IDENTITY
  - a break-glass IAM user per account, hardware-MFA, with
    credentials in a physical safe and in a separate password
    manager tenant hosted outside both regions
  - its use pages the security team automatically
  - tested quarterly, which found in the first test that two
    of the four listed holders had left the company

IMAGES
  - ECR replication extended to all repositories including
    base images
  - plus a pull-through cache in each region, so a registry
    outage does not block a scale-up at all

OBSERVABILITY
  - the metrics and logs pipeline made multi-region: the
    Collector gateway runs in both, and the backend is a
    managed multi-region service
  - plus a deliberately minimal "is it up" dashboard hosted
    entirely outside both regions, on the status-page
    provider, so a total loss of observability still leaves
    one signal

SECRETS
  - the break-glass credential moved out of the secrets
    manager into the physical/offline path
  - a documented rule: no credential required to recover
    system X may be stored in system X

GAME DAYS
  - alternate direction. Every other exercise now fails over
    FROM the primary, which is what surfaces the dependencies
    that live there.

"No credential required to recover system X may be stored in system X" is a one-line rule that generalises the whole circular-dependency category, and it is checkable.

The residency work, driven by the enterprise deal:

REQUIREMENT (contractual, not statutory): customer personal
data stored and processed in the EU, with a documented list of
any sub-processors outside it.

The data model, split in a two-day workshop:

  PERSONAL, region-pinned:
    users, organisations, documents, comments, activity logs,
    uploaded files, search indexes over the above
  SHARED, replicated:
    plan definitions, feature flags, templates, the ML model
    artifacts (trained on aggregated, anonymised data), the
    public help content
  DERIVED, decided case by case:
    usage analytics -> aggregated per region above a
      threshold of 50 organisations, then combined centrally
    billing -> the INVOICE lives in the EU; the payment
      gateway is a named sub-processor with its own regional
      posture, documented in the contract

IMPLEMENTATION:
  - user and organisation ids gained a region prefix
    (eu1_, us1_) rather than a lookup, because a lookup is a
    permanent cross-region dependency in the request path
  - the edge resolves the region from the id prefix or the
    token claim, once, and forwards
  - a global directory holding ONLY sha256(lowercased email)
    -> region, replicated everywhere, ~40 bytes per user
  - admin tooling: operators are routed to the region rather
    than data being routed to operators, and every access to
    personal data is logged with the operator, the subject and
    the reason

TIMELINE: 11 weeks, against an estimate of 2 quarters for the
retrofit-everything approach that had been assumed.

The saving came almost entirely from the id prefix: because
the region was in the identifier, no service needed a lookup
and no foreign key had to change meaning.

Putting the region into the identifier rather than into a lookup table is the decision that made it eleven weeks instead of two quarters, and it is the one thing worth doing before you have a residency requirement, because it costs nothing at the start and is the expensive part later.

Two things that were harder than expected:

1. BACKGROUND JOBS. A nightly job iterated all users to send
   digest emails. Split by region, it now runs twice, and the
   two runs disagreed about a shared rate limit for the email
   provider, briefly exceeding it.
   Fix: per-region quotas allocated from a shared budget,
   which is the general shape for any shared external
   resource under a regional split.

2. SEARCH. The search index over documents is personal data,
   so it had to be regional. A "search everything you have
   access to" feature for organisations with users in both
   regions became a scatter-gather across regions with
   per-region authorisation, which is slower and more complex
   than the single index it replaced.
   Accepted, with the latency cost measured and communicated,
   because the alternative was replicating personal data.

Production evidence

GDPR's actual mechanism is a restriction on transfers to third countries (Chapter V), not a storage mandate, and the Schrems II judgment of the Court of Justice of the EU invalidated Privacy Shield and required transfer impact assessments alongside standard contractual clauses. The commercial reality that EU customers demand EU residency contractually is separate from the statute and produces the same engineering requirement.

British Columbia's Freedom of Information and Protection of Privacy Act and Nova Scotia's PIIDPA have historically restricted the storage and access of personal information held by public bodies to within Canada, with subsequent amendments; they are the provisions that appear in Canadian public-sector procurement.

Cloud providers' residency controls (AWS Control Tower data residency guardrails, Azure's data residency documentation, Google Cloud's Assured Workloads) exist because the requirement is common enough to be a product, and their existence is the clearest evidence that customers ask for it contractually.

Circular dependencies in recovery paths are documented in AWS's own guidance on static stability and in post-incident writeups across the industry; the general principle, that a recovery path should not depend on the control plane it is recovering, is the reason "static stability" is a named design property.

Break-glass access with hardware MFA, offline storage and automatic alerting on use is standard practice in cloud security baselines (CIS benchmarks, cloud providers' well-architected security guidance), specifically because SSO is a single point of failure for administrative access.

Pull-through caches for container registries are provided by AWS ECR, Google Artifact Registry and Harbor precisely so that a registry outage or a cross-region dependency does not block a scale-up, which is the failure mode that only appears when a new node joins.

The debate

Is residency a legal requirement or a sales requirement? Usually the latter, and it does not matter for the engineering. GDPR restricts transfers rather than mandating storage, and most residency work is driven by a contract clause a customer's procurement team wrote, so the right posture is to build the capability and let sales tell you which regions, rather than to argue about the statute.

Region in the identifier, or a lookup table? In the identifier. A lookup is a cross-region dependency in the request path forever, and it becomes a single point of failure for routing. The counter-argument is that ids become opaque and a user cannot move regions without a new id, which is true and is the correct trade: moving regions should be an explicit migration with an audit record, not an UPDATE.

Should you tokenise instead of pinning? When the personal data is a small fraction of the model and the processing is mostly non-personal, tokenisation gives you a global system with a small resident vault. The cost is a resolve call on every display path and a vault that is a single point of failure for anything user-facing, so it is a genuine alternative rather than a shortcut.

How thorough should the dependency audit be? Thorough enough to walk the runbook line by line and ask what each step needs. A checklist finds the dependencies you already know about; the walkthrough finds the ones nobody listed, and in the worked example the walkthrough found three stuck steps in a runbook that had been rehearsed four times.

Is break-glass access a security risk? It is a deliberate, monitored one, and the alternative is worse. A break-glass credential with hardware MFA, offline storage, quarterly testing and automatic paging on use is a controlled risk; having no path when SSO is down is an uncontrolled outage. The quarterly test matters: in the worked example the first test found that half the listed credential holders had left the company.

Do game days need to alternate direction? Yes, and this is under-appreciated. A rehearsal that always fails over from the standby to the primary, or that always goes the same way, never exercises the dependencies living in the region you would actually lose. Alternating is free and it is what surfaced all three stuck steps.

Follow-up Q&A

"Does GDPR require EU data residency?"

No. It restricts transfers to third countries without an adequacy decision or appropriate safeguards, and after Schrems II that means standard contractual clauses plus a transfer impact assessment. What produces the engineering requirement is usually a contract clause from an enterprise customer's procurement team, which is a commercial fact rather than a statutory one and creates the same work. The correct posture is to build the capability, keep a documented sub-processor list, and let sales tell you which regions.

"How do you implement residency without a rewrite?"

Put the home region in the identifier rather than in a lookup table, so every service can route from an id or a token claim without a cross-region call. Resolve the region once at the edge and forward. Keep a minimal global directory of hashed login identifier to region, which is the only globally replicated personal data and is defensible because it is the minimum needed to route. Then split the model explicitly into personal, shared and derived, and give the cross-region features a designed answer: route operators to the data rather than data to operators, aggregate per region and combine the aggregates, and treat a user changing region as a migration with an audit record rather than an UPDATE. In one case the id-prefix decision took an eleven-week project that had been estimated at two quarters.

"What is the dependency audit and how do you run it?"

Walk the failover runbook line by line and ask, for each step, what it needs and where that thing lives. Identity, DNS, secrets, container registry, CI/CD, certificates, config and flags, observability, message queues, cron, object storage replication, and any third-party SaaS in the path. Run it as a tabletop rather than a form, because a checklist finds the dependencies you already know about and a walkthrough finds the ones nobody listed. In one case that found three stuck or blind steps in a runbook rehearsed four times.

"Give an example of a circular dependency in a recovery path."

The SSO provider deployed only in the primary region: step one of the runbook is to log into the cloud console, and nobody can, because the identity provider is in the region that failed. Or the break-glass admin credential for the secrets manager stored inside that secrets manager. Or a deploy pipeline that is required to deploy the deploy pipeline. The fix always has the same shape: a break-glass path depending on nothing in the loop, stored somewhere reachable without the thing it breaks glass on, tested quarterly, and paging loudly when used. The generalisable rule is that no credential required to recover system X may be stored in system X.

"Why did a rehearsed runbook still have stuck steps?"

Because every game day failed over in the same direction. Rehearsing a failover from the standby to the primary, or always exercising one path, never touches the dependencies that live in the region you would actually lose. In one case that meant nobody discovered that the SSO provider, the base container images and the entire observability stack were single-region in the primary, because no rehearsal had ever required them to be unavailable. Alternating direction is free and it surfaced all three.

"What breaks when you split a system by region?"

Two things people miss. Background jobs now run once per region, so anything with a shared external quota needs per-region allocation from a shared budget, which one team discovered by briefly exceeding an email provider's rate limit. And any global index over personal data becomes regional, so cross-region search for an organisation with users in both regions turns into a scatter-gather with per-region authorisation, which is slower and more complex than the single index it replaced. That cost was accepted and measured, because the alternative was replicating personal data.

Common misconceptions

"GDPR requires data to stay in the EU." It restricts transfers without safeguards. The residency requirement usually comes from a customer contract, which produces the same work by a different route.

"Encrypting it makes it non-resident." A copy in another jurisdiction is still a copy there for most regimes, though key location and access control matter contractually and for some rules.

"Look up the user's region from a table." That is a cross-region dependency in the request path forever, and a single point of failure for routing. Put it in the identifier.

"Internal admin tools are outside the residency boundary." An operator viewing personal data across a border is a transfer. Route the operator, and log the access.

"Our failover is rehearsed." In one case rehearsed four times, with three stuck or blind steps, because every rehearsal went the same direction and never required the primary region's dependencies to be unavailable.

"Break-glass credentials are a security risk we should avoid." The controlled version, hardware MFA, offline, quarterly-tested, paging on use, is a managed risk. Having no path when SSO is down is an uncontrolled outage.

Interview delivery note

Say this verbatim: "Put the home region in the identifier rather than in a lookup table, because a lookup is a cross-region dependency in the request path forever. That one decision took an eleven-week residency project that had been estimated at two quarters, since no service needed a lookup and no foreign key had to change meaning." It is a specific, cheap, early decision with a measurable consequence.

The senior-versus-staff separator is auditing the recovery path rather than the request path. A senior engineer diagrams the system. A staff engineer walks the failover runbook line by line asking what each step needs and where that lives, finds that step one requires logging into a console through an SSO provider deployed only in the region that just failed, and generalises it into a rule that no credential required to recover system X may be stored in system X. The circular dependency is invisible on any architecture diagram because it is not in the request path.

The second signal is noticing that every game day went the same direction. Saying "the runbook had been rehearsed four times and still had three stuck steps, because we always failed over toward the standby and never required the primary's dependencies to be unavailable" shows you evaluate the test as well as the system, which is the same instinct as auditing a load-test rig before its results.

Further reading

  • GDPR Chapter V on international transfers, and the Schrems II judgment, for what the regulation actually restricts.
  • British Columbia's FIPPA and Nova Scotia's PIIDPA provisions on storage and access of personal information by public bodies, for the Canadian public-sector requirement.
  • AWS Builders' Library on static stability, for why a recovery path should not depend on the control plane it recovers.
  • Cloud provider residency products (AWS Control Tower guardrails, Azure data residency, Google Assured Workloads), for the shape of the controls customers ask for.
  • The failover decision and runbook page, which is the runbook this audit is run against.