Перейти к основному содержимому
Версия: 2.0.x

Selena grants, roles и CM API

Этот документ объясняет, как настраивать доступ к данным в Selena Engine через Selena Cluster Manager API. Он написан для администраторов, которые раньше не работали со StarRocks/Selena RBAC и не знают, чем отличается privilege на catalog, database, table, view, materialized view, resource и другие объекты.

В Selena используется StarRocks-compatible privilege model. Для справки при подготовке этого документа сверялись официальные StarRocks 4.0 pages:

Важно: документация StarRocks - upstream reference. Для конкретного внедрения проверяйте поведение на используемом Selena Engine image.

1. Модель доступа Selena​

Внешняя production-модель Selena не раздает права напрямую каждому пользователю вручную. Основной путь такой:

Keycloak group
-> CM external group mapping
-> Selena external group
-> Selena role
-> Selena privileges/grants
-> CM materializes roles on canonical SQL users

Пример:

Keycloak group:       /data/analytics/readers
CM external group: analytics_readers
Selena role: analytics_readonly
Selena grants: USAGE ON CATALOG lakekeeper_iceberg
SELECT ON ALL TABLES IN DATABASE mart
SQL user: alice

Пользователь alice получает роль не потому, что роль напрямую выдали пользователю, а потому что:

  1. alice состоит в Keycloak group /data/analytics/readers;
  2. CM values map'ят эту group в external group analytics_readers;
  3. external group analytics_readers bound к роли analytics_readonly;
  4. CM membership refresh materializes expected role на Selena SQL user alice.

CM API roles (cm_admin, cm_role_admin, cm_viewer) не дают доступа к данным. Они только разрешают вызывать protected CM API. Доступ к данным задают Selena roles/grants.

2. Кто может менять grants​

Для операций ниже нужен CM access token пользователя с cm_admin или cm_role_admin.

В примерах используется:

PlaceholderЧто это
{cm_url}Base URL CM API, например https://cm.example.com/api/v1.
{cm_admin_access_token}Access token пользователя с cm_admin или cm_role_admin.
{role_name}Selena custom role, например analytics_readonly.
{external_group}Selena external group из CM mapping, например analytics_readers.

Если token еще не получен:

curl -fsS -X POST {cm_url}/auth/login \
-H 'Content-Type: application/json' \
-d '{
"username": "{cm_admin_username}",
"password": "{cm_admin_password}"
}' \
| jq

Скопируйте .accessToken в {cm_admin_access_token}.

3. Быстрый happy path​

Перед этим примером убедитесь, что:

  • Keycloak group уже добавлена в CM external-groups.mappings;
  • external group name из mapping совпадает с analytics_readers;
  • catalog lakekeeper_iceberg, database mart и нужные tables уже существуют в Selena.

Создайте custom role:

curl -fsS -X POST {cm_url}/selena/roles \
-H 'Authorization: Bearer {cm_admin_access_token}' \
-H 'Content-Type: application/json' \
-d '{"name":"analytics_readonly"}' \
| jq

Дайте роли доступ к catalog:

curl -fsS -X POST {cm_url}/selena/roles/analytics_readonly/grants \
-H 'Authorization: Bearer {cm_admin_access_token}' \
-H 'Content-Type: application/json' \
-d '{
"privileges": ["USAGE"],
"objectType": "CATALOG",
"objectQualifier": "lakekeeper_iceberg",
"scope": "OBJECT",
"withGrantOption": false
}' \
| jq

Дайте роли read access ко всем таблицам database mart в этом catalog:

curl -fsS -X POST {cm_url}/selena/roles/analytics_readonly/grants \
-H 'Authorization: Bearer {cm_admin_access_token}' \
-H 'Content-Type: application/json' \
-d '{
"privileges": ["SELECT"],
"objectType": "TABLE",
"objectQualifier": "mart",
"catalog": "lakekeeper_iceberg",
"scope": "ALL_TABLES_IN_DATABASE",
"withGrantOption": false
}' \
| jq

Привяжите role к external group:

curl -fsS -X POST {cm_url}/selena/external-groups/analytics_readers/roles \
-H 'Authorization: Bearer {cm_admin_access_token}' \
-H 'Content-Type: application/json' \
-d '{"roleName":"analytics_readonly"}' \
| jq

Если external group еще не появляется в membership snapshot, проверьте mapping и Keycloak membership до привязки role:

