Bearer-neutral edge connectivity¶
Decision¶
PETRA treats Cloudflare, Wi-Fi, HaLow, cellular, Starlink, Ethernet and customer radios as interchangeable IP bearers. They provide reachability; they do not provide PETRA identity, authority or data trust. If an Android phone can route to a configured PETRA service and validate its TLS certificate, PETRA can use that path.
PETRA does not provision or manage OpenWrt, Wi-Fi, HaLow or radio appliances. Their setup is deployment context, like a carrier network. This boundary keeps field operation legible: operators diagnose the bearer, DNS, TLS, Directory and Zenoh as separate layers.
Trust and DDIL assumptions¶
- The managed Android OS is trusted while in use; it is not assumed to be actively compromised. A captured phone is contained by keeping only the current session's bounded data and keys, then applying expiry, revocation, wipe and group-key rotation.
- The network is hostile and unreliable. TLS/QUIC authenticates configured services; Directory-issued authority, application signatures, replay protection, classification and revocation remain authoritative above the transport.
- Directory and Web run in a physically protected, reliably connected Core. Cloud, on-prem cloud and deployment-specific diodes are outside this edge-connectivity decision.
- Losing internet removes the Cloudflare path. PETRA reports that loss, preserves valid DDIL caches, and reconnects when a usable bearer returns. It does not invent an embedded-IP or insecure DNS fallback.
This is deliberately similar to the ordinary banking model: do not trust the access network; authenticate the service with TLS and the principal in the application. Optional mTLS may add deployment-wide socket admission, but it does not replace PETRA identity.
Android per-app WARP incident¶
The demonstrated failure came from Cloudflare One's Android per-app VPN routing:
- the profile included
com.waypoint.androidand Chrome; - Android represented those packages inside the VPN as numeric UIDs;
- reinstalling PETRA assigned a new UID, while the running VPN sometimes retained the old UID until Cloudflare One restarted;
- Chrome still used WARP and completed WebAuthn, but PETRA used the underlying network;
- PETRA's native Directory exchange then failed DNS resolution and the UI reduced the result to “Could not reach the server”.
The phone reproduced two forms of the mismatch directly. With the original package selectors,
PETRA's installed UID was absent from the active VPN UID ranges while an unowned stale UID
remained. After every selector was removed in Hexnode's editor, Hexnode delivered one blank
bundle child; Cloudflare One remained connected but exposed Uids: <{}>, installed no VPN rule
for Chrome or PETRA, and both applications bypassed its private DNS path. A fresh
auth.bedrock.lan request then returned NXDOMAIN even though Cloudflare One reported that it
was connected. That connected state was a failed canary, not evidence of full-device routing.
The later 2026-08-31 canary removed the Cloudflare One App Configuration assignment while
retaining the managed install and existing organisation enrollment. ConnectivityService then
reported one validated Cloudflare VPN over Wi-Fi with ranges 0-10144, 10146-20144 and
20146-99999. The two omitted UIDs are one atomic Android package exception: application UID
10145 resolved only to Google Play Store, and UID 20145 is its derived SDK-sandbox companion.
Chrome and PETRA were both inside the VPN. PETRA was uninstalled and reinstalled without
restarting Cloudflare One, changed from UID 10330 to 10331, and remained covered. Chrome
WebAuthn, the native Directory exchange, capability refresh, private-name resolution and both
configured Zenoh routers then passed. This closes the stale numeric PETRA-UID failure and proves
PETRA/Chrome route continuity under the approved exact-Play-Store exception. It does not prove
disconnected DDIL, a Wi-Fi/WAN move, the owned-name reset or a digest-locked release candidate.
The coupled gap is not a residual Hexnode package selector. The device has no Android always-on
VPN package, lockdown mode or lockdown allow-list. Android's
VpnService.Builder
includes every application by default unless the VPN calls addAllowedApplication or
addDisallowedApplication. Read-only inspection of the exact installed Cloudflare One 2.5.5
APK found that its VpnSplitTunnel construction unconditionally calls
addDisallowedApplication("com.android.vending") before applying any configured excluded-app
list. Android's VPN implementation
automatically adds the corresponding SDK-sandbox UID for each allowed or disallowed application;
the platform mapping
derives it from the application UID in the same Android user. One excluded Play Store package
therefore appears as two coupled UID gaps, not two package exclusions.
The approved deviation is deliberately fail-closed. Evidence must resolve com.android.vending
at runtime for the active user and prove that no other package shares its UID. On API 33 and
later it must derive the companion SDK-sandbox UID and require both UIDs to be routed or both to
be the only package-derived gaps; earlier supported releases have only the application UID. It
must likewise prove that only com.cloudflare.cloudflareoneagent owns the VPN-owner UID, which
may remain the sole additional omission. A one-sided pair where applicable, a hard-coded UID,
any unrelated gap, an empty VPN range or an application allow-list still fails. Cloudflare
documents tunneled_apps only as a per-app allow-list and exposes no setting that restores Play
Store to an otherwise full-device Android tunnel.
Two independent conditions amplified the failure:
.lancan be subject to local-domain fallback or venue DNS, depending on the effective Cloudflare profile; and- native HTTP and Zenoh sessions did not always rebuild when WARP appeared after Wi-Fi was already available.
Cloudflare's Local Domain Fallback documentation
lists lan among the default local suffixes. During the 2026-08-31 incident inspection the
live account had no lan fallback entry, so the reproduced NXDOMAIN is not attributed to Local
Domain Fallback. The design still avoids suffix and venue-DNS ambiguity by using an owned
namespace.
One-rack v1 profile¶
The one-rack demo uses:
- dashboard-managed Traffic and DNS/full-device WARP on dedicated PETRA phones, preserving an enrolled handset's proven absence of Cloudflare App Configuration;
- stable private-hostname routes in the owned
bedrockdefence.comnamespace; - one outbound
cloudflaredconnector on privilegedcore-01; - the rack LAN between the two equivalent stock-Zenoh routers; and
- a closed Cloudflare L4 allow-list for phone-facing service ports followed by a catch-all block for those rack destinations.
The L4 policy is network exposure control, not PETRA authentication. It remains important because some rack services, such as tiles and media, are intentionally unauthenticated and other management listeners must not become reachable from the shared WARP organisation. The demo deliberately does not couple this boundary to Cloudflare device UUIDs, Android posture checks or MDM asset tags. Any phone admitted to the WARP organisation receives only the exact routed L4/SNI opportunity; TLS, plus PETRA identity and authority where the service uses them, remains the trust boundary above it. This keeps the dev/test configuration legible and avoids turning device inventory synchronisation into a second application admission system.
The dashboard profile for this bearer-neutral demo must not enable VPN lockdown, so a phone can
continue on a local Wi-Fi/HaLow or customer-radio route when that bearer can reach the same
configured names. Cloudflare recommends
supplying only organization when MDM is needed for enrollment and managing all other settings
in the dashboard because local MDM values take precedence. Its current
MDM parameter reference
defines warp as the default Traffic and DNS mode and organization as the value that registers
the device with the Zero Trust organisation.
The Hexnode organization-only payload is therefore an optional reference for a fresh,
unregistered handset. It has exactly one app_config_bundle_list child containing only
organization and omits tunneled_apps, local service_mode, onboarding, switch_locked,
auto_connect, per-device PETRA locators and enrollment secrets. It is not assigned to an
already-enrolled canary whose registration and full-device route have passed without Cloudflare
App Configuration. Each phone still authenticates as its own PETRA principal.
Hexnode may serialize its empty bundle editor as one blank tunneled_apps child even after
every package is removed. Cloudflare One Android 2.5.5 retains that child as a non-empty
per-app list, cannot resolve the blank package name, and creates a VPN for zero application
UIDs. That delivered form is an unconditional failure even though the UI looks empty.
Do not create, clone, assign, edit, remove or replace Cloudflare App Configuration on the
enrolled canary, and do not synthesize an empty app_config_bundle_list, a literal zero-length
tunneled_apps array or a blank child to represent absence. If a separately approved fresh,
unregistered handset needs MDM-assisted enrollment, create the organization-only payload from
the reference; the effective restrictions and runtime route remain authoritative, not the
Hexnode editor or Cloudflare One's connected indicator.
The current rack has only one host suitable for the Tunnel credential. cloudflared maintains
multiple outbound edge connections, but loss of core-01 still removes the remote Cloudflare
path. Valid DDIL caches remain intact; local operation continues only where another bearer can
still route the configured names. A second host-level replica requires another trusted connector
host; the content-blind router and isolated media host are not widened merely to claim failover.
This is a bounded deployment limitation, not a reason to add Mesh or a second rack.
Android recovery contract¶
Android observes both its default network and every app-visible network. Availability, capability, address, DNS, route and loss changes all enter one bounded recovery path. A burst of Android callbacks is conflated, a healthy configured router link is left alone, and a dead stock-Zenoh dial is recreated using the unchanged locator set. Directory HTTP drops idle connections and retries through the new route.
Diagnostics retain the failing application layer while adding path context. Operators can distinguish no bearer, no validated internet, no VPN where the deployment expects WARP, DNS, TCP/timeout, TLS, Directory and Zenoh failures. A local-only tactical bearer is not rejected merely because Android does not label it general internet.
Managed-handset reassignment boundary¶
PETRA owns and clears its session database, credentials, content and offline-map caches, active notifications, crash report and PETRA-tagged clipboard entries before another session can start. The Android client also prevents its activity from appearing in screenshots, non-secure displays and the Recents task snapshot. It does not erase an unrelated clipboard entry merely because a session ends.
Some residue belongs to the trusted Android platform rather than PETRA. Notification history, bounded system log buffers and input-method learning are not app-wipeable. Active PETRA notifications therefore use generic text. A deployment may apply stricter MDM controls or factory-reset a reassigned handset when its handling policy requires clearing Android-owned residue, but package allowlists, overlay restrictions, device-attestation gates and similar platform hardening are not PETRA runtime requirements.
PETRA strictly validates the WebAuth callback and uses random state plus S256 PKCE, so an intercepted authorisation code is unusable without PETRA's app-private verifier. Another application or an actively compromised Android platform can still deny service; that is outside the accepted threat model rather than a condition PETRA tries to solve with another admission system. Development and demo builds must not be used with real classified data.
Rack roaming and future Mesh¶
Moving a phone between HaLow/Wi-Fi bubbles, cellular, Starlink or customer radios changes reachability, not PETRA configuration or identity. The same owned hostnames, TLS trust bundle, Directory identity and router locators remain in use.
Cloudflare Mesh does not fix the Android UID problem and is not needed inside one rack. It is deferred until two racks require symmetric rack-to-rack Zenoh connectivity. At that point the network layer must provide non-overlapping rack routes; PETRA continues to consume ordinary IP reachability. Stock Zenoh remains the baseline unless a physical reproducer shows that a small upstreamable change removes material PETRA recovery or operator complexity.
Acceptance sequence¶
The original WARP UID failure is proved closed. Preserve that state during the owned-name and CA cutover:
- record the current canary-only assignments and effective non-secret configuration. Require
the already-enrolled device to remain registered to the intended organisation with no
effective Cloudflare App Configuration, the expected dashboard-managed mode and the passing
full-user WARP scope. Do not create, clone, assign, edit, remove or replace Cloudflare App
Configuration; do not synthesize an empty
app_config_bundle_listor blank child; and do not restart Cloudflare One. Keep Required App, install and enrollment unchanged; - after the owned routes and rack leaves are ready, apply only the exact
bedrock-rack-ca.pemin the Default keystore and the exact, unedited Infrastructure-generatedpetra.jsonto this one canary, applying the CA first. Relaunch only PETRA if the delivered managed configuration is not reflected. Make no Cloudflare policy or application change; - rerun the read-only exact-serial WARP UID gate against the still-active VPN. Record the current
Android user and the Cloudflare One, Chrome, PETRA and Play Store package UIDs. Resolve the Play
Store UID's package set and require exactly
com.android.vending; resolve the VPN-owner UID's package set and require exactlycom.cloudflare.cloudflareoneagent. On API 33 and later, derive the Play Store SDK-sandbox companion for that user; earlier supported releases have only the application UID. The VPN ranges must cover every other UID in the user's100000-UID interval. The VPN-owner UID may be included or omitted independently, and the applicable Play Store UID set may be fully covered or the only package-derived gap. Reject a one-sided pair, unrelated gap,Uids: <{}>or narrower application allow-list; and - rerun the read-only owned-name, DNS/Gateway, TLS, PETRA and Zenoh gates. Require Chrome/platform
and PETRA's native clients to accept the rack-issued leaves, the existing PETRA session to
refresh Directory keys, group keys and capabilities, and both exact routers from
petra.jsonto be live. Do not broaden the MDM assignment while any gate is open.
The reinstall, WARP/Wi-Fi/WAN movement and DDIL recovery exercises remain separately approved later gates; they are not part of this one-canary MDM cutover. No live MDM, Cloudflare, CA, rack or handset mutation follows merely from merging this document.