Files
HIPs/HIPs/hip-1173-network-the-zero-trust-overlay.md
zeekay ad5a010f79 Three words for what a proposal is, and a generator that refuses
The same fact lived in nine hand-kept places and they disagreed about 58
proposals. This makes the file the only authority and everything else a
projection of it.

ONE VOCABULARY, in vocabulary.json, read by the lint, the generator and the
doc site. Three words, each answering "can I rely on this?" and nothing else:

    Draft    nothing implements it yet, or its own text says the work is ahead
    Final    the thing it specifies exists in the code
    Living   governance and process: amended in place, never finished

Eight spellings folded in. `Active` was the one doing real damage: on four Meta
and Process HIPs it meant living, on 48 others it meant shipped, and one word
doing two jobs is why nothing agreed. `Review` and `Last Call` described a
queue rather than a document, and a proposal under review is still one you
cannot build against.

STATUS IS EARNED, not declared. Every Standards Track proposal was checked
against the estate: 235 have their implementation, and eight do not and say so.
HIP-0095 carries a twelve-week plan ending at "mainnet launch" and has no code.
HIP-0525 specifies an all-machine meeting while apps/meet refuses a machine a
seat. HIP-0078 names a prover at a "planned location" that does not exist.
HIP-0114 is the cog.* procedure set, and that procedure set returns nothing.
HIP-0003, HIP-0102, HIP-0305 and HIP-0901 likewise: looked, found nothing.

SIXTEEN TOMBSTONES DELETED rather than statused. A dead document kept alive in
the index is one concept wearing two names. Each successor exists and carries
the text, and the 90 references that pointed at a tombstone now point at it --
whole markdown links at once, so link text cannot outlive its target. Three of
the sixteen were pure compatibility: HIP-0028 specified a migration off a
Bitnami chart, HIP-0029 dual-engine MySQL, HIP-0030 a schema-deprecation
policy. We ship no backwards compatibility, so we do not specify it.

Nine links were already broken and had been since the corpus was renumbered:
short-form ./hip-5.md paths that never existed. Two named the wrong proposal --
one cited "HIP-1: Hanzo Multimodal Models" where multimodal is HIP-0003.

THE GENERATOR REFUSES more often than it writes, because a short table looks
exactly as authoritative as a complete one. Rows must equal files; a shrinking
index must say by how much; a section whose input is missing is an error, not
an omission; nothing is written until all of it validates. Its self-test breaks
the corpus eleven ways and requires each to refuse AND leave README byte-
identical -- a guard that reports after half-writing has protected nothing.
The lint's second implementation of the same comparison is gone.

The site rendered 52 proposals with a fallback grey badge and counted them
toward none of its three stat tiles, because docs/lib/source.ts declared a
status union by hand: it admitted a `Stagnant` no file has ever carried and
omitted the one 52 files did. Five components each kept their own copy of the
colours. All six now read vocabulary.json.
2026-08-28 18:05:41 -07:00

8.6 KiB
Raw Permalink Blame History

hip, title, author, type, category, capability, status, created, requires
hip title author type category capability status created requires
1173 Network — An Org-Scoped Overlay Hanzo AI Standards Track Infrastructure network Final 2026-08-20 HIP-0026, HIP-0106, HIP-0139

HIP-1173: Network — An Org-Scoped Overlay

Abstract

/v1/network is the tenant's Hanzo Zero Trust footprint: the overlay, its routers and its mesh services, org-scoped, off the unified cloud binary. It fronts the Hanzo Zero Trust controller (hanzoai/zt, an OpenZiti-based fabric) and translates it into the shape a tenant reads. It is implemented in hanzoai/cloud at apps/network (HIP-0106).

Motivation

A private fabric is only useful if its operator can see it. Everything the controller knows — which routers are online, which services are dialable, where they are — is admin data behind a service credential, and a tenant holds no such credential and must never be handed one. The one thing a tenant may have is their own slice of it, selected server-side and read-only. That is what this capability is: a filter with an address, and no second control plane.

Specification

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as in RFC 2119.

§1 It owns no store

Every row is the controller's. Nothing here is written and nothing is cached across requests except the management session token, which is held only until its expiry and re-minted transparently.

The overlay network is not even a stored object anywhere. An org has at most one, and it is projected from the edge-routers carrying that org's role attribute: its id is derived from the org, its node count is the real router count, and its status is connected once at least one router has dialled home and provisioning while none has. An org with no routers has no network, and the answer is an empty list. A fabricated network would be worse than no network, because a tenant would build on it.

§2 The boundary: east–west, not the edge

Three capabilities touch a packet and only one of them is this.

  • ingress (HIP-1133) is the edge: TLS and hostname routing for traffic arriving from the public internet.
  • gateway (HIP-1127) is the policy applied to a request that has already arrived: CORS, rate ceiling, cache TTL, allowed methods.
  • network is neither. It is the private fabric between the things a tenant runs, where a service is reachable because an identity was granted it and not because a name resolves. Nothing it lists has a public address at all.