curl -fsS {cm_url}/selena/membership-snapshot/groups/analytics_readers/members \
-H 'Authorization: Bearer {cm_admin_access_token}' \
| jq

Проверьте grants роли:

curl -fsS {cm_url}/selena/roles/analytics_readonly/grants \
-H 'Authorization: Bearer {cm_admin_access_token}' \
| jq

Проверьте binding external group:

curl -fsS {cm_url}/selena/external-groups/analytics_readers/roles \
-H 'Authorization: Bearer {cm_admin_access_token}' \
| jq

После следующего membership refresh CM выдаст роль текущим members external group. Если role binding меняется через CM API, CM сразу materializes role delta для current members этой external group.

4. Как читать CM API​

Этот раздел не заменяет Swagger. Полный справочник по полям request/response, кодам ошибок и актуальным examples находится в CM OpenAPI:

selena-cm/src/main/openapi/cm-api.yaml
{cm_url}/swagger-ui/index.html
{cm_url}/v3/api-docs

Здесь важно понять, какие операции нужны администратору и в каком порядке их обычно вызывать.

Что сделатьCM endpointЧто делает в Selena
Посмотреть rolesGET /selena/rolesЧитает live list roles из Engine.
Создать custom rolePOST /selena/rolesВыполняет CREATE ROLE <roleName>.
Удалить custom roleDELETE /selena/roles/{roleName}Выполняет DROP ROLE <roleName>.
Посмотреть grants roleGET /selena/roles/{roleName}/grantsВозвращает live SHOW GRANTS для role.
Выдать privilege rolePOST /selena/roles/{roleName}/grantsВыполняет GRANT ... TO ROLE <roleName>.
Отозвать privilege у rolePOST /selena/roles/{roleName}/grants:revokeВыполняет REVOKE ... FROM ROLE <roleName>.
Посмотреть roles external groupGET /selena/external-groups/{externalGroup}/rolesЧитает roles, выданные external group.
Привязать role к external groupPOST /selena/external-groups/{externalGroup}/rolesВыполняет GRANT <roleName> TO EXTERNAL GROUP <externalGroup> и сразу применяет delta к текущим users из snapshot.
Отвязать role от external groupDELETE /selena/external-groups/{externalGroup}/roles/{roleName}Выполняет REVOKE <roleName> FROM EXTERNAL GROUP <externalGroup> и сразу применяет delta к текущим users из snapshot.
Проверить snapshot группGET /selena/membership-snapshot/status, GET /selena/membership-snapshot/groups, GET /selena/membership-snapshot/groups/{externalGroup}/membersПоказывает, какие Keycloak groups CM сейчас видит и в какие external groups они превращены.
Проверить себя как пользователяGET /me/direct-sql, GET /me/driftПоказывает direct-SQL user state, expected roles и расхождения между expected/actual.

Обычный порядок настройки такой:

  1. Создать role.
  2. Выдать role нужные privileges на catalog/database/table/view/etc.
  3. Проверить grants role.
  4. Привязать role к external group.
  5. Проверить members external group в membership snapshot.
  6. Проверить пользователя через /me/direct-sql, /me/drift и direct SQL.

CM здесь не является отдельной моделью прав поверх Selena. Source of truth для roles/grants - Selena Engine: CM собирает безопасный SQL (CREATE ROLE, GRANT, REVOKE, SHOW GRANTS), выполняет его через admin connection и возвращает live result. Поэтому смысл privileges ровно тот же, что у прямого Selena GRANT.

Если прямой SQL grant работает, но эквивалентный CM request не проходит, это не "другая authorization semantics", а bug или gap в покрытии CM API. Типичные причины такого gap: CM еще не умеет выразить конкретный scope, object type не добавлен в enum, request не проходит проверку identifier safety или нужен catalog context для non-default catalog.

5. Request body для grant/revoke​

POST /selena/roles/{roleName}/grants и POST /selena/roles/{roleName}/grants:revoke используют один формат:

