101 lines
4 KiB
Markdown
101 lines
4 KiB
Markdown
---
|
|
id: RMASTER-ADR-0008
|
|
title: "Private-by-default Exposure"
|
|
status: accepted
|
|
revision: "accepted-1"
|
|
owner: railiance-master
|
|
last_reviewed: "2026-08-15"
|
|
review_interval: 6m
|
|
---
|
|
|
|
# ADR-0008: Private-by-default Exposure
|
|
|
|
Date: 2026-08-15
|
|
Status: Accepted
|
|
|
|
## Context
|
|
|
|
ADR-0006 says a topology binding is not permission to run a workload in
|
|
production. It does not say who may reach a listener. A working deploy,
|
|
a `hosts_rail` / `binds_rapp` line, or an Ingress object has been enough
|
|
to put something on the public internet.
|
|
|
|
Family readiness vocabularies are deliberately not unified
|
|
(`schemas/README.md`). Reef `lifecycle_state` has no
|
|
`production-approved`. Rapp `readiness_state` has no
|
|
`production-approved` either. Exposure cannot be derived from those
|
|
enums.
|
|
|
|
Live public surfaces already exist on `reef-railiance`. They must be
|
|
named as grants, not silently grandfathered and not taken down by this
|
|
decision.
|
|
|
|
Ratified 2026-08-15 under `RMASTER-WP-0023-T01`.
|
|
|
|
## Decision
|
|
|
|
New reefs, rails, and rapps are unreachable from the public internet
|
|
until they are production-safe **and** explicitly granted. The field
|
|
name is `exposure`. Missing field means `private`.
|
|
|
|
| Posture | Meaning | Who may reach it |
|
|
| --- | --- | --- |
|
|
| `private` | No extra listener we control | in-cluster DNS, same-reef services |
|
|
| `operator` | Same listener as `private`, plus a named ops-bridge / SSH tunnel | operator and approved agents |
|
|
| `public` | Internet listener we publish | anyone the Ingress / DNS / UFW surface allows |
|
|
|
|
`operator` is an access annotation, not a different packet posture. It
|
|
does not open a host port or a public Ingress.
|
|
|
|
Default for a new reef, rail, or rapp is `private`. Use `operator` only
|
|
for a named admin or API surface that must be reachable before admission
|
|
(k3s API, OpenBao UI). Do not prefer `operator` as the debug default.
|
|
|
|
`public` requires both an ADR-0006 binding of `production-approved` and
|
|
an explicit grant. A deploy, a binding line, or an Ingress object is not
|
|
a grant. Do not key `public` off rapp `readiness_state` and do not add
|
|
`production-approved` to the rapp enum for this purpose.
|
|
|
|
A reef public surface (host port or public DNS we publish) is a
|
|
**substrate grant**, not reef `lifecycle_state`. A rapp cannot be
|
|
`public` on a reef that has not granted a public surface. Conflicting
|
|
declarations fail closed.
|
|
|
|
The shared vocabulary is one enum. It is not one schema shape and not
|
|
one admission check:
|
|
|
|
| Family | What the field means | What makes `public` legal |
|
|
| --- | --- | --- |
|
|
| `rapp-*` | intended consumer-facing listener | binding `production-approved` + grant |
|
|
| `rail-*` | which listener classes the rail may emit | rail may emit public Ingress only when a bound grant exists |
|
|
| `reef-*` | host ports and public DNS we publish | substrate grant |
|
|
|
|
A grant is accepted residual risk, not a self-serve wish. Required
|
|
fields: hostname or port, reason, `approved_on`, residual-risk owner.
|
|
|
|
`6443` / the k3s API is not a grantable public surface.
|
|
|
|
This contract covers listeners we control: host ports, Ingress, Service
|
|
types, and public DNS we publish. Provider-native internet APIs
|
|
(Scaleway S3 and other provider-delegated endpoints) are outside this
|
|
enum.
|
|
|
|
Ops-bridge is the normal path to a shielded thing.
|
|
|
|
The detailed per-family reading lives in
|
|
[`docs/exposure-posture-contract.md`](../exposure-posture-contract.md).
|
|
|
|
## Consequences
|
|
|
|
- ADR-0006 still answers "may this binding run in production?" This ADR
|
|
answers "who may reach the listener?" Do not merge the axes.
|
|
- The three readiness enums stay distinct on purpose.
|
|
- Family schemas grow an additive `exposure` field. Rapp
|
|
`data_classification: public` is a different field and must not be
|
|
reused as the posture name.
|
|
- Implementation stays in the owning repos. This ADR does not install
|
|
NetworkPolicy, UFW, Ingress, or tunnels.
|
|
- Existing public surfaces on `reef-railiance` remain up until named as
|
|
grants. This ADR is not a shutdown plan.
|
|
- CoulombCore host inventory and Q7 / Goss reaction stay outside this
|
|
decision.
|