Issue 010 — the mesh's derived login does not fit every backend's identity rules
Found doing the per-backend provider e2e: redis and postgres accept the mesh's `as` (mesh_<node>_<module>) verbatim, but minio's S3 access key is capped at 20 chars and `as` is 22, so the provisioner cannot create the service account. `as` is doing two jobs — a stable identity the two ends agree on, and a literal identifier a backend must accept — and those are not always the same string. Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
---
|
||||
status: open
|
||||
opened: 2026-09-05
|
||||
located-in: [mesh-control, mesh-catalog]
|
||||
fixed-by:
|
||||
amended-design:
|
||||
---
|
||||
|
||||
# The mesh's derived login does not fit every backend's identity rules — S3 rejects it
|
||||
|
||||
## What was observed
|
||||
|
||||
Proving the provider/consumer contract per backend (ADR 0053), redis and postgres passed: a
|
||||
consumer authenticated against the provider with the login the mesh derived and the password
|
||||
the mesh minted. **minio failed**, and not on the credential — on the *name*:
|
||||
|
||||
```
|
||||
mc: <ERROR> Unable to add a new service account. The access key is invalid.
|
||||
(access key length should be between 3 and 20).
|
||||
```
|
||||
|
||||
The mesh derives a consumer's login as `mesh_<node>_<module>` — here `mesh_anchor_bucketuser`,
|
||||
22 characters. That is a valid postgres role and a valid redis ACL user, so those providers
|
||||
create it verbatim. S3 access keys are capped at **20 characters**, so minio refuses to create
|
||||
the service account under it, and the provisioner retries forever while the consumer, holding
|
||||
that same too-long access key, could never present it either.
|
||||
|
||||
## Why it matters beyond this instance
|
||||
|
||||
ADR 0053 says a provider creates *exactly* the login the mesh derived, so that the two ends
|
||||
agree by construction — the mesh hands the same name to the provider (to create) and the
|
||||
consumer (to present). That only holds if the derived name is one every provider can accept.
|
||||
It is not: the mesh's `as` is a single format with no knowledge of a backend's identity rules,
|
||||
and S3's are stricter than a database's. Any provider whose backend constrains identifiers more
|
||||
tightly than postgres — a length cap, a charset, a required prefix — inherits this, and the
|
||||
failure lands at provision time, per consumer, as an infinite retry rather than a refusal at
|
||||
assignment.
|
||||
|
||||
This also shows the seam is real, not cosmetic: `as` is doing two jobs — a stable per-consumer
|
||||
identity the two ends must agree on, and a literal identifier a specific backend must accept —
|
||||
and those are not always the same string.
|
||||
|
||||
## The shape of a fix (open, not decided)
|
||||
|
||||
- **Constrain the derivation** so `as` is broadly acceptable — short (≤ 20), a conservative
|
||||
charset, deterministic. This keeps "the provider creates exactly what the mesh derived" true
|
||||
everywhere, at the cost of a less legible name, and it is a mesh-wide identity change (every
|
||||
provider that already created the longer name would see it change).
|
||||
- **Let a provider map `as` to a backend-valid identifier** it derives the same way on create
|
||||
and on the consumer's behalf — but the consumer is generic and cannot run minio's mapping, so
|
||||
this only works if the mapped identifier is *delivered back* to the consumer. That is the
|
||||
data-provision return path this era keeps meeting (umami's siteId, cloudflare's record) and
|
||||
does not yet have.
|
||||
- **Declare the constraint on the interface** (`s3-bucket` states its identifier bounds) and
|
||||
have the mesh derive within them — the most honest, the most work.
|
||||
|
||||
## Open questions
|
||||
|
||||
- Is `as` meant to be human-legible, or is a short opaque token acceptable — i.e., can the
|
||||
derivation simply be shortened without anyone minding?
|
||||
- Do redis/postgres actually want the long name, or did it only survive because they are
|
||||
permissive? If nothing needs it long, the cheap fix is to cap it.
|
||||
- Does this fold into the same decision as the data-provision return path, or is it separate?
|
||||
Reference in New Issue
Block a user