{
"privileges": ["SELECT"],
"objectType": "TABLE",
"objectQualifier": "mart.orders",
"catalog": "lakekeeper_iceberg",
"scope": "OBJECT",
"withGrantOption": false
}
ПолеНужноЧто значит
privilegesДаСписок Selena privilege names: SELECT, INSERT, USAGE, CREATE TABLE и т.д. CM нормализует casing и собирает SQL, а совместимость privilege с object type проверяется тем же Selena Engine, что и при прямом GRANT.
objectTypeДаТип объекта Selena: SYSTEM, CATALOG, DATABASE, TABLE, VIEW, MATERIALIZED_VIEW, FUNCTION, GLOBAL_FUNCTION, RESOURCE_GROUP, RESOURCE, STORAGE_VOLUME, USER.
objectQualifierОбычно даИмя объекта: catalog name, database name, db.table, storage volume name, username. Для SYSTEM не используется.
catalogНетCatalog context для DATABASE, TABLE, VIEW, MATERIALIZED_VIEW, FUNCTION grants в non-default catalog. CM перед GRANT/REVOKE выполняет SET CATALOG <catalog> в admin session.
scopeНетПо умолчанию OBJECT. Используется для grants вида "all tables in database".
withGrantOptionНетРазрешает получателю дальше выдавать такой privilege другим. Для обычных data roles почти всегда false.

Supported scope values:

ScopeObject typeobjectQualifier
OBJECTВсе object types, кроме SYSTEMКонкретный object: default_catalog, mart, mart.orders, selena_s3_volume, alice.
ALL_DATABASESDATABASEНе нужен.
ALL_TABLES_IN_DATABASETABLEDatabase name.
ALL_TABLES_IN_ALL_DATABASESTABLEНе нужен.
ALL_VIEWS_IN_DATABASEVIEWDatabase name.
ALL_MATERIALIZED_VIEWS_IN_DATABASEMATERIALIZED_VIEWDatabase name.
ALL_FUNCTIONS_IN_DATABASEFUNCTIONDatabase name.

Если scope нельзя однозначно превратить в Selena SQL для выбранного object type, CM вернет 400. Если собранный GRANT syntactically valid для CM, но privilege не подходит object type или target object не существует, Selena Engine вернет такой же SQL error, как при прямом GRANT; CM только отдаст его в unified error response.

6. Object types и privileges​

Ниже - практическая матрица для Selena/StarRocks 4.0-compatible RBAC. ALL означает "все privileges на объекте этого типа", а не "все в кластере".

SYSTEM​

SYSTEM privileges управляют cluster-level возможностями, а не данными в таблицах.

PrivilegeЗа что отвечает
CREATE RESOURCE GROUPСоздание resource groups.
CREATE RESOURCEСоздание resources для Spark Load/external tables.
CREATE EXTERNAL CATALOGСоздание external catalogs.
PLUGINУстановка и удаление plugins.
REPOSITORYBackup/restore repositories.
BLACKLISTSQL blacklist и BE blacklist.
FILEFile objects.
OPERATEОперационные действия: replicas, configs, variables, transactions, kill/query operations.
CREATE GLOBAL FUNCTIONСоздание global UDF.
CREATE STORAGE VOLUMEСоздание storage volumes.
SECURITYSecurity integrations и group providers.

NODE и GRANT существуют в StarRocks privilege model, но не должны выдаваться напрямую custom roles: они принадлежат built-in administrative roles cluster_admin и user_admin.

CM request:

{
"privileges": ["CREATE EXTERNAL CATALOG"],
"objectType": "SYSTEM",
"scope": "OBJECT"
}

CATALOG​

Catalog - верхний уровень namespace. default_catalog - internal Selena catalog. External catalogs обычно указывают на Iceberg/Hive/Hudi/Delta и т.п.

PrivilegeInternal catalogExternal catalogЗа что отвечает
USAGEДаДаПозволяет использовать catalog как namespace. Для external catalog это базовый grant почти для любого data access.
CREATE DATABASEДаОграниченно, зависит от catalog typeСоздание databases в catalog.
DROPНет для default_catalogДаУдаление external catalog.
ALLДаДаВсе supported privileges на catalog.

Read-only external catalog почти всегда начинается с:

{
"privileges": ["USAGE"],
"objectType": "CATALOG",
"objectQualifier": "lakekeeper_iceberg"
}

Сам по себе USAGE ON CATALOG не дает читать таблицы. Он дает право использовать catalog, но для чтения данных нужны grants на TABLE, VIEW или MATERIALIZED_VIEW.

DATABASE​

Database privilege управляет самим database object и созданием объектов внутри него. Он не является table read/write privilege.

PrivilegeЗа что отвечает
ALTERИзменение свойств, rename, quotas.
DROPУдаление database.
CREATE TABLEСоздание tables в database.
CREATE VIEWСоздание views.
CREATE FUNCTIONСоздание database-level UDF.
CREATE MATERIALIZED VIEWСоздание materialized views.
ALLВсе database-level privileges.

