Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
På den här sidan beskrivs vanliga mönster för implementering av ABAC-radfilter och kolumnmaskprinciper.
- Övergripande begrepp finns i Grundläggande begrepp för attributbaserad åtkomstkontroll (ABAC).
- Principsyntax finns i Skapa och hantera principer för radfilter och kolumnmask.
- För GRANT policyer, se ABAC GRANT policyer.
- Om din miljö använder RBAC läser du Använda RBAC med ABAC för hur identitetsfunktioner beter sig när användare tar på sig en roll och mönster som kombinerar RBAC med ABAC.
Cast-kompatibla maskeringsfunktioner
Azure Databricks automatiskt omvandlar maskeringsfunktionens utdata så att de matchar målkolumnens datatyp. Se Automatisk typgjutning för kolumnmasker.
Följande mönster hjälper dig att utforma cast-kompatibla maskeringsfunktioner.
Returnera en typ möjligt att konvertera
När du maskerar en kolumn returnerar du samma datatyp eller en typ som kan castas till den. Kontrollera datatyperna för kolumnerna som dina principmål har och kontrollera att varje gren av funktionen returnerar ett kompatibelt värde.
-- Succeeds: Masks a DOUBLE column, returns DOUBLE in every branch
CREATE FUNCTION mask_salary(salary DOUBLE, user_role STRING)
RETURNS DOUBLE
RETURN CASE
WHEN user_role IN ('admin', 'hr') THEN salary
WHEN user_role = 'manager' THEN ROUND(salary / 1000) * 1000
ELSE 0.0
END;
-- Fails: 'CONFIDENTIAL' cannot be cast to a DOUBLE column type
CREATE FUNCTION mask_salary_as_text(salary DOUBLE, user_role STRING)
RETURNS STRING
RETURN CASE
WHEN user_role IN ('admin', 'hr') THEN CAST(salary AS STRING)
ELSE 'CONFIDENTIAL'
END;
Undvik numeriskt överflöde
När en maskfunktion accepterar och returnerar en bredare numerisk typ än målkolumnen kastas resultatet automatiskt tillbaka till kolumnens typ. Om det returnerade värdet överskrider intervallet för den begränsade typen, flödar kastet över och frågan misslyckas under körning.
-- The target column is TINYINT (max 127). The input is upcast to BIGINT
-- for the function. Adding 1000 produces a BIGINT result that overflows
-- when cast back to TINYINT.
CREATE FUNCTION mask_score(score BIGINT)
RETURNS BIGINT
RETURN score + 1000;
Använda VARIANT för flera kolumntyper
Se Maskering av flera kolumntyper med en enda funktion.
Testa kompatibilitet för streaming
Testa maskeringsfunktioner med olika datamönster.
SELECT CAST(mask_salary(salary, 'admin') AS DOUBLE) FROM employees;
SELECT CAST(mask_salary(salary, 'manager') AS DOUBLE) FROM employees;
SELECT CAST(mask_salary(salary, 'viewer') AS DOUBLE) FROM employees;
Maskering av flera kolumntyper med en enda funktion
En enda maskerings-UDF som accepterar och returnerar en VARIANT kan maskera kolumner av många datatyper, vilket minskar antalet UDF:er och policyer du underhåller. Azure Databricks kastar kolumnvärdet till VARIANT innan funktionen körs, och kastar sedan returvärdet tillbaka till kolumnens typ enligt ANSI SQL-regler.
I funktionen använder du schema_of_variant() för att inspektera värdet och förgrena utifrån dess typ. I varje gren returnerar du ett värde som kan konverteras till den avsedda kolumnens datatyp.
Maskera flera numeriska typer
Den enklaste VARIANT masken returnerar en enda konstant som Azure Databricks kastar till varje kolumns typ. En policy som använder denna funktion kan maskera INT, DOUBLE, och DECIMAL kolumner, utan en separat funktion för varje precision:
CREATE FUNCTION mask_numeric(val VARIANT)
RETURNS VARIANT
DETERMINISTIC
RETURN 0::VARIANT;
För att variera det maskerade värdet efter typ, förgrena på schema_of_variant() och returnera ett lämpligt värde för varje:
CREATE FUNCTION flexible_mask(data VARIANT)
RETURNS VARIANT
RETURN CASE
WHEN schema_of_variant(data) = 'BIGINT' THEN 0::VARIANT
WHEN schema_of_variant(data) = 'DATE' THEN DATE'1970-01-01'::VARIANT
WHEN schema_of_variant(data) = 'DOUBLE' THEN 0.00::VARIANT
ELSE NULL::VARIANT
END;
Heltalstyper utökas till BIGINT i en VARIANT, så gör förgreningar baserat på BIGINT istället för INT eller TINYINT.
Maskera STRUCT-, ARRAY- och MAP-kolumner
Metoden VARIANT maskerar också komplexa typkolumner och utvidgar det numeriska exemplet ovan till nästlade data. En STRUCT, , eller MAP kolumn når funktionen som en VARIANT, och Azure Databricks kastar tillbaka det som funktionen returnerar till kolumnens deklarerade ARRAYtyp. Det returnerade värdet måste ha samma schema som indatan, annars misslyckas casten och frågefelen uppstår.
Note
STRUCT kolumner stöds på Databricks Runtime 18.1 och uppåt.
ARRAY och MAP kolumner stöds på Databricks Runtime 19 och senare. Denna casting fungerar endast inom ABAC:s kolumnmask- och radfilterpolicys, inte i generella SQL- eller tabellmasker.
Följande exempelfunktion maskerar specifika STRUCT, ARRAY, och MAP typer. Lägg till en WHEN gren för varje schema du behöver maskera:
CREATE OR REPLACE FUNCTION generic_mask(val VARIANT)
RETURNS VARIANT
RETURN CASE
-- STRUCT<id: INT, ssn: STRING>: keep id, redact ssn
WHEN schema_of_variant(val) = 'OBJECT<id: BIGINT, ssn: STRING>' THEN
to_variant_object(named_struct('id', val:id, 'ssn', 'xxx-xx-xxxx'))
-- ARRAY<STRING>: return a single redacted element
WHEN schema_of_variant(val) = 'ARRAY<STRING>' THEN
to_variant_object(array('redacted'))
-- MAP<STRING, STRING>: redact every value
WHEN schema_of_variant(val) = 'OBJECT<key1: STRING, key2: STRING>' THEN
to_variant_object(map('key1', 'redacted', 'key2', 'redacted'))
ELSE NULL::VARIANT
END;
Varje WHEN gren gör två saker, beskrivna i följande avsnitt:
-
Identifiera VARIANT-schemat. Varje
VARIANTschema behöver sin egen maskeringslogik, så funktionen grenar på schemasträngen somschema_of_variant(val)återvänder för att tillämpa rätt redaktion på varje. -
Bygg upp maskvärdet igen. Skapa ett maskerat värde med kolumnens typ och omslut det med
to_variant_object()för att returnera enVARIANT.
Ett värde vars schema inte matchar någon gren faller igenom till ELSE.
Identifiera VARIANT-schemat
Matcha mot värdets VARIANT schema, inte kolumnens deklarerade typ: att kasta till VARIANT normaliserar datan, så schemat kan skilja sig från kolumndefinitionen. Följande exempel visar vanliga fall:
| Kolumntyp |
schema_of_variant() resultat |
Notes |
|---|---|---|
ARRAY<STRING> |
ARRAY<STRING> |
|
ARRAY<INT> |
ARRAY<BIGINT> |
Heltalstyper utökas till BIGINT. |
STRUCT<id: INT, name: STRING> |
OBJECT<id: BIGINT, name: STRING> |
både STRUCT- och MAP-kolumnerna blir OBJECT. |
STRUCT<name: STRING, id: INT> |
OBJECT<id: BIGINT, name: STRING> |
Fälten sorteras alfabetiskt efter nyckel, inte deklarationsordning. |
ARRAY<STRUCT<id: INT, name: STRING>> |
ARRAY<OBJECT<id: BIGINT, name: STRING>> |
|
MAP<STRING, STRING> Avgörande {a: 'x'} |
OBJECT<a: STRING> |
Varierar beroende på rad: varje rads nycklar bestämmer schemat. |
MAP<STRING, STRING> Avgörande {a: 'x', b: 'y'} |
OBJECT<a: STRING, b: STRING> |
En annan rad i samma kolumn ger ett annat schema. |
MAP<STRING, STRING> Avgörande {a: null} |
OBJECT<a: VOID> |
Ett nollvärde blir VOID. |
MAP<STRING, STRUCT<id: INT, name: STRING>> Avgörande {a: ...} |
OBJECT<a: OBJECT<id: BIGINT, name: STRING>, ...> |
Återskapa det maskerade värdet
För varje schema du matchar, bygg ett redigerat värde med samma struktur och slå in det i to_variant_object():
- Använd
named_struct()för att bygga om ettSTRUCT, behålla de fält du vill ha och ersätta resten. - Använd
array()för att bygga om enARRAY. - Använd
map()för att bygga om enMAPmed redigerade värden.
Azure Databricks konverterar den returnerade VARIANT tillbaka till kolumnens deklarerade typ, så varje återskapat värde måste kunna konverteras till den typen.
Testa en VARIANT-mask
Innan du kopplar en funktion till en policy kan du testa den i en vanlig fråga för att bekräfta den maskerade utdatan. Följande funktion maskerar en ARRAY<STRUCT<id: BIGINT, value: FLOAT>> kolumn och ger ett fel för vilket annat schema som helst:
CREATE OR REPLACE FUNCTION mask_points(v VARIANT)
RETURNS VARIANT
RETURN CASE
WHEN schema_of_variant(v) = 'ARRAY<OBJECT<id: BIGINT, value: FLOAT>>' THEN
to_variant_object(array(named_struct('id', 1, 'value', 2.1)))
ELSE raise_error('Unexpected VARIANT schema: ' || schema_of_variant(v))
END;
Konvertera kolumnen med to_variant_object(), applicera maskeringsfunktionen och använd variant_get() för att kasta tillbaka den maskerade VARIANT till kolumnens typ. Detta speglar vad policyn gör vid körning:
SELECT variant_get(mask_points(to_variant_object(points)), '$', typeof(points)) AS masked
FROM my_catalog.my_schema.my_table;
Limitations
- En komplex kolumn som innehåller
CHAR,VARCHAR, ,GEOMETRY,GEOGRAPHYellerTIMEsom inte kan maskeras medVARIANT. -
MAPNycklar måste varaSTRING. Kolumner som skrivsMAP<INT, ...>,MAP<DATE, ...>, och så vidare konverteras inte.
Förhindra åtkomst tills känsliga kolumner har taggats
Ett vanligt styrningsmönster är att kontrollera åtkomsten baserat på om data har klassificerats. Du kan implementera detta med en standardbegränsande tagg och principer som tillämpar olika skyddsnivåer beroende på klassificeringsstatusen.
- Använd en tagg som
classification : unverifiedalla nya objekt som standard, via automatisering eller genom taggarv genom att tillämpa taggen på katalog- eller schemanivå, så att alla nya tabeller som läggs till i katalogen eller schemat automatiskt ärver taggen. - Skapa en radfilterprincip som blockerar åtkomst till tabeller taggade
classification : unverified. - Skapa en kolumnmaskprincip som maskerar känsliga kolumner i tabeller där taggen
classification : unverifiedinte längre finns. - När en dataförvaltare slutför klassificeringen uppdaterar de taggen. Blockeringsprincipen matchar inte längre och maskeringsprincipen börjar gälla.
-- Block access to unverified tables for all non-admin users
CREATE FUNCTION catalog.schema.block_all() RETURNS BOOLEAN
RETURN FALSE;
CREATE POLICY block_unverified
ON CATALOG my_catalog
ROW FILTER catalog.schema.block_all
TO `account users` EXCEPT `data_admins`
FOR TABLES
WHEN has_tag_value('classification', 'unverified');
Om du vill skydda känsliga data efter att de har klassificerats definierar du en kolumnmaskprincip som börjar gälla när taggen classification : unverified inte längre finns:
CREATE FUNCTION catalog.schema.mask_pii(val STRING)
RETURNS STRING
RETURN '***';
CREATE POLICY mask_reviewed_pii
ON CATALOG my_catalog
COLUMN MASK catalog.schema.mask_pii
TO `account users`
EXCEPT `data_admins`
FOR TABLES
WHEN NOT has_tag_value('classification', 'unverified')
MATCH COLUMNS (has_tag_value('pii', 'name') OR has_tag_value('pii', 'address')) AS m
ON COLUMN m;
Partiell avslöjande utan regex
Visa en del av ett känsligt värde med hjälp av strängåtgärder i stället för regex. Regex-baserad maskering söker igenom hela värdet för varje rad, vilket är dyrt för stora textfält (se Undvik regexmaskering på stora textfält).
CREATE FUNCTION mask_ssn(ssn STRING, show_last INT) RETURNS STRING
DETERMINISTIC
RETURN CONCAT('***-**-', RIGHT(ssn, show_last));
Konsekvent hashning (deterministisk pseudonymisering)
Konsekvent hashning (kallas även deterministisk pseudonymisering) ersätter känsliga data med ett hashvärde som är detsamma i flera tabeller. Markera en funktion som DETERMINISTIC talar om för motorn att funktionen alltid returnerar samma resultat för samma indata, vilket hjälper den att optimera frågan. Se Använda deterministiska, felsäkra uttryck.
Följande funktion hashar konsekvent ett strängvärde och använder en version parameter för att stödja nyckelrotation. Öka version talet genom en klausul i policyn USING COLUMNS för att generera nya hashvärden utan att bryta historiska data som använde den tidigare versionen. Funktionen sammanfogar det ursprungliga värdet med versionsnumret före hashning, så samma indata med samma version genererar alltid samma hash.
CREATE FUNCTION pseudonymize(val STRING, version INT) RETURNS STRING
DETERMINISTIC
RETURN SHA2(CONCAT(val, CAST(version AS STRING)), 256);
Maskera en kolumn baserat på attribut hos den sökande användaren
Important
Identitetsattribut i ABAC-policyer är i Beta. För att använda dem måste en kontoadministratör:
- Aktivera identitetsattributen i ABAC Policies Preview från kontokonsolens Förhandsgranskningssida . Se Hantera förhandsversioner på kontonivå.
- Konfigurera identitetsattributprovisionering för kontot. Se Identitetsattribut.
En kolumnmaskpolicy kan använda användarens identitetsattribut för att maskera känslig data utan att behöva dedikerade grupper. Till exempel kan den hålla data omaskerad för användare med department = HR och maskera den för alla andra.
Dessa mönster kräver identitetsattribut som tillhandahålls till dina användare från din identitetsleverantör, och funktionerna beter sig annorlunda än tagg-only-villkor på sätt som påverkar hur du skriver policyn. Innan du använder dem, granska funktioner för identitetsattribut och identitetsattribut.
Important
Funktionerna löses till false när användaren inte har något värde för attributet eller när attributnyckeln inte existerar. Skriv villkoret så att detta false resultat begränsar åtkomst snarare än ger den. Neutralisera matchningen med NOT så att masken gäller om inte attributet matchar. Till exempel WHEN NOT has_identity_attribute_value('department', 'HR') maskerar kolumnen för alla utom användare vars avdelning är HR, och eftersom ett saknat värde också falseär , maskeras användare utan avdelningsattribut också. Undvik det motsatta: ett villkor som bara maskerar när attributet matchar lämnar användare som inte har något värde för attributet omaskerade.
För utvärderingsbeteende, se Identitetsattributvillkor. För begränsningar, se Identitetsattribut i policyvillkor.
Matcha ett fast värde
Dölj ssn för alla vars avdelning inte är HR:
CREATE FUNCTION hr_catalog.people.mask_ssn(s STRING) RETURNS STRING RETURN '***-**-****';
CREATE OR REPLACE POLICY mask_ssn_non_hr
ON SCHEMA hr_catalog.people
COLUMN MASK hr_catalog.people.mask_ssn
TO `account users`
FOR TABLES
WHEN NOT has_identity_attribute_value('department', 'HR')
MATCH COLUMNS has_tag_value('pii', 'ssn') AS ssn_col
ON COLUMN ssn_col;
I detta exempel ser en användare vars avdelning är HR verkliga värden. En användare i någon annan avdelning, och en användare utan avdelningsattribut, ser båda masken.
Matcha mot en reglerad tagg
Det föregående exemplet namnger ett specifikt attributvärde (HR) i policyn, så att täcka flera avdelningar skulle innebära att man skriver en separat policy för varje avdelning. För att täcka alla avdelningar med en enda policy, tagga varje tabell med den avdelning som äger den, och jämför sedan användarens department attribut med den taggen. Kolumnen avslöjas endast när användarens avdelning matchar tabellens dept_tag värde:
CREATE FUNCTION prod.sales.mask_ssn(s STRING) RETURNS STRING RETURN '***-**-****';
CREATE OR REPLACE POLICY mask_unless_dept_matches
ON SCHEMA prod.sales
COLUMN MASK prod.sales.mask_ssn
TO `account users`
FOR TABLES
WHEN NOT has_identity_attribute_tag_match('department', 'dept_tag')
MATCH COLUMNS has_tag_value('pii', 'ssn') AS ssn_col
ON COLUMN ssn_col;
Attributnycklar och värden är båda kasuskänsliga, och värden jämförs exakt: Finance och finance matchar inte.
Begränsa åtkomsten för externa agenter som agerar på uppdrag av en användare
Important
Kontextattribut i ABAC-policyer är i Beta. För att använda dem måste en kontoadministratör aktivera UC ABAC Context Attributes förhandsvisning från kontokonsolens Förhandsgranskningssida . Se Hantera förhandsversioner på kontonivå.
Kontextattribut kan användas för att begränsa dataåtkomst för förfrågningar som görs på användarens vägnar via en OAuth-applikation (user-to-machine (U2M) authorization). Om agenter är anslutna via OAuth kan denna uppsättning användas för att förhindra att de får tillgång till data när de agerar på användarens vägnar, även om användaren fortfarande kan läsa datan när de frågar direkt i arbetsytan.
All OAuth-autentiserad åtkomst via Azure Databricks CLI,SDK:erna eller SQL Statement Execution API ställs request.is_on_behalf_of in till 'true', även när en användare manuellt frågar. Åtkomst som autentiseras med en personlig åtkomsttoken (PAT) gör det inte. Åtkomst till Genie kan inte fångas genom denna mekanism.
Dessa mönster använder kontextattributfunktionerna. För tillgängliga attribut och beteende, se Context attribut-funktioner (Beta).
Anslut agenten till Azure Databricks
För att använda kontextattribut, koppla agenten med en anpassad OAuth-applikation:
- En kontoadministratör aktiverar förhandsvisningen av UC ABAC Context Attributes från kontokonsolen. Se Hantera förhandsversioner av Azure Databricks.
- En kontoadministratör registrerar en anpassad OAuth-applikation i kontokonsolen och noterar dess klient-ID.
- Koppla agenten till den Azure Databricks hanterade MCP via den OAuth-applikationen. Se Konfigurera en anpassad OAuth-klient.
En agent som använder den inbyggda databricks-cli klienten autentiserar sig fortfarande över OAuth, så request.is_on_behalf_of läser 'true'. Du kan dock inte skilja dess förfrågningar från manuell användning av CLI, eftersom båda delar databricks-cli klient-ID. För att styra en specifik applikation, registrera en anpassad OAuth-applikation och koppla agenten genom den.
Varning
Se till att en agent inte kan nå datan via en väg som din försäkring inte täcker:
- Om du begränsar åtkomsten baserat på
request.is_on_behalf_of, se till att agenten inte kan autentiseras med en PAT. En PAT sätterrequest.is_on_behalf_ofinte till'true', så ett villkor på det attributet begränsar det inte. - Om du begränsar åtkomst baserat på
request.client_id, se till att agenten inte kan ansluta via en klient som ditt tillstånd inte täcker, som den generiskadatabricks-cliklienten.
Maskera en kolumn för begäranden som görs för någon annans räkning
Mask ssn för förfrågningar som körs för en användares räkning, såsom en agent som agerar via en registrerad OAuth-applikation, medan den lämnas omaskad för direkta frågor:
CREATE FUNCTION hr_catalog.people.mask_ssn(s STRING) RETURNS STRING RETURN '***-**-****';
CREATE OR REPLACE POLICY mask_ssn_for_agents
ON SCHEMA hr_catalog.people
COLUMN MASK hr_catalog.people.mask_ssn
TO `account users`
FOR TABLES
WHEN has_context_attribute_value('request.is_on_behalf_of', 'true')
MATCH COLUMNS has_tag_value('pii', 'ssn') AS ssn_col
ON COLUMN ssn_col;
I det här exemplet returnerar en direkt fråga faktiska värden, och en begäran som görs för någon annans räkning visar de maskerade värdena. Med CLI:t och SQL Statement Execution API:t läser request.is_on_behalf_of också 'true', så den här policyn maskerar kolumnen även för dessa begäranden. För att rikta in dig på en specifik applikation istället, matcha request.client_id mot applikationens klient-ID.
Begränsa en kolumn till en godkänd applikation
Mask ssn för varje extern förfrågan utom de från din godkända applikation, identifierad av dess OAuth-klient-ID:
CREATE OR REPLACE POLICY mask_ssn_unapproved_apps
ON SCHEMA hr_catalog.people
COLUMN MASK hr_catalog.people.mask_ssn
TO `account users`
FOR TABLES
WHEN NOT has_context_attribute_value('request.client_id', '<your-app-client-id>')
MATCH COLUMNS has_tag_value('pii', 'ssn') AS ssn_col
ON COLUMN ssn_col;
För att se vilken applikation som gjort en begäran, granska identity_metadata.acting_resource fältet i revisionsloggarna.
Radfiltrering med endast kolumnpredikat
Filtrera rader med enkel boolesk logik som endast refererar till tabellkolumner. Endast kolumnpredikat aktiverar predikat-pushdown, vilket gör att motorn kan hoppa över irrelevanta data under genomsökningar (se Förstå predikat-pushdown på skyddade tabeller).
CREATE FUNCTION filter_by_region(region STRING, allowed STRING)
RETURNS BOOLEAN
DETERMINISTIC
RETURN array_contains(split(allowed, ','), lower(region));
Använd med en policy som överför de godkända regionerna som en konstant.
CREATE POLICY regional_access
ON CATALOG analytics
ROW FILTER filter_by_region
TO 'emea_team'
FOR TABLES
MATCH COLUMNS has_tag('region') AS rgn
USING COLUMNS (rgn, 'emea,apac');
Radfiltrering över flera relaterade kolumner
När en tabell har flera kolumner som representerar relaterade attribut (till exempel ship_to_country och bill_to_country), kan du matcha dem med separata taggvillkor och skicka båda till en enda UDF. Detta undviker att skapa separata principer för varje kolumn. En radfilterpolicy kan innehålla upp till sex kolumnuttryck, och en kolumnmaskpolicy kan inkludera upp till tre kolumnuttryck i klausulen MATCH COLUMNS (se policykvoter).
CREATE FUNCTION filter_by_countries(ship_country STRING, bill_country STRING, allowed STRING)
RETURNS BOOLEAN
DETERMINISTIC
RETURN array_contains(split(allowed, ','), lower(ship_country))
OR array_contains(split(allowed, ','), lower(bill_country));
CREATE POLICY regional_orders
ON SCHEMA prod.orders
ROW FILTER filter_by_countries
TO analysts
FOR TABLES
WHEN has_tag_value('sensitivity', 'high')
MATCH COLUMNS
has_tag('ship_country') AS ship,
has_tag('bill_country') AS bill
USING COLUMNS (ship, bill, 'us,ca,mx');
En analytiker ser bara beställningar där leverans- eller faktureringslandet finns i listan över tillåtna.
Uppslagstabeller i ABAC-policy UDF:er
När åtkomstreglerna varierar per användare och inte kan uttryckas enbart via principens satser kan du kontrollera åtkomsträttigheterna mot en liten uppslagstabell TO/EXCEPT . Använd TO/EXCEPT när det är möjligt, eftersom det är den bästa metoden för att rikta in sig på huvudkonton (se Metod för att rikta in sig på huvudkonton). Håll uppslagstabellen liten så att optimeraren konverterar underfrågan till en sändningshashkoppling (se Behåll uppslagstabeller små).
CREATE TABLE access_rules (
principal VARCHAR(255),
priority VARCHAR(64)
);
INSERT INTO access_rules VALUES
('alice@company.com', '1-URGENT'),
('alice@company.com', '2-HIGH'),
('bob@company.com', '1-URGENT');
CREATE FUNCTION priority_allowed(o_priority STRING) RETURNS BOOLEAN
RETURN EXISTS (
SELECT 1 FROM access_rules
WHERE principal = session_user() AND priority = o_priority
);
CREATE POLICY priority_filter
ON CATALOG operations
ROW FILTER priority_allowed
TO `account users`
FOR TABLES
MATCH COLUMNS has_tag('priority') AS pri
USING COLUMNS (pri);