ADR-0040: Tenant Names Without a Site

ADR-0040: A Tenant Service Is Named <service>.<tenant>.deevnet.net, and Its Sites Are Extra Names #

StatusAccepted (2026-11-07): built by CHG-0054, where V2, V4 and V10 passed ( What would settle it). The signing role is widened rather than guarded; open question 1 is answered by a CEL role, in service since 2026-11-07 ( CHG-0059)
Date2026-10-21
Revised2026-10-21, before review, and 2026-10-25 in the Tenant PKI review. The drafts of 2026-10-21 put canonical names under t.deevnet.net and made vanity names optional, for people only, issued by a Names CA. All three are withdrawn: the site-less name is the service’s identity, and the tenant CA issues it. 2026-10-26: site-less names resolve only at production sites (§1), so the Mobile Factory answers a tenant by its site names alone; and the bus name is withdrawn (§5), since every device dials its own tenant’s broker
ScopeA tenant’s DNS names: the name that identifies each service, the per-site names beside it, what a tenant certificate carries, which labels a tenant may not take, the broker name devices dial, and how names follow a tenant between sites. Not reverse zones or addresses, which stay per site
AmendsNaming standard §5.1–§5.3; ADR-0004 §2 (a tenant has a site-less zone beside its site zone); ADR-0015 §13 (the names it publishes); ADR-0037 §3 (the names a tenant certificate carries, and the secret store’s signing role)
RelatedADR-0039 (Proposed), which depends on this; ADR-0005; ADR-0008; ADR-0036

Context #

A tenant’s names carry the site it runs on. Its zone is <tenant>.<site>.deevnet.net (naming standard §5.2, ADR-0004 §2), and the API builds every name from it (ADR-0037 §3). A tenant developed on the Mobile Factory and deployed elsewhere changes every name its devices dial and every name its certificates carry.

TLS checks the name a client dialed against the certificate’s SANs. A CNAME does not change that, and the CN is ignored when SANs are present (RFC 6125).

The tenant CAs can issue any name under deevnet.net (ADR-0039 §2), so a site-less name needs no new CA.

Tenant names are checked for shape only. ^[a-z][a-z0-9]{0,7}$ accepts home, mobile and mqtt. There is no reserved list.

deevnet.net is internal. Each site’s resolver answers its site zone and forwards each tenant zone to the tenant DNS server; nothing is published publicly.

Decision #

1. A service’s identity is its site-less name #

Every tenant service is named <service>.<tenant>.deevnet.net, for its whole life, wherever it runs: console.eds.deevnet.net, mqtt.eds.deevnet.net. People and devices both dial it. It is the passport of a service, as a device’s URI is of a device (ADR-0039 §4).

Site-less names resolve only at the sites where a tenant runs in production. Such a site answers <tenant>.deevnet.net with its own deployment. The Mobile Factory does not: it builds tenants, and names a tenant there only under its site zone, <tenant>.mobile.deevnet.net. A tenant built at the factory is reached and tried there by its site names, and takes its site-less names to the site it is deployed to. The factory never answers for a tenant’s production names, so no site’s DNS shadows another’s.

The certificate carries both regardless (§3): the names a certificate holds do not depend on where they resolve, so moving a tenant from the factory to production needs no reissue.

2. A site name is an extra name for one deployment #

A tenant service also has <service>.<tenant>.<site>.deevnet.net at each site it runs on or is headed for: console.eds.mobile.deevnet.net, console.eds.home.deevnet.net. A site name reaches one deployment in particular, for instance dev beside prod. At the Mobile Factory it is the only name that resolves (§1).

3. A tenant certificate names the service, then its sites #

The CN and the first SAN are the site-less name; the site names follow as SANs.

CN:   console.eds.deevnet.net
SANs: console.eds.deevnet.net
      console.eds.mobile.deevnet.net
      console.eds.home.deevnet.net

The API builds every name from a label and the tenant’s sites. A tenant sends labels, never names, as in ADR-0037 §3. The sites come from the tenant’s record: the site it runs on and any it is headed for. A move to a site already listed needs no new certificate. A move to a new one is a reissue, in a work session.