Database admin role обычно требует не только ALL ON DATABASE, но и object grants на tables/views/materialized views/functions внутри database.

Пример:

{
"privileges": ["CREATE TABLE", "CREATE VIEW"],
"objectType": "DATABASE",
"objectQualifier": "mart",
"catalog": "lakekeeper_iceberg"
}

TABLE​

Table privilege управляет чтением, записью и изменением tables.

PrivilegeЗа что отвечает
SELECTЧтение rows из table.
INSERTInsert/load в table. Для INSERT INTO ... SELECT ... нужен еще SELECT на source tables.
UPDATEUpdate rows.
DELETEDelete rows.
EXPORTExport data.
ALTERAlter table; для external table также refresh metadata по StarRocks 4.0 docs.
DROPDrop table.
ALLВсе table privileges.

Read-only на все tables database:

{
"privileges": ["SELECT"],
"objectType": "TABLE",
"objectQualifier": "mart",
"catalog": "lakekeeper_iceberg",
"scope": "ALL_TABLES_IN_DATABASE"
}

Write на одну table:

{
"privileges": ["SELECT", "INSERT"],
"objectType": "TABLE",
"objectQualifier": "mart.orders",
"catalog": "lakekeeper_iceberg",
"scope": "OBJECT"
}

ALL_TABLES_IN_DATABASE удобнее object-level grants, если в database будут появляться новые tables. Object-level grant на конкретную table привязан к этому object; при drop/recreate table privilege может потеряться.

VIEW​

View privilege управляет logical views отдельно от base tables.

PrivilegeЗа что отвечает
SELECTQuery existing view.
ALTERChange view definition.
DROPDrop view.
ALLВсе view privileges.

Grant на все views database:

{
"privileges": ["SELECT"],
"objectType": "VIEW",
"objectQualifier": "mart",
"catalog": "lakekeeper_iceberg",
"scope": "ALL_VIEWS_IN_DATABASE"
}

Для создания view обычно нужен CREATE VIEW на database и SELECT на base tables, из которых строится view.

MATERIALIZED_VIEW​

Materialized view privilege управляет отдельным materialized view object.

PrivilegeЗа что отвечает
SELECTQuery materialized view напрямую и использовать его как acceleration target.
REFRESHRefresh materialized view.
ALTERChange materialized view.
DROPDrop materialized view.
ALLВсе materialized view privileges.

Grant на refresh всех materialized views database:

{
"privileges": ["REFRESH"],
"objectType": "MATERIALIZED_VIEW",
"objectQualifier": "mart",
"catalog": "lakekeeper_iceberg",
"scope": "ALL_MATERIALIZED_VIEWS_IN_DATABASE"
}

Для создания materialized view нужен CREATE MATERIALIZED VIEW на database и обычно SELECT на base tables.

FUNCTION и GLOBAL_FUNCTION​

Database-level functions и global functions имеют похожую модель:

Object typePrivilegesЗа что отвечает
FUNCTIONUSAGE, DROP, ALLDatabase-level UDF.
GLOBAL_FUNCTIONUSAGE, DROP, ALLGlobal UDF.

CM поддерживает object types FUNCTION и GLOBAL_FUNCTION, но function signatures в StarRocks syntax могут включать symbols вроде (, ), ,. Если конкретный function grant нужен в production, сначала проверьте request на целевом CM/Engine. Для большинства customer data-access ролей function grants не требуются.

Grant на все functions database:

{
"privileges": ["USAGE"],
"objectType": "FUNCTION",
"objectQualifier": "mart",
"catalog": "lakekeeper_iceberg",
"scope": "ALL_FUNCTIONS_IN_DATABASE"
}

RESOURCE_GROUP​

Resource group управляет resource governance/classifiers.

PrivilegeЗа что отвечает
ALTERAdd/drop classifiers.
DROPDrop resource group.
ALLВсе resource group privileges.

Обычным data users это не нужно.

RESOURCE​

Resource используется для Spark Load и некоторых external integrations.

PrivilegeЗа что отвечает
USAGEИспользовать resource.
ALTERИзменить resource.
DROPУдалить resource.
ALLВсе resource privileges.

Grant:

{
"privileges": ["USAGE"],
"objectType": "RESOURCE",
"objectQualifier": "spark_resource"
}

