roryqi commented on code in PR #12757:
URL: https://github.com/apache/gravitino/pull/12757#discussion_r3901321638


##########
design-docs/tag-based-access-control.md:
##########
@@ -0,0 +1,441 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+# Design of Tag-Based Access Control in Gravitino
+
+**Status:** draft for discussion. The [open questions](#open-questions) are 
deliberately left
+undecided in this revision, each presented with its options; decisions will be 
folded in after
+review.
+
+Discussion: [#12619](https://github.com/apache/gravitino/discussions/12619)
+
+---
+
+## Summary
+
+An access rule is a `Policy` of type `system_access_control` whose `content` 
carries an action, a
+role condition and a scope. The policy is bound to a tag. Any object carrying 
that tag becomes
+subject to the rule.
+
+```json
+POST /api/metalakes/prod/policies
+{
+  "name": "analyst_read_certified_finance",
+  "policyType": "system_access_control",
+  "enabled": true,
+  "content": {
+    "action": "SELECT_TABLE",
+    "role":   { "name": "analyst" },
+    "scope":  { "catalog": "lakehouse", "schema": "finance" }
+  }
+}
+```
+
+```
+PUT  /api/metalakes/prod/tags/certified/policies/analyst_read_certified_finance
+     { "selector": { "type": "ALL_VALUES" } }
+
+POST /api/metalakes/prod/objects/TABLE/lakehouse.finance.orders/tags
+     { "tagsToAdd": [{ "name": "certified" }] }
+```
+
+Read together: *members of the role `analyst` may `SELECT` any table under
+`lakehouse.finance` that carries the tag `certified`.*
+
+There is exactly one attachment — the policy-to-tag bind. The role and the 
scope are values
+inside `content`, not associations. No new user-facing entity, REST resource 
or client API is
+introduced.
+
+---
+
+## Background
+
+Gravitino authorizes metadata operations through RBAC. A grant names a 
securable object and a
+privilege and binds them to a role; the authorization expression on each REST 
endpoint evaluates
+those grants over the object's ancestor chain.
+
+Tags are a separate subsystem. They apply to catalogs, schemas, tables, views, 
topics, filesets,
+models, columns and functions, carry assignment values (see
+[tag-assignment-values.md](tag-assignment-values.md)), and inherit down the 
object hierarchy.
+Policy-on-tag ([policy-on-tag.md](policy-on-tag.md)) lets governance policies 
be selected by those
+tags. Authorization does not read tags at all.
+
+The consequence is that intent expressed as classification cannot drive 
access. An organization
+that already labels tables `certified`, `pii` or `data_domain=finance` must 
still enumerate grants
+object by object to act on those labels. New objects need new grants, dropped 
objects leave stale
+ones, and the rule itself is written down nowhere — it exists only as the 
accumulated set of grants
+someone remembered to issue.
+
+---
+
+## Scope
+
+### In this version
+
+- A rule of the form *(action, role condition, scope)* bound to a tag.
+- `ALLOW` only.
+- Roles as the matched condition.
+- Evaluation inside the existing authorization-expression path, composing with 
RBAC.
+- Reuse of the `Policy` entity, the policy-to-tag relation and 
`PolicySelector`, so tag conditions
+  are written identically for governance and for authorization.
+- No new REST resource or client API. The only storage addition is an internal 
derived index, not
+  written or read by any endpoint — see [Lifecycle](#lifecycle).
+
+### Not in this version
+
+| Excluded | Reason |
+|---|---|
+| `DENY` | Deny that cannot be suppressed by re-tagging a descendant is a 
separate problem. Allow-only keeps v1 evaluation total and order-independent. |
+| Users and groups as the matched condition | The condition schema can gain 
them later without changing the model. |
+| Row filtering and column masking | Distinct policy types; this design 
governs whole-object decisions. |
+| Cross-tag conditions | A rule matches one tag. Conditions spanning several 
tags await the `EXPRESSION` selector type in 
[policy-on-tag.md](policy-on-tag.md). |
+| Column-level decisions | A tag on a column does not affect decisions about 
its table. |
+| Replacing RBAC | Baseline privileges, ownership and traversal are unchanged. 
See [Composition with RBAC](#composition-with-rbac). |
+
+---
+
+## Alternatives considered
+
+| Option | Pros | Cons | Status |
+|---|---|---|---|
+| **A `system_access_control` policy type bound to a tag** | Reuses the 
entity, relation, selector and resolver; no new REST or client surface; one 
governance model to learn | The role condition lives in `content` JSON, so 
lookup by role needs a derived index rather than a foreign key | **Proposed** |
+| A dedicated `tag_access_policy` entity with action, role and scope as 
columns | Foreign key on role; indexed lookup; cascade on role deletion falls 
out of the schema | New table across three dialects, new REST resource, new 
client and CLI surface, a second governance model alongside policies | Rejected 
|
+| Extend RBAC grants with a tag predicate | No new concepts | The grant table 
is object-identified; a predicate has no object, and every grant read path 
would change | Rejected |
+| Evaluate tags in an external engine (OPA and similar) | Arbitrary policy 
language | Moves the decision out of Gravitino, duplicates the tag hierarchy, 
and cannot use the existing expression path | Rejected |
+
+The consequence of that one con — referential integrity maintained by the 
server rather than by the
+schema — is addressed in [Lifecycle](#lifecycle).
+
+---
+
+## Model
+
+### Content
+
+`PolicyContent` is an interface, and each built-in policy type has a concrete 
implementation with
+typed fields and a `validate()` that runs at write time. 
`IcebergDataCompactionContent` is the
+existing example. `system_access_control` follows the same pattern with a new
+`AccessControlContent`:
+
+| Field | Type | Meaning |
+|---|---|---|
+| `action` | `Privilege.Name` | The privilege the rule confers. Must be one of 
the permitted names — see [Composition with RBAC](#composition-with-rbac) for 
the exclusions. |
+| `role` | object with `name` | The **condition**. Matched against the 
caller's expanded roles. |
+| `scope` | object with optional `catalog`, `schema`, `table` | Where the rule 
may take effect. Omitted means metalake-wide. |

Review Comment:
   If you add a tag for metdata object called `A`, but your scope is filled 
with `B`, what will it happen?



-- 
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]

Reply via email to