@@ -202,26 +202,49 @@ that include `org: "acme"` and `team: "platform"`. Otherwise, the server returns
202202The server uses **containment** (superset check) for claim validation : the
203203caller's claims must be a superset of the resource's claims. For example :
204204
205- | Resource claims | Caller JWT claims | Result |
206- | --------------------------------- | --------------------------------- | ------- |
207- | `{org : " acme" }` | `{org: "acme", team: "platform"}` | Allowed |
208- | `{org : " acme" , team: "platform"}` | `{org: "acme"}` | Denied |
209- | `{}` (no claims) | `{org : " acme" }` | Allowed |
210- | `{org : " acme" }` | `{org: "contoso"}` | Denied |
211-
212- Registries and sources with no claims are accessible to all authenticated
213- callers.
214-
215- :::warning[Entries without claims are invisible when authorization is enabled]
216-
217- Entries with no claims are visible in anonymous mode and
218- [auth-only mode](#auth-only-mode), but **invisible** when full authorization is
219- enabled. The per-entry filter requires both sides to have claims for a match.
220- Entries without claims are filtered out. To make entries visible, attach claims
221- to the source (for synced sources) or to individual entries (via the publish
222- payload or the
223- [`authz-claims` annotation](./configuration.mdx#per-entry-claims-via-annotation)
224- for Kubernetes sources).
205+ | Resource claims | Caller JWT claims | Result |
206+ | --------------------------------- | --------------------------------- | ---------------------------------- |
207+ | `{org : " acme" }` | `{org: "acme", team: "platform"}` | Allowed |
208+ | `{org : " acme" , team: "platform"}` | `{org: "acme"}` | Denied |
209+ | `{}` (no claims) | `{org : " acme" }` | Denied (default-deny on unlabeled) |
210+ | `{org : " acme" }` | `{org: "contoso"}` | Denied |
211+
212+ :::warning[Unlabeled resources are invisible when authorization is enabled]
213+
214+ When `auth.authz` is configured, sources, registries, and entries with no claims
215+ are treated as **default-deny** : invisible to every authenticated caller except
216+ a super-admin. The list endpoints and the single-resource gate agree, so a
217+ resource is either visible everywhere or nowhere.
218+
219+ Anonymous mode and [auth-only mode](#auth-only-mode) bypass the gate entirely,
220+ so unlabeled resources remain accessible there.
221+
222+ To make a resource reachable under full authorization, attach claims to it :
223+
224+ - **Sources and registries**: set the `claims` field on the source or registry
225+ in your configuration file.
226+ - **Entries from synced sources**: tag the source so its claims are inherited
227+ during sync.
228+ - **Entries on Kubernetes sources**: use the
229+ [`authz-claims` annotation](./configuration.mdx#per-entry-claims-via-annotation)
230+ on the CRD.
231+ - **Entries on managed sources**: include `claims` in the publish payload or
232+ call `PUT /v1/entries/{type}/{name}/claims` from a super-admin.
233+
234+ :: :
235+
236+ :::info[Upgrading from earlier releases]
237+
238+ Releases before v1.4.1 treated an unlabeled resource as visible to every
239+ authenticated caller, but only on single-resource paths like
240+ ` GET /v1/sources/{name}` . List endpoints already filtered them out, so the same
241+ row could appear via one path and not another.
242+
243+ After upgrading to v1.4.1 or later with `auth.authz` configured, those unlabeled
244+ rows become invisible to every non-super-admin caller. To restore access, a
245+ super-admin can tag them in place via the per-entry claims endpoint, or
246+ operators can add a tenant-wide claim to the source so synced entries inherit it
247+ on the next sync.
225248
226249:: :
227250
@@ -398,6 +421,8 @@ sources:
398421
399422 - name: shared
400423 managed: {}
424+ claims:
425+ org: 'acme'
401426
402427registries:
403428 - name: platform
@@ -441,17 +466,20 @@ With this configuration:
441466 ` shared` .
442467- **Data team members** (JWT with `org: "acme"`, `team: "data"`) can access the
443468 ` data` registry and see entries from `data-tools` and `shared`.
444- - **Writers** (JWT with `role: "writer"`) can publish to the `shared` managed
445- source.
469+ - **Writers** in the `acme` org (JWT with `org: "acme"`, `role: "writer"`) can
470+ publish to the `shared` managed source. The `org : " acme" ` claim on the source
471+ is what makes it reachable to non-super-admin callers under default-deny.
446472- **Admins** (JWT with ` org: "acme"`, `role: "admin"`) can manage sources and
447473 registries within the `acme` org.
448474- **Super-admins** (JWT with `role: "super-admin"`) can access and manage
449475 everything.
450476
451- Entries published to the `shared` source without claims are visible through any
452- registry that includes it, subject only to the registry-level claims gate. To
453- restrict visibility further, attach claims when
454- [publishing entries](#claims-on-published-entries).
477+ Every entry published to the `shared` source must carry claims (publishing
478+ without claims is rejected when authentication is enabled), and those claims
479+ must be a subset of the publisher's JWT. To narrow visibility within a registry,
480+ publish with team-scoped claims like `{org : " acme" , team: "platform"}` so only
481+ that team's registry surfaces the entry. See
482+ [Claims on published entries](#claims-on-published-entries) for the full rules.
455483
456484# # Next steps
457485
0 commit comments