STORAGE_VOLUME​

Storage volume описывает remote storage credentials/config для shared-data, cloud-native storage и похожих сценариев.

PrivilegeЗа что отвечает
USAGEDescribe storage volume и set as default storage volume.
ALTERChange credentials/properties/comment/enabled status.
DROPDrop storage volume.
ALLВсе storage volume privileges.

Обычным query users обычно не нужен ALTER или DROP на storage volume.

Grant:

{
"privileges": ["USAGE"],
"objectType": "STORAGE_VOLUME",
"objectQualifier": "selena_s3_volume"
}

USER​

USER object type сейчас используется для IMPERSONATE.

{
"privileges": ["IMPERSONATE"],
"objectType": "USER",
"objectQualifier": "alice"
}

В Selena v1 external model не выдавайте IMPERSONATE business roles вручную. CM bootstrap и direct-SQL provisioning сами выдают нужные impersonation grants configured service users (cm, ide, ai) на canonical SQL users.

PIPE, WAREHOUSE, COLUMN​

В upstream StarRocks privilege model есть дополнительные object types вроде PIPE, WAREHOUSE, COLUMN. Текущий public CM PrivilegeGrantRequest не имеет objectType для них. Если customer deployment реально использует эти features, нужен отдельный product decision: расширять CM API или вести эти grants отдельным admin SQL runbook.

7. Типовые роли​

Ниже приведены готовые fragments для POST /selena/roles/{roleName}/grants. Для выполнения используйте тот же curl формат, что в quick path выше, меняя только JSON body.

Read-only на internal database​

Минимальный read-only для default_catalog.mart:

curl -fsS -X POST {cm_url}/selena/roles/mart_readonly/grants \
-H 'Authorization: Bearer {cm_admin_access_token}' \
-H 'Content-Type: application/json' \
-d '{
"privileges": ["USAGE"],
"objectType": "CATALOG",
"objectQualifier": "default_catalog"
}' \
| jq

curl -fsS -X POST {cm_url}/selena/roles/mart_readonly/grants \
-H 'Authorization: Bearer {cm_admin_access_token}' \
-H 'Content-Type: application/json' \
-d '{
"privileges": ["SELECT"],
"objectType": "TABLE",
"objectQualifier": "mart",
"scope": "ALL_TABLES_IN_DATABASE"
}' \
| jq

Если users должны читать views или materialized views напрямую, добавьте отдельные grants на VIEW и MATERIALIZED_VIEW.

Read-only на external Iceberg/Lakekeeper catalog​

Для external catalog важно дать USAGE на catalog и передавать catalog в нижестоящих grants:

curl -fsS -X POST {cm_url}/selena/roles/iceberg_readonly/grants \
-H 'Authorization: Bearer {cm_admin_access_token}' \
-H 'Content-Type: application/json' \
-d '{
"privileges": ["USAGE"],
"objectType": "CATALOG",
"objectQualifier": "lakekeeper_iceberg"
}' \
| jq

curl -fsS -X POST {cm_url}/selena/roles/iceberg_readonly/grants \
-H 'Authorization: Bearer {cm_admin_access_token}' \
-H 'Content-Type: application/json' \
-d '{
"privileges": ["SELECT"],
"objectType": "TABLE",
"objectQualifier": "mart",
"catalog": "lakekeeper_iceberg",
"scope": "ALL_TABLES_IN_DATABASE"
}' \
| jq

Writer на existing tables​

Writer, который может читать и append/update/delete rows, но не создавать tables:

{
"privileges": ["SELECT", "INSERT", "UPDATE", "DELETE"],
"objectType": "TABLE",
"objectQualifier": "mart",
"catalog": "lakekeeper_iceberg",
"scope": "ALL_TABLES_IN_DATABASE"
}

Для write-only ingestion service можно дать INSERT без SELECT, но тогда UI preview, validation queries и INSERT INTO ... SELECT ... из источника без дополнительных grants будут ломаться.

Database maintainer​

Maintainer, который может создавать tables/views/materialized views и управлять объектами внутри database:

{
"privileges": ["ALL"],
"objectType": "DATABASE",
"objectQualifier": "mart",
"catalog": "lakekeeper_iceberg"
}

Плюс отдельно:

{
"privileges": ["ALL"],
"objectType": "TABLE",
"objectQualifier": "mart",
"catalog": "lakekeeper_iceberg",
"scope": "ALL_TABLES_IN_DATABASE"
}

