> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dataerai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Geobounds operations

> For operators: the GEOBOUNDS_ENABLED kill-switch, configuring a signal provider, trusted-proxy hops, the no-bypass recovery path, and why government lists are deny-kind country sets.

Use this page if you operate a Dataerai deployment and need to turn on, configure, or recover [project geobounds](/sharing/geobounds). Geobounds are **off by default** and require operator configuration before they enforce anything.

## The kill-switch: `GEOBOUNDS_ENABLED`

The entire feature is gated by one setting:

| Setting             | Default | Effect                                                                                                                                                                                                                              |
| ------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GEOBOUNDS_ENABLED` | `False` | When `False`, the geobound gate is a **complete no-op** — every read behaves exactly as if no project had a geobound, regardless of project policy. When `True`, enforcement is active for every project whose geobound is enabled. |

Leaving it `False` is safe: project owners can configure geobound policy, but nothing is enforced until you flip the switch. Set it `True` only after you have configured a trusted signal provider (below) — otherwise every fail-closed project will deny all reads, because the viewer's region is always unknown.

<Warning>
  Turn `GEOBOUNDS_ENABLED` on **after** configuring a signal provider. With the switch on but no provider, IP country is always unknown, so every fail-closed geofenced project denies all access — including to its owners and to system admins.
</Warning>

## Configuring a signal provider: `GEOBOUNDS_SIGNAL_PROVIDER`

Region and VPN/proxy evidence come from a pluggable signal provider you configure:

| Setting                     | Default   | Effect                                                                                                                                                                                                                              |
| --------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GEOBOUNDS_SIGNAL_PROVIDER` | *(empty)* | A dotted import path to the provider that resolves a request's IP country and VPN/proxy status. The default (empty) is the **null provider**: it reports everything as *unknown*, so under fail-closed every fenced project denies. |

Point this at a provider backed by your IP-intelligence source (a GeoIP database, a commercial VPN/proxy feed, etc.). The provider's job is to turn the trusted client IP into a country code and a VPN/proxy flag; the geobounds evaluator owns the allow/deny decision.

## Trusted client IP: `GEOBOUNDS_TRUSTED_PROXY_HOPS`

Geobounds derive the client IP from the `X-Forwarded-For` header so it reflects the real viewer behind your edge, not your load balancer:

| Setting                        | Default | Effect                                                                                                                             |
| ------------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `GEOBOUNDS_TRUSTED_PROXY_HOPS` | `0`     | How many right-most `X-Forwarded-For` entries are your own trusted proxies. The client IP is taken from just inside that boundary. |

Set this to the number of reverse proxies / load balancers between the public internet and the application, so a client cannot spoof its country by injecting `X-Forwarded-For` entries. Getting this wrong is a security issue: too low and clients can forge their apparent country; too high and you trust an attacker-controlled hop.

## No bypass — recovery is a policy edit

Geobounds enforce **all-access, no-bypass, fail-closed** semantics:

* The fence applies to anonymous / public-link readers, directly-granted users, organization members, and **system administrators** alike.
* There is **no request-time override** — no header, query parameter, or admin "unlock" reads a fenced project from outside the fence.
* A locked-out owner or admin can only be recovered by an **out-of-band policy edit**: an operator with database or Django-admin access sets `geobound_enabled = False` on the affected Project row.

This is deliberate. The recovery path is intentionally narrow so the fence cannot be quietly circumvented; document it in your runbook and restrict who can perform it.

## Government lists are deny-kind country sets

`GeoBoundCountrySet` rows are versioned, source-attributed reference lists, each with a `kind`:

* **allow** — permits only the listed countries (geographic groupings).
* **deny** — blocks the listed countries no matter what else permits them.

**Government, sanctions, and export-control lists (for example OFAC or ITAR §126.1) are deny-kind sets.** Deny always wins over any allow rule. Country sets carry source and version metadata so you can update them deliberately as the underlying lists change — the platform does not interpret them legally for you. Country sets are read-only to ordinary users and writable only by system admins via `POST /api/geobound-country-sets/`.

<Note>
  The geobounds evaluator does no live network calls during access evaluation, and the platform does not automatically interpret the legal meaning of a government list. You own keeping deny-kind sets current and correct.
</Note>

## Verification

When you enable geobounds, confirm:

* With `GEOBOUNDS_ENABLED=False`, fenced projects are reachable as normal (no-op).
* With it `True` and a provider configured, a viewer outside the fence is denied on every read surface, and a viewer inside is allowed.
* A system admin outside the fence is **also** denied (no bypass).
* The only way back in for a locked-out project is editing `geobound_enabled` on the Project row.

The backend unit suite `api/tests/test_geobounds_acl.py` exercises the IP-based allow/deny, fail-closed, basis modes, VPN blocking, allow/deny sets, and the no-bypass guarantee against a stub signal provider.

## Next steps

<CardGroup cols={2}>
  <Card title="Geographic access fences" icon="globe" href="/sharing/geobounds">
    The end-user view of geobounds.
  </Card>

  <Card title="Organization administration" icon="settings" href="/account/administration">
    Other things operators and org admins manage.
  </Card>
</CardGroup>
