Skip to content

fix(iam): grant org viewers read on the service catalog - #299

Closed
mdobush wants to merge 1 commit into
mainfrom
fix/services-viewer-role-grant
Closed

mdobush wants to merge 1 commit into
mainfrom
fix/services-viewer-role-grant

Conversation

@mdobush

@mdobush mdobush commented Sep 28, 2026

Copy link
Copy Markdown

Summary

datumctl compute (and any future plugin built on the same service-activation
SDK) checks the platform-wide service catalog before every command, to read
the live entitlement mode for its own service. No assignable role granted
that read — owner, editor and viewer all inherited the services.miloapis.com
entitlement/consumer/availability roles, but never the sibling -viewer role
that covers the Service resource itself. Every caller that relies on the
Role/PolicyBinding system got Forbidden on that lookup, independent of which
role they held, including project owner.

Confirmed live: dumped the owner Role's status.effectivePermissions on the
platform and it has zero services.miloapis.com/services.* entries, while a
sibling role (services.miloapis.com-viewer) already ships with exactly that
permission and was simply never wired into viewer.

Change

Add services.miloapis.com-viewer next to the existing
services.miloapis.com-entitlement-viewer grant in the viewer role. editor
and owner both inherit viewer, so this reaches every assignable
organization role from one place.

Test plan

  • kustomize build config/assignable-organization-roles renders cleanly
    (verified locally)
  • After this reaches staging, confirm owner's
    status.effectivePermissions includes services.miloapis.com/services.list
  • A project-scoped service account with an owner PolicyBinding can run
    datumctl compute services list (or any gated compute command) without
    a Forbidden on services.services.miloapis.com
  • No regression to existing service-catalog reads (serviceentitlements,
    serviceconsumers, serviceavailabilities)

Note: merging ships to staging only per this repo's deploy flow — reaching
production needs a release tag afterward.

datumctl plugins that gate on service activation (compute, and any future
plugin adopting the same SDK) list Service objects in the platform-wide
catalog before running, to read the live entitlement mode instead of a
hard-coded copy. No assignable role granted that read: owner, editor and
viewer all inherited services.miloapis.com-entitlement-viewer/-admin
(ServiceEntitlement, ServiceConsumer, ServiceAvailability) but never the
sibling services.miloapis.com-viewer role that covers the Service resource
itself. Every caller that goes through the Role/PolicyBinding system —
service accounts in particular — got Forbidden on that lookup, regardless
of role.

Add services.miloapis.com-viewer next to the existing entitlement-viewer
grant. Editor and owner both inherit viewer, so this reaches every
assignable organization role from one place, matching how the other
per-service viewer roles are wired in this file.
@mdobush
mdobush requested a review from a team as a code owner September 28, 2026 08:41
@cla-assistant

cla-assistant Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@cla-assistant

cla-assistant Bot commented Sep 28, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@mdobush

mdobush commented Sep 28, 2026

Copy link
Copy Markdown
Author

Closing — this doesn't fix the underlying bug.

The catalog-read check runs against `iam.miloapis.com/Root:services.miloapis.com/Service`, and that type only accepts direct tuples (`InternalUser`/`InternalUserGroup#member`) — see
`openfga-provider`'s `getRootTypeDefinition` (internal/openfga/authorization_model_reconciler.go:486-518). A role granted through an Organization- or Project-scoped PolicyBinding, which is what this PR added permissions to, can never write a tuple that satisfies that check, regardless of which permissions the role carries. So this change has no effect on the actual authorization decision.

The real fix already exists as unshipped code: a `ResourceKind` PolicyBinding granting `services.miloapis.com-viewer` to `Group: system:authenticated` (service-catalog's `iam-authenticated-catalog-read` component), plus turning on multi-cluster OpenFGA discovery in production so project-scoped service accounts are recognized as members of that group at all. Tracked in milo-os/service-catalog#101.

This PR also grants read on `ServiceConfiguration` (billing/quota/provisioning settings) to every org member, harmless today only because that resource has no parent — worth avoiding regardless.

@mdobush mdobush closed this Sep 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant