Replies: 4 comments 12 replies
|
Thanks for your discussion. I prefer solution A. So only the role can use the policy. Other objects won't use the policy |
|
Hi @bharos, thanks for opening the discussion. As @roryqi mentioned, we strongly prefer a policy-on-tag model (option A). I'll walk through your use case, then quote and address each concern you raised. @roryqi correct me if i'm wrong anywhere. Use case
Today a grant names a table. Tags are labels. Authorization never looks at them. You want the grant to follow the label, inside one schema. Tag Here's how we would implement that with policy-on-tag. The tag bind is the condition. Role, scope, and action live in content. The authorizer checks them after object-policy lookup. 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" }]
}When Alice (an analyst) queries, her role is used in resolution. Access is granted or denied: sequenceDiagram
actor Alice
participant Engine
participant Authz as Authorizer
participant Tags as Effective tags
participant Rel as Policy-tag relations
participant Policy as access_control policy
participant FGAC as Read restrictions
Alice->>Engine: SELECT lakehouse.finance.orders
Engine->>Authz: authorize(user=alice, action=SELECT, table=orders)
Authz->>Authz: resolve alice to role analyst
Authz->>Tags: effective tags on orders
Tags-->>Authz: certified
Authz->>Rel: policies bound to certified
Rel-->>Authz: analyst_read_certified_finance
Authz->>Policy: check role, scope, action
alt role analyst AND scope finance AND SELECT
Policy-->>Authz: match
Authz-->>Engine: ALLOW
Engine->>FGAC: resolve read_restriction policies
alt compose cleanly
FGAC-->>Engine: row filter and/or mask
Engine-->>Alice: granted, restricted
else conflict
FGAC-->>Engine: fail closed
Engine-->>Alice: denied
end
else role, scope, or action miss
Policy-->>Authz: no match
Authz-->>Engine: DENY
Engine-->>Alice: denied
end
Eval: table has effective tag This is option A on the policy-on-tag write path. Coarse allow. When FGAC is factored in, we compose: Alice is allowed the table, then read-restriction policies on the same list apply (row filter, column mask). If two distinct filters or masks conflict on one resource, we fail closed. Addressing your concernsWhere the rule lives
We prefer A. Same policy object, same policy-tag relation, same selector. A new Create authority
Create authority is separate. We consider that an auth-level question. You're right that it should be resolved. It is orthogonal to policy-on-tag. Policy-on-tag is how the rule attaches and evaluates. It is not how we decide who may create the rule. On We understand this is a bit more involved than a typical HTTP access check. We accept that as part of the design tradeoff.
Role condition
Lookup-by-role and role-delete are not blockers. If we want "show every rule for analyst," we index the role condition. For delete we use that index, or we mark the role as deleted so nothing matches it anymore. Either way the name-reuse leak goes away. Not a reason to hang the policy on the role object. DENY
That's a real situation. A deny on an ancestor and an allow (or a looser tag) on a child can silently change who can read. Nearest-wins makes a normal tag edit into an escape hatch. You're right to call that out. Policy-on-tag doesn't preclude denies, and we can define resolution for them. We advocate allow lists instead. We see this as an end-user policy management issue. Ultimately it's up to the end user to write policies for their use case. That ancestor-deny / child-allow case can be treated as a policy conflict and a failure condition. That's a resolution choice. It doesn't require hanging the policy on the object or a second attachment model. Policy on schema and role
No. Condition on the tag is right. Scope and role do not need object attachment. That write path is policy-on-object. Rory is removing it. The use case above does the same four facts without those two |
|
Coming in as an outside reader. A looks settled, so I'll skip that and raise two things about the evaluation path that I think need an answer in the design doc either way, plus a few smaller notes. 1. A tag rule can't be a jCasbin policy row
The second matches the sequence diagram above. If it's that one, the doc should state explicitly: does an RBAC DENY beat a tag ALLOW? If the tag stage runs after the enforcer returns false and can flip it to true, a tag rule silently defeats every existing deny. I'd suggest unioning the tag ALLOW with the RBAC allow set and applying RBAC deny last - but the point is that it should be written down rather than fall out of call ordering. Related, and currently unhandled: 2. Dropping DENY reverses the escalation rather than removing it
Understood, and the Starburst/Databricks comparison is fair. But allow-only means anyone who can apply a tag that has an access policy bound to it can pull objects into that policy. A table owner in Which is why I'd push back gently on this:
Separable from the attachment model, agreed. Not separable from shipping: without it, If the check is derived from Smaller notes
|
|
We’ve gone fairly deep on evaluation, create authority, and listing. I’d like to zoom out to process for a moment. Who will be writing the design proposal? What’s in scope for that doc vs later? What are the milestones, expected timeline, and priority? Thanks. Nevin |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
I am working on a design for tag-based access control in Gravitino. Before I finalize it,
there is one structural decision I would like consensus on, so it would be great to get some inputs here than me bringing a design that has already assumed an answer.
Grants today are object-identified, and authorization never reads tags. So there is no way
to express something like:
I would like to add an access rule of the shape
(principal, action, effect, tag condition, scope), evaluated inside the existingauthorization-expression path. With policy-on-tag merged, there are two plausible homes for
it.
Option A — an
access_controlpolicy type, reusingPolicyand the policy-tagrelation. Principal, action and effect live in the policy's
content; the authorizer callsObjectPolicyResolverand keeps policies of that type. Almost no new plumbing.Option B — a separate entity with principal, action, effect and scope as columns,
reading tags directly rather than through
PolicyorObjectPolicyResolver. It wouldreuse
PolicySelectorso both features express tag conditions the same way. Costs a newtable across three dialects, a REST resource and client support.
Which authority should create an access rule?
Under A, creating that rule needs
APPLY_POLICYon the policy andAPPLY_TAGon the tag.It needs no permission on the objects the rule affects — the call names no object — and
does not involve
MANAGE_GRANTS, which governs granting privileges today viahasMetadataPrivilegePermission. The rule still grantsSELECT_TABLEon every objectcarrying the tag.
Scope differs too.
APPLY_TAGbinds only atMETALAKE/TAGandAPPLY_POLICYonly atMETALAKE/POLICY(ApplyTag.canBindTo), so access rules could only be administeredmetalake-wide.
MANAGE_GRANTSbinds at every object type, and its binding at a parent covers all children.Under B the create is checked against the rule's
scope, so it can use whichever authority the project considers correct and be delegatedper catalog or schema.
Is
APPLY_POLICY+APPLY_TAGthe intended authority for creating access rules, orshould they require grant authority on the data they affect?
A related point: principal and effect
Neither has a home in policy-on-tag today — the relation has no principal column (the
policy-on-tag doc(#12177) says the selector "does not support ... principals, scopes, or general
expressions"), and
enabled/ disabled is not allow / deny.content(like a JSON text), so rules cannot belooked up by role, and deleting a role leaves rules behind that still name it - a later
role created with the same name silently inherits them.
Guidance on either point would help a lot before I take the design further.
All reactions