share (HIP-1152) is the useful contrast: it gives one local service a public URL. network gives a set of services no public URL, and reachability is the grant.

Within the fabric, enrolment, policy and identity remain the controller's own surface. This capability reads; it does not admit. A surface that could enrol an identity would be a second control plane over one fabric, which is the shape HIP-0139 §7 refuses.

§3 The addresses

One prefix, and every operation on it is typed: GET /v1/network, GET /v1/network/routers, GET /v1/network/{id} and GET /v1/network/services. No route here is declared with prose, because every answer is a value.

It was two — /v1/network and /v1/mesh — and both were lines in the misfiled ratchet (HIP-0139 §5.1). They closed together by fold (HIP-0139 §7.1), which §1 permits because there is no store to split along: a mesh service is an edge service OF the overlay exactly as an edge-router is one of its nodes.

The routers hang off the network they belong to and MUST stay there. An edge-router is a node of an overlay, so it is addressed as one at /v1/network/routers and is never a top-level noun. routers is a literal beside {id} on one subtree; the router registers first by convention, and this router resolves the static segment over its parameter sibling in either order, so nothing has to be frozen to keep the address reachable.

§4 Tenancy

The tenant is the org from the validated IAM owner claim (HIP-0026), resolved by principal.Acting so a SuperAdmin acting for another org reads that org and no one reads by asking. It selects the org-<org> role attribute; the client lists the controller's resources and this capability filters to that role.

The org is never a parameter. There is no query on this surface in which an org appears, so there is no query that can be written with somebody else's. A service or router tagged for another org, or tagged for none, is invisible.

The single network's id is derived from the org, so GET /v1/network/{id} for any other id is 404 — including one that exists for another tenant. An id-guessing loop learns nothing it did not already know.

§5 Fail closed to write, honest to read

The credential to the controller (ZT_CLIENT_ID / ZT_CLIENT_SECRET, KMS-injected) may be absent on a deployment. The full route space still mounts and one gate answers 503 before any handler touches the controller. The customer-facing body names no internal configuration; what is missing is recorded in the mount's own log, for the operator who can act on it.

The two projections of the router inventory — /v1/network and /v1/network/routers — degrade instead: an unconfigured deployment and an unreachable controller both answer 200 with an empty list, and the failure is a log line. This is deliberate and it is bounded to those two reads, because the network they project does not exist until a router is on it, so "none yet" is the same true statement either way.

/v1/network/services MUST NOT degrade. A configured service exists whether or not the controller can be reached, so an empty list there would assert something false: that the tenant has no services. It answers 503 when unconfigured and surfaces the upstream's status when unreachable.

§6 Money

Free (plugin/network/main.go, cloud.Free). Reading your own fabric is not a metered act, and there is no unit here to meter — the capability provisions nothing.

§7 Observability

It publishes nothing on the bus: no network.* event reaches a customer's webhooks. Beyond the request span every route already gets, it emits structured log lines only: the mount posture, including whether the credential is present, and a warning when a read degraded under §5.

§8 Stage

ga. The manifest row declares no stage, and absent is ga (HIP-0139 §8).

§9 Upstream

The capability derives from no upstream code. It embeds no generated client: it speaks the OpenZiti Edge Management REST API (/edge/management/v1) as a thin net/http client. Password authentication returns a session token carried in the zt-session header; success is {data, meta} with pagination in the meta, failure is {error: {code, message}} at a non-2xx.

The controller it fronts is hanzoai/zt, Apache-2.0, which derives from OpenZiti (openziti/ziti, NetFoundry) with that Apache-2.0 notice preserved in its own NOTICE. What survives in HEAD there is the fabric; what survives here is the wire.

Rationale

The alternative to a filtered read is handing the console a controller credential, which makes every browser session an administrator of the whole fabric. The alternative to projecting the network from its routers is storing a network object, which then has to be kept true against a fabric that changes without asking — and a stale network row is exactly the fabrication §1 refuses.

Security Considerations

The wrong implementation shows one tenant another tenant's fabric, and a fabric listing is a map: what a tenant runs, where it is reachable, and which of it is up. The role attribute derived from the claim is the only filter, and a handler cannot omit it, because it never receives an org it could substitute.

The management credential never appears in a customer-facing body; the 503 says the deployment is not configured and nothing more. The controller fronts its own CA, so ZT_CA_PEM pins its root when set and the system pool is used otherwise; ZT_INSECURE_SKIP_VERIFY disables verification and exists for local development, where there is no fabric to protect. Full verification is the default.

An upstream is also an input. Every list is paged with a per-page size, a hard page cap and a response-size cap, so a controller that answers pathologically — or one that has been taken — can neither exhaust memory nor spin the process forever.

References

  • HIP-0026 — Identity and Access Management
  • HIP-0106 — Hanzo Plugin Contract
  • HIP-0139 — Capability
  • HIP-1127 — Gateway — Live Edge Policy
  • HIP-1133 — Ingress — The Embedded Edge
  • HIP-1152 — Share — A Public URL for a Local Service

Released under CC0 1.0 Universal Public Domain Dedication.