No wildcard, no address, no name outside the tenant’s own, as in ADR-0037 §3.

The signing role can no longer hold the line on its own. ADR-0037 §3’s role permits names at least two labels below a site zone. A site-less name, console.eds.deevnet.net, is two labels below deevnet.net, and so is a site’s substrate name, grafana.mobile.deevnet.net. What tells them apart is the second label, a tenant or a site. The reserved list (§4) is what keeps them apart, so the signing role must enforce it too. How (a role per tenant, written at creation, or a check OpenBao’s roles can express) is an open question.

4. Some labels are reserved, and the API refuses them #

A tenant may not take a label that is a site, a site code, a retired zone, a global alias, or device: home, mobile, mgmt, dvnt, dvntm, device, every global alias under naming §4.3 (artifacts among them), and mqtt, now and as the list grows. A tenant named artifacts would own artifacts.deevnet.net, the alias; a tenant named mobile would own the site’s substrate names; and a tenant named mqtt would own mqtt.<site>.deevnet.net, a site broker’s name.

A service label may not be device, which holds a tenant’s device CNs (ADR-0039 §4).

The API’s name check enforces the list, in place of §5.1’s sentence alone. Tenant names are one namespace: only the Mobile Factory creates tenants (ADR-0039), so a name taken is taken everywhere.

5. A device dials its own tenant’s broker #

There is no platform-wide bus name. Every edge device belongs to a tenant ( ADR-0032), so a device dials its tenant’s broker, by the name §1 gives it where it is:

  • At a production site, the tenant’s own broker, by its site-less name: mqtt.<tenant>.deevnet.net.
  • At the Mobile Factory, where tenants share the platform’s broker, that broker by its site name: mqtt.mobile.deevnet.net.

No site answers mqtt.deevnet.net, and no certificate carries it. A tenant’s certificate carries only its tenant’s names (§3), so a stolen Pi key answers for that tenant alone, never for a site’s broker. Withdrawn 2026-10-26; see the alternatives.

6. What stays per site #

Reverse zones, addresses and a tenant’s index stay per site (ADR-0015 §1, §8). Only forward names leave the site.


Consequences #

A tenant in production gains a second zone, <tenant>.deevnet.net, answered by the production site that hosts it. The Mobile Factory creates no site-less zone (§1).

Firmware at a production site dials site-less names for the tenant’s own services, <service>.<tenant>.deevnet.net. At the Mobile Factory it dials site names, so a device that is moved between the two holds what each site needs.

Existing tenants are reissued once, their certificates gaining the site-less name. Their site names stay valid, so nothing breaks while firmware moves to site-less names.

The reserved list becomes load-bearing, for both the API and the signing role.


Alternatives considered #

  • Withdrawn: canonical names under t.deevnet.net (2026-10-21). A subtree gave a Tenants CA a name constraint that did not age. There is no Tenants CA (ADR-0039), and mbedTLS enforces no constraint anyway.
  • Withdrawn: vanity names for people only, from a Names CA. A second issuer for a name the tenant CA can issue, and devices kept off the name that never changes.
  • Rejected: a CNAME alone for the site-less name. TLS checks the name dialed.
  • Rejected: keep the site in the only name. Every move would change what devices dial.
  • Rejected: wildcard certificates. ADR-0037 already refuses them.
  • Withdrawn: one bus name, mqtt.deevnet.net, answered by each site’s broker (2026-10-26). Every device belongs to a tenant (ADR-0032) and dials its tenant’s broker, so no device needs a name for every site’s broker, and a certificate carrying one could answer for all of them.

Open questions #

  1. How the signing role enforces the reserved list (§3): a role per tenant, written by the API at creation, or a constraint OpenBao’s roles can express. A role the API writes needs a policy that lets it write roles, which a faulty API could abuse. Answered 2026-11-07: a constraint. OpenBao’s CEL role, a program Ansible writes, refuses a reserved label, a request naming two tenants and any name of another shape, and the API may sign through nothing else ( CHG-0059)

What would settle it #

V2, V4 and V10 of the validation plan.

Page last modified: November 7, 2026