Repository navigation
Axum: add optional Geo providers for local GeoIP databases and trusted CloudFront metadata #432
Description
Goal
Add optional native Geo providers so Axum applications can obtain geographic facts from either a local GeoIP database or trusted CloudFront metadata. Follow the explicit provider selection and startup ownership used for native AWS services, without treating Geo as a config, secret or KV store.
Track this as a separate follow-up under #391. Do not expand the AWS store-provider PR #414 to include geography.
Why this is needed
The checked native ingress work in #409 provides client-IP facts and their provenance. It does not provide visitor country or subdivision. Trusted Server's native PlatformGeo currently returns no geography, leaving jurisdiction unknown. Its intentional fail-closed auction/identity behavior is documented in IABTechLab/trusted-server#1134.
An AWS deployment region is not visitor geography. A browser language, timezone, arbitrary country header or missing TCF string is not a substitute either.
Provider contract and ownership
- Expose typed geographic facts through the existing request/runtime composition model: at least optional country and subdivision, with provider provenance and explicit unavailable/partial/error behavior. Do not invent a country, region, city or coordinates to fill missing fields.
- EdgeZero owns provider mechanics and checked metadata. Applications own jurisdiction classification, regulatory lists, CMP interpretation, consent and auction/identity decisions. Geography is an estimate, not proof of residency or consent.
- Provider selection is explicit and optional. Absence remains unavailable; a configured provider must not silently switch to another source. Keep native provider dependencies default-off and preserve portable/WASM contracts.
- Reuse existing native startup/initializer ownership and explicit runtime options or bindings patterns. No new general plugin framework is required. A selected unusable local database fails startup before readiness; an application that selects no Geo provider can still run.
flowchart TD
Selection[Explicit native Geo selection] --> Local[Local GeoIP provider]
Selection --> CloudFront[Optional CloudFront provider]
IP[Checked reader IP] --> Local
Ingress[Verified front-door metadata] --> CloudFront
Local --> Facts[Geographic facts and provenance, or unavailable]
CloudFront --> Facts
Facts --> App[Application jurisdiction and consent policy]
Initial providers
Local GeoIP database
- Resolve the checked effective reader IP, not an unconditionally selected X-Forwarded-For value or the load balancer's address.
- Use an operator-supplied database format that can provide country and subdivision. Country-only data must retain the fact that subdivision is unknown.
- Load and validate the database through bounded native startup preparation. Document read-only mounts, supported format, licensing, data version/freshness and explicit replacement/restart behavior.
- Do not download a database implicitly or send visitor IPs to an external lookup service. Missing matches and unresolved reader IPs remain unavailable.
Trusted CloudFront metadata
- Optionally consume CloudFront country and country-region headers through a checked ingress boundary, with strict parsing and explicit missing/partial behavior.
- Require a deployment-owned, protected CloudFront-to-origin path and header provenance. Reaching the application through a trusted ALB subnet alone does not prove that a geographic header originated at CloudFront.
- Reject or ignore spoofed, duplicate, malformed or untrusted assertions. Never trust raw geographic headers supplied directly by a client.
- Keep CloudFront provisioning and origin access configuration in deployment guidance, not automatic SDK infrastructure mutation. Header consumption should not require AWS store providers or AWS SDK calls.
Acceptance
- Explicit selection, default-off dependencies and provider availability have focused tests; selected invalid configuration fails before listen without local/provider fallback.
- Local database fixtures exercise country/subdivision, IPv4/IPv6, unresolved reader IP, no match, malformed database and read-only startup.
- CloudFront ingress fixtures exercise a verified source, direct-client spoofing, an ALB forwarding unverified headers, malformed/duplicate assertions and missing subdivision.
- Consumers can distinguish unavailable or partial geography from a known result. In particular, US country with no state retains an unknown subdivision; the provider makes no claim about which privacy regime applies.
- Documentation shows local-database and protected CloudFront deployments, privacy-safe diagnostics, capability limitations and the difference between geographic facts and application policy.
- Existing adapters, native lifecycle behavior and WASM/default dependency checks remain intact. Record fixture evidence separately from any real CloudFront deployment acceptance.
Geo remains optional for general Axum hosting. A downstream profile that depends on geography must demonstrate its configured provider or retain its existing fail-closed behavior. This issue does not authorize changing Trusted Server's consent rules, adding an assumed jurisdiction, or implementing an identity database.
Related
- Parent epic: Make the Axum adapter production-ready for self-hosted deployments #391
- Checked native ingress: feat(axum): add safe diagnostics and trusted proxy metadata #409
- Related client metadata work: Axum ClientInfo #92
- Native provider composition reference, separate scope: Add native AWS store providers #414
- Downstream adoption and policy: An adapter with no geo module fails closed on Edge Cookie creation and on the auction trusted-server#1134
- CloudFront header reference: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/adding-cloudfront-headers.html
Activity
ChristianPavilonis commentedon Oct 22, 2026
Implementation scope is split for the initial delivery. The pluggable synchronous Geo contract and protected CloudFront provider follow the reviewed specification; local databases, checked-reader-IP inputs and database lifecycle are deferred to #438. CloudFront support will not satisfy the local-database acceptance items above. Native celld remains the base of the implementation stack. Actual CloudFront/ALB deployment acceptance and Trusted Server adoption stay separate from local implementation proof.