И, если нужно:

{
"privileges": ["ALL"],
"objectType": "VIEW",
"objectQualifier": "mart",
"catalog": "lakekeeper_iceberg",
"scope": "ALL_VIEWS_IN_DATABASE"
}
{
"privileges": ["ALL"],
"objectType": "MATERIALIZED_VIEW",
"objectQualifier": "mart",
"catalog": "lakekeeper_iceberg",
"scope": "ALL_MATERIALIZED_VIEWS_IN_DATABASE"
}

Причина: StarRocks FAQ explicitly calls out that database privileges do not make tables visible/readable by themselves. SHOW TABLES returns only tables where user has at least one table privilege.

8. Что будет в спорных комбинациях​

Есть USAGE ON CATALOG, но нет grants на database/table​

Пользователь получает право использовать catalog namespace. Но:

  • SELECT * FROM catalog.db.table будет denied, потому что нет SELECT на table/view/materialized view;
  • SHOW TABLES для external catalog требует USAGE на catalog, но без table privileges пользователь все равно не увидит data objects, на которые у него нет прав;
  • BI/SQL tools могут показать catalog, но не показать tables или не дать выполнить query.

Практический вывод: USAGE ON CATALOG - это входная дверь в catalog, не доступ к данным.

Есть grants на database, но нет grants на tables​

Например role имеет:

GRANT ALL ON DATABASE mart TO ROLE mart_admin

Но не имеет:

GRANT SELECT ON ALL TABLES IN DATABASE mart TO ROLE mart_admin

Тогда role может иметь database-level capabilities вроде create/alter/drop database или create objects, но existing tables не становятся readable. Это частая ошибка: database grant не наследуется автоматически на tables.

StarRocks FAQ отдельно говорит, что SHOW TABLES при ALL ON DATABASE может ничего не вернуть, если user не имеет privileges на сами tables.

Есть grants на tables, но нет database-level CREATE TABLE​

Например role имеет:

GRANT SELECT, INSERT ON ALL TABLES IN DATABASE mart TO ROLE mart_writer

Но не имеет:

GRANT CREATE TABLE ON DATABASE mart TO ROLE mart_writer

Тогда role может читать/писать existing tables по table grants, но не может создавать новые tables в database. Это нормальная модель для ingestion users, которым нельзя менять schema.

Есть CREATE TABLE ON DATABASE, но нет table grants​

Role может создавать tables в database, но это не заменяет grants на чтение, insert, update, delete или export данных. Для operational simplicity обычно сразу добавляют table-level grant pattern, например ALL_TABLES_IN_DATABASE, если role действительно является maintainer'ом этого database.

Есть table SELECT, но нет catalog USAGE на external catalog​

Не делайте так в production. На external catalogs StarRocks docs отдельно требуют USAGE на соответствующем external catalog для metadata operations вроде SHOW TABLES. Даже если какой-то fully-qualified query пройдет на конкретной версии, SQL clients, UI metadata browsing и SET CATALOG будут вести себя непредсказуемо для пользователя.

Практический вывод: для external catalog всегда выдавайте:

USAGE ON CATALOG <catalog>
SELECT/INSERT/... ON TABLE ... with catalog context

Есть INSERT, но нет SELECT​

Такой user может быть write-only ingestion actor. Но:

  • он не сможет прочитать rows для проверки;
  • многие UI tools сначала делают SELECT/metadata queries и будут выглядеть "сломано";
  • INSERT INTO target SELECT ... FROM source требует SELECT на source.

Для human writer обычно выдавайте SELECT вместе с INSERT.

Есть SELECT на table, но нет SELECT на view​

View - отдельный object type. Если пользователь должен query'ить view, выдайте SELECT на VIEW или ALL_VIEWS_IN_DATABASE. Table grants не являются grants на view.

Есть SELECT на view, но нет direct SELECT на base table​

Такой pattern может быть полезен как controlled access через curated views. Перед production use проверьте на целевом Selena Engine image, потому что view/base-table authorization details могут зависеть от версии и типа catalog.

Есть REFRESH на materialized view, но нет SELECT​

REFRESH позволяет refresh operation, но не означает, что пользователь может читать materialized view. Для чтения нужен SELECT на MATERIALIZED_VIEW.

Role bound к external group, но user не получает access​

Проверьте по цепочке:

  1. Keycloak user реально состоит в expected group.
  2. Group path совпадает с key в cm.identity.external-groups.mappings.
  3. Mapping указывает на тот же {external_group}, к которому bound role.
  4. GET /selena/membership-snapshot/groups/{externalGroup}/members содержит user.
  5. GET /me/drift для user показывает expected role.
  6. Если drift есть, дождитесь refresh или выполните user login/CLI reset path, который triggers reconcile.

Role имеет grants, но user видит no permission​

Проверьте:

  • role действительно materialized на SQL user: SHOW GRANTS или GET /me/direct-sql;
  • CM при reconcile вызывает SET DEFAULT ROLE ALL TO '<username>'@'%', но старая SQL session могла стартовать до изменения roles;
  • переподключите MySQL/JDBC session;
  • проверьте, что grant выдан на нужный catalog/database/table, а не на объект с похожим именем в другом catalog.

9. Revoke и удаление​

Revoke privilege с role:

curl -fsS -X POST {cm_url}/selena/roles/analytics_readonly/grants:revoke \
-H 'Authorization: Bearer {cm_admin_access_token}' \
-H 'Content-Type: application/json' \
-d '{
"privileges": ["SELECT"],
"objectType": "TABLE",
"objectQualifier": "mart",
"catalog": "lakekeeper_iceberg",
"scope": "ALL_TABLES_IN_DATABASE"
}' \
| jq

Revoke role from external group:

curl -fsS -X DELETE \
{cm_url}/selena/external-groups/analytics_readers/roles/analytics_readonly \
-H 'Authorization: Bearer {cm_admin_access_token}' \
| jq

Delete role:

curl -i -sS -X DELETE {cm_url}/selena/roles/analytics_readonly \
-H 'Authorization: Bearer {cm_admin_access_token}'

Перед удалением role сначала снимите external group bindings и проверьте, что role не нужна другим группам. Если role используется в grants/bindings, Selena может вернуть SQL error.

10. Проверка результата​

Проверить role grants через CM:

curl -fsS {cm_url}/selena/roles/{role_name}/grants \
-H 'Authorization: Bearer {cm_admin_access_token}' \
| jq

Проверить external group roles:

curl -fsS {cm_url}/selena/external-groups/{external_group}/roles \
-H 'Authorization: Bearer {cm_admin_access_token}' \
| jq

Проверить members external group:

curl -fsS {cm_url}/selena/membership-snapshot/groups/{external_group}/members \
-H 'Authorization: Bearer {cm_admin_access_token}' \
| jq

Проверить текущего пользователя:

curl -fsS {cm_url}/me/direct-sql \
-H 'Authorization: Bearer {user_access_token}' \
| jq

curl -fsS {cm_url}/me/drift \
-H 'Authorization: Bearer {user_access_token}' \
| jq

Проверить direct SQL:

mysql --protocol=TCP \
-h {selena_fe_mysql_host} \
-P 9030 \
-u {username} \
-p{cli_secret} \
-e "SELECT CURRENT_USER(); SELECT CURRENT_ROLE(); SHOW GRANTS;"

Если проверяете external catalog:

mysql --protocol=TCP \
-h {selena_fe_mysql_host} \
-P 9030 \
-u {username} \
-p{cli_secret} \
-e "SET CATALOG lakekeeper_iceberg; SHOW TABLES FROM mart; SELECT * FROM mart.orders LIMIT 1;"

11. Практические правила​

  • Управляйте data access через roles и external groups, а не прямыми user grants.
  • Для external catalog всегда выдавайте USAGE ON CATALOG плюс конкретные grants на tables/views/materialized views.
  • Не считайте database grant заменой table grants.
  • Для read-only human users обычно нужны USAGE ON CATALOG, SELECT ON TABLE, а если используются views/MVs - отдельные SELECT ON VIEW и SELECT ON MATERIALIZED_VIEW.
  • Для writers обычно нужны SELECT и INSERT; UPDATE/DELETE выдавайте только если это реально требуется.
  • WITH GRANT OPTION не нужен обычным business roles.
  • Built-in roles root, cluster_admin, db_admin, user_admin, security_admin не используйте как business data roles.
  • После изменения group membership учитывайте refresh interval CM.
  • После изменения grants переподключайте long-lived SQL sessions при проверке.
  • При сомнении смотрите live grants через CM или SHOW GRANTS, а не только values/config.