Skip to content
Latchkey

How to Enforce Data Residency in CI

Pinning runners and artifact storage to a region, then asserting the region at runtime, keeps regulated data from leaving its jurisdiction during CI.

Some data must stay in a region. In CI that means region-scoped runners and region-scoped artifact buckets, plus a runtime assertion so a misconfigured job fails loudly. This page shows the pattern; it is educational, verify residency needs with your own counsel.

Steps

  • Target self-hosted runners labeled by region.
  • Point artifact and cache storage at a bucket in the same region.
  • Assert the runner region at runtime and fail if it is wrong.

Region-pinned job

.github/workflows/ci.yml
jobs:
  build-eu:
    runs-on: [self-hosted, region-eu-central-1]
    env:
      AWS_REGION: eu-central-1
      ARTIFACT_BUCKET: acme-ci-artifacts-eu
    steps:
      - name: Assert region
        run: |
          R=$(curl -s http://169.254.169.254/latest/meta-data/placement/region)
          [ "$R" = "eu-central-1" ] || { echo "Runner not in EU: $R"; exit 1; }
      - run: ./build.sh && aws s3 cp dist/ "s3://$ARTIFACT_BUCKET/" --recursive

Notes

  • GitHub-hosted runners do not guarantee a region; use self-hosted for hard residency needs.
  • The runtime assertion catches label or infrastructure drift before data is written.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →