ryuan-cw opened a new issue, #4573:
URL: https://github.com/apache/polaris/issues/4573
### Is your feature request related to a problem? Please describe.
`GET /api/management/v1/catalogs` (`listCatalogs`) is authorized by
`CATALOG_LIST` on the **root container** — effectively a `service_admin`
capability — and it is all-or-nothing: a principal lacking that root privilege
gets a hard `403`, not a filtered list. A least-privilege principal therefore
cannot *discover* catalogs even for catalogs it has been explicitly granted
access to.
Concretely, with a principal whose catalog role grants
`CATALOG_READ_PROPERTIES` / `NAMESPACE_LIST` / `TABLE_LIST` / `TABLE_READ_DATA`
on specific catalogs:
- `GET /api/management/v1/catalogs` → `403` (`Principal '…' … is not
authorized for op LIST_CATALOGS`)
- `GET /api/management/v1/catalogs/{name}` (`getCatalog`) → `200`
- Iceberg catalog API (list namespaces/tables, read data) → works
So the principal can read everything in the catalogs it is granted, but
cannot enumerate them. This makes the **polaris-console** catalog browser
(which calls `listCatalogs`) and any read-only "viewer" persona unusable for
non-admins — the catalog list is empty/forbidden.
And there is no narrower fix: `CATALOG_LIST` must sit on the root container,
the only code path that places a privilege there
(`PolarisAdminService.grantPrivilegeOnRootContainerToPrincipalRole`, op
`ADD_ROOT_GRANT_TO_PRINCIPAL_ROLE`, itself requiring `SERVICE_MANAGE_ACCESS`)
is **not exposed via the management REST API**, so the only API-reachable way
to make `listCatalogs` succeed is to grant `service_admin` (full administrative
access: create/drop catalogs, manage all principals/roles/grants) — the
opposite of least privilege.
Relevant code (`apache-polaris-1.3.0-incubating`; authorization path
unchanged on `main`):
- `PolarisAdminService.listCatalogs()` →
`authorizeBasicRootOperationOrThrow(LIST_CATALOGS)`, then
`listCatalogsUnsafe()` returns **all** catalogs (no filtering).
- `authorizeBasicRootOperationOrThrow(...)` resolves the **root container**
as the authorization target.
- `RbacOperationSemantics`: `register(LIST_CATALOGS, CATALOG_LIST)`.
- `PolarisAuthorizerImpl`: `CATALOG_LIST` is satisfied by
`SERVICE_MANAGE_ACCESS` (or catalog-level `CATALOG_READ_PROPERTIES`, etc.) **on
the same securable** — i.e. on the root container, which a non-admin never
holds.
### Describe the solution you'd like
When the caller does not hold `CATALOG_LIST` on the root container,
`listCatalogs` should return the **subset of catalogs the caller is authorized
on** (holds any catalog-role grant / `CATALOG_READ_PROPERTIES`), instead of
throwing `403`. Callers with root `CATALOG_LIST` / `SERVICE_MANAGE_ACCESS`
continue to see all catalogs.
This reuses the same per-securable check `getCatalog` already performs,
mirrors how `listNamespaces` / `listTables` are scoped within a catalog, and
matches how object stores filter list results by ACL. Because each catalog is
itself a securable with grants (unlike principal-roles in #363), filtering the
catalog list by the caller's effective grants is straightforward. Result:
non-admins discover exactly the catalogs they can use, the console works for
read-only personas, and no `service_admin` grant or root-container grant API is
required.
### Describe alternatives you've considered
- **Expose root-container grants via REST** so `CATALOG_LIST`-only can be
granted to a principal role — enables a "list, no write/drop" role, but is
still all-or-nothing ("see all catalogs") and adds a privilege that is hard to
reason about; filtering is more useful and least-surprising.
- **`service_admin`** (current workaround) — over-privileged (can drop
catalogs, manage all principals); unacceptable for viewer / least-privilege use.
- **A catalog-scoped discovery endpoint** — cumbersome when a principal has
access to many catalogs (also noted in #363).
### Additional context
Sibling issue #363 raises the same class of problem for `listPrincipalRoles`
under `catalog_admin`. Performance: filtering adds a per-catalog authorization
check; catalog counts are typically small and this can be batched if needed.
Observed on Apache Polaris 1.3.0-incubating via polaris-console; authorization
path verified unchanged on `main`.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]