ABAC DENY policies (Beta)

Important

ABAC DENY policies are in Beta. DENY policies are attached at the catalog or schema level and deny the MANAGE ACCESS CONTROL privilege on the supported securable types. See Supported securable types and privileges.

ABAC DENY policies explicitly deny Unity Catalog privileges to principals on securable objects whose governed tags match a condition, always taking precedence over any grant. This page covers how to create, edit, list, and delete ABAC DENY policies, what it means to deny MANAGE ACCESS CONTROL, and the current scope and limitations.

You can create and manage ABAC DENY policies using Catalog Explorer, SQL, the REST API, Terraform, or the Databricks SDKs.

For an overview of ABAC and core concepts, including governed tags and built-in functions such as has_tag and has_tag_value, see Core concepts for attribute-based access control (ABAC).

Compute requirements

Using SQL to create, modify, or drop DENY policies requires a classic compute resource running Databricks Runtime 18 LTS or above.

Note

Databricks Runtime 18 is newer than Databricks Runtime 18.0, 18.1, and 18.2. Features that would previously have shipped as a later numbered version now ship as dated updates to Databricks Runtime 18 instead. For details, see About unified release notes.

What is a DENY policy

A DENY policy is an attribute-based access control policy that explicitly denies a Unity Catalog privilege to specified principals on the securable objects whose governed tags match the policy's condition. Unity Catalog evaluates the policy's WHEN condition against the governed tags on each securable object in the policy's scope every time access is checked, and denies the privilege on every securable object that matches.

A DENY policy takes precedence over any grant of the same privilege and cannot be overridden by an individual grant.

A DENY policy is governed by the following rules:

  • DENY always takes precedence. A DENY policy overrides any grant of the same privilege, including grants held through inheritance, group membership, or implicitly through object ownership. No individual grant can override an active DENY.
  • Metastore admins are always implicitly exempt. A metastore admin is never affected by a DENY policy for MANAGE ACCESS CONTROL, which ensures there is always a path to modify or remove any DENY policy.
  • DENY inherits downward. The denial itself inherits down the object hierarchy the same way grants follow privilege inheritance. A DENY policy on a catalog denies the privilege on every current and future object within that catalog, and a DENY policy on a schema denies it on every current and future object within that schema.
  • Overlapping DENY policies are combined, and the most restrictive outcome applies. When multiple DENY policies apply to the same principal, their effects are unioned. One DENY policy cannot exempt a principal that another DENY policy targets. If any applicable policy denies the privilege, it is denied.
  • DENY policies are independent of grants. Unlike a REVOKE, which only removes a privilege that was explicitly granted, a DENY policy does not depend on an existing grant. You can deny a privilege that was never granted, and removing a grant does not remove a DENY policy. A DENY policy remains in effect until it is explicitly dropped.

DENY policies can reference either governed tags you create yourself or system tags predefined by Azure Databricks in their conditions.

DENY policies differ from row filter and column mask policies in two ways:

  • Row filter and column mask policies restrict the content of data a user can already access. DENY policies determine whether a principal can perform an action, such as managing access control, at all.
  • Row filter and column mask policies require a user-defined function (UDF) to implement the filter or mask. DENY policies do not use UDFs. The condition is expressed inline in the policy definition.

What does it mean to deny MANAGE ACCESS CONTROL?

MANAGE ACCESS CONTROL is a child of the MANAGE privilege that governs access management, such as granting and revoking privileges, transferring ownership, and managing ABAC policies. It can be denied, but not granted. For details, see MANAGE ACCESS CONTROL.

DENY policies can be used to deny the MANAGE ACCESS CONTROL privilege to prevent specified principals, including object owners, from performing access-management operations on the objects in a policy's scope. It removes the access-management capabilities this privilege governs, regardless of how a principal holds them, whether through the MANAGE privilege or implicitly through object ownership.

On the affected objects, a denied principal loses the ability to:

Denying MANAGE ACCESS CONTROL does not remove a principal's ability to view object metadata. A principal with MANAGE or an object owner can still see that the object exists, and can still exercise every other capability that MANAGE, their other privileges, or ownership provide. They lose only the access-management abilities listed above.

Denying MANAGE ACCESS CONTROL does not close every path through which a principal can share data. See Considerations for data sharing.

DENY policy examples

The following policy denies MANAGE ACCESS CONTROL on every table tagged sensitive in catalog_a to all account users, except the data_admins group. Affected principals, including table owners, lose the ability to grant or revoke privileges, change ownership, or manage row filters and column masks on those tables:

CREATE POLICY deny_manage_access_control_sensitive_tables
ON CATALOG catalog_a
COMMENT 'Prevent non-admins from managing permissions on sensitive tables'
TO `account users`
EXCEPT `data_admins`
DENY MANAGE ACCESS CONTROL
FOR TABLES
WHEN has_tag('sensitive');

The following policy denies MANAGE ACCESS CONTROL on all schemas in catalog_a to a designated group, except data_admins. Because DENY inherits downward, affected principals also lose the ability to manage access on the objects within those schemas:

CREATE POLICY deny_designated_users_catalog_access
ON CATALOG catalog_a
COMMENT 'Prevent designated users from managing access on catalog objects'
TO `designated_users`
EXCEPT `data_admins`
DENY MANAGE ACCESS CONTROL
FOR SCHEMAS;

Supported securable types and privileges

DENY policies support one privilege, MANAGE_ACCESS_CONTROL, on the following securable types. A policy applies to one securable type. Unity Catalog validates the privilege against the securable type when you create the policy.

Securable type MANAGE_ACCESS_CONTROL
Catalog
Schema
Table
Volume
Function
Model
Secret

This is the list of securable types supported in the FOR clause. When a policy is attached to a catalog or schema, the DENY inherits to all objects within that catalog or schema, even objects whose type is not supported by the FOR clause.

In SQL, use the plural securable type after FOR, such as DENY MANAGE ACCESS CONTROL FOR TABLES or FOR SCHEMAS. Singular forms are not accepted. In the REST API, set for_securable_type to the singular form, for example TABLE.

Create a DENY policy

You can create a DENY policy through the Catalog Explorer UI, with the CREATE POLICY SQL statement, or with the REST API.

To create a DENY policy, you must have MANAGE on the catalog or schema where the policy is attached, or own that securable object.

Catalog Explorer

DENY policies must be created from a catalog or schema. The Deny access policy type is not available when you start from an individual object such as a table.

  1. In your Azure Databricks workspace, click Data icon. Catalog.
  2. Select the catalog or schema where you want to attach the policy. DENY policies can only be attached at the catalog or schema level.
  3. Click the Policies tab.
  4. Click New policy.
  5. Under Policy identification, enter a Policy name and an optional Description.
  6. Under Principals and scope:
    • In Applied to, select the principals (users, groups, or service principals) that the policy applies to.
    • In Except for, optionally select principals to exclude from the policy.
    • In Scope, confirm the catalog or schema where the policy is attached.
  7. Under Policy type, select Deny access.
  8. Under Securable objects, select the securable type the policy applies to. See supported types and privileges.
  9. Under Condition, choose how to scope the policy to securables of the selected type in the catalog or schema:
    • No condition applies the policy to all securables of that type under the selected catalog or schema.
    • Securables matching any of these tags applies the policy only to securables that carry at least one of the selected governed tags.
    • Securables matching a custom expression lets you write a tag-based expression to determine which securables the policy applies to. See Conditions and built-in functions for the available condition functions.
  10. Under Privileges, select MANAGE ACCESS CONTROL. This is the only privilege DENY policies support.
  11. Click Show code to review the equivalent SQL statement before saving, then click Create policy.

SQL

The SQL syntax for a DENY policy uses a DENY ... FOR ... WHEN ... body in place of ROW FILTER or COLUMN MASK.

CREATE [OR REPLACE] POLICY policy_name
ON { CATALOG catalog_name | SCHEMA schema_name }
[COMMENT description]
TO principal [, ...]
[EXCEPT principal [, ...]]
DENY MANAGE ACCESS CONTROL
FOR securable_type
[WHEN condition]

Parameters:

  • policy_name: A name for the policy. Must be unique among all policies defined on the same securable object.
  • ON { CATALOG | SCHEMA }: The scope where the policy is attached. DENY policies can be attached at the catalog or schema level, not at an individual securable object.
  • TO principal [, ...]: The users, groups, or service principals the policy applies to.
  • EXCEPT principal [, ...]: Principals exempt from the policy. Metastore admins are always implicitly exempt and do not need to be listed.
  • DENY MANAGE ACCESS CONTROL: The privilege to deny. MANAGE ACCESS CONTROL is the only supported privilege.
  • FOR securable_type: The securable type within the scope that the policy applies to. A policy applies to one type. See supported types and privileges.
  • WHEN condition: A tag-based boolean expression that determines which securables the policy applies to within scope. Uses built-in functions has_tag('tag_name') and has_tag_value('tag_name', 'tag_value'). If omitted, defaults to TRUE (applies to all securables of the type in scope). See Conditions and built-in functions for the available condition functions.

For examples, see DENY policy examples.

REST API

This example denies MANAGE ACCESS CONTROL on every table tagged sensitive in catalog_a to all account users, except data_admins:

curl -X POST "https://${DATABRICKS_HOST}/api/2.1/unity-catalog/policies" \
  -H "Authorization: Bearer ${DATABRICKS_TOKEN}" \
  -H "Content-Type: application/json" \
  --data-binary @- << 'EOF'
{
  "name": "deny_manage_access_control_sensitive_tables",
  "comment": "Prevent non-admins from managing permissions on sensitive tables",
  "on_securable_type": "CATALOG",
  "on_securable_fullname": "catalog_a",
  "for_securable_type": "TABLE",
  "policy_type": "POLICY_TYPE_DENY",
  "to_principals": ["account users"],
  "except_principals": ["data_admins"],
  "deny": {
    "privileges": ["MANAGE_ACCESS_CONTROL"]
  },
  "when_condition": "has_tag('sensitive')"
}
EOF

name, on_securable_type, on_securable_fullname, for_securable_type, policy_type, to_principals, and deny.privileges are required. comment, except_principals, and when_condition are optional.

For request and response details, see Create policy in the REST API reference.

Edit a DENY policy

Catalog Explorer

Manage DENY policies from the Policies tab of the parent catalog or schema they are attached to.

  1. In your Azure Databricks workspace, click Data icon. Catalog.
  2. Select the catalog or schema the policy is attached to.
  3. Click the Policies tab.
  4. Select the policy you want to edit.
  5. Update any fields you want to change.
  6. Click Update policy.

SQL

To edit a DENY policy with SQL, run CREATE OR REPLACE POLICY with the same name and target. See Create a DENY policy.

REST API

Unlike CREATE OR REPLACE POLICY in SQL, PATCH supports partial updates. Use the update_mask query parameter to specify which fields to change. Only those fields are updated, and fields absent from the request body are left unchanged.

This example adds audit_admins to the principals excluded from the policy:

curl -X PATCH "https://${DATABRICKS_HOST}/api/2.1/unity-catalog/policies/CATALOG/catalog_a/deny_manage_access_control_sensitive_tables?update_mask=except_principals" \
  -H "Authorization: Bearer ${DATABRICKS_TOKEN}" \
  -H "Content-Type: application/json" \
  --data-binary @- << 'EOF'
{
  "except_principals": ["data_admins", "audit_admins"]
}
EOF

The value you send replaces the existing list rather than adding to it, so you must include every principal you want to exclude, not just the new ones.

Delete a DENY policy

Catalog Explorer

Manage DENY policies from the Policies tab of the parent catalog or schema they are attached to.

  1. In your Azure Databricks workspace, click Data icon. Catalog.
  2. Select the catalog or schema the policy is attached to.
  3. Click the Policies tab.
  4. Select the policy.
  5. Click Delete policy.

SQL

To delete a DENY policy with SQL, run DROP POLICY:

DROP POLICY deny_manage_access_control_sensitive_tables ON CATALOG catalog_a;

REST API

curl -X DELETE "https://${DATABRICKS_HOST}/api/2.1/unity-catalog/policies/CATALOG/catalog_a/deny_manage_access_control_sensitive_tables" \
  -H "Authorization: Bearer ${DATABRICKS_TOKEN}"

Show policies

Use SHOW POLICIES to list the policies defined on a securable object. Use SHOW EFFECTIVE POLICIES to also include policies inherited from parent scopes, such as catalog-level policies that affect a schema.

SHOW [EFFECTIVE] POLICIES ON { CATALOG | SCHEMA } securable_name

The result includes the policy name, policy type, the catalog and schema of the securable each policy is defined on, and that securable's type and full name. DENY policies are returned with policy type DENY alongside any row filter, column mask, and GRANT policies attached at the same scope. The Table column is populated only when a policy is defined on a table. This applies to row filter and column mask policies. For GRANT and DENY policies, the Table column is NULL.

Example:

SHOW EFFECTIVE POLICIES ON CATALOG catalog_a;
Policy Name                                  Policy Type  Catalog    Schema  Table  Comment                                                           on_securable_type  on_securable_fullname
-------------------------------------------  -----------  ---------  ------  -----  ----------------------------------------------------------------  -----------------  ---------------------
deny_manage_access_control_sensitive_tables  DENY         catalog_a  NULL    NULL   Prevent non-admins from managing permissions on sensitive tables  CATALOG            catalog_a

SHOW GRANTS does not reflect DENY policies. See Limitations.

Describe a policy

Use DESCRIBE POLICY to view the details of a specific DENY policy. Requires READ METADATA or MANAGE on the target securable object, or object ownership.

{ DESC | DESCRIBE } POLICY policy_name ON { CATALOG | SCHEMA } securable_name

The result shows the policy's properties as key-value pairs, including name, securable object type, securable object name, principals, denied privileges, and the WHEN condition.

Query policy definitions with Information Schema

You can query DENY policy definitions in the current catalog using INFORMATION_SCHEMA.ABAC_POLICY_DEFINITIONS:

SELECT *
FROM information_schema.abac_policy_definitions
WHERE policy_type = 'DENY';

For the available columns and additional examples, see ABAC_POLICY_DEFINITIONS.

Policy quotas

Resource Limit
Policies per metastore 10,000
Policies per catalog or schema 100

These quotas are separate from the quotas for row filter and column mask policies and from the quotas for GRANT policies.

Audit logging

DENY policy create, alter, and drop operations are logged under the same createPolicy, deletePolicy, getPolicy, and listPolicies actions as row filter and column mask policies. See Audit logging for example audit log queries.

Best practices

  • Use groups in TO and EXCEPT, not individual users. Adding or removing users from a group named in a policy changes who the policy applies to, without editing the policy.
  • Always exempt a trusted group from the policy, so you don't accidentally lock everyone out. This is especially important when a policy applies to the account users group. Use the EXCEPT clause to name a group that retains the privilege, so that at least one set of principals can still manage access on the affected objects.
  • Attach policies at the smallest scope that covers the targets. A broader scope brings unrelated securables into the policy's tag-matching, and might deny access where you didn't intend.

Considerations for data sharing

Denying MANAGE ACCESS CONTROL blocks only the capabilities that ownership and the MANAGE privilege control. It does not close every path through which a principal can share data. A DENY policy does not prevent the following:

  • Copying data with CTAS. A principal with SELECT on a table and CREATE TABLE on a schema (along with USE CATALOG and USE SCHEMA) can copy the data into a new table with CREATE TABLE ... AS SELECT. To restrict this, avoid granting CREATE TABLE.
  • Exposing data through a view. A principal with SELECT on a table and CREATE TABLE on a schema (along with USE CATALOG and USE SCHEMA) can create a view over the table. Because a view runs with the privileges of its owner, principals granted SELECT on the view can read the underlying data without direct access to the source table. To restrict this, avoid granting CREATE TABLE, which also authorizes view creation.
  • Applying or removing governed tags. A principal with APPLY TAG on an object and the ASSIGN privilege on a governed tag can still change that tag on the object, which can affect tag-based policies. To restrict this, limit who holds ASSIGN on the governed tag and APPLY TAG on the object. See Manage permissions on governed tags.
  • OpenSharing. A share owner with the required privilege on an object can add it to a share. To restrict this, avoid granting CREATE SHARE on the metastore.
  • Credential vending. A principal can share access to objects through credential vending. To restrict this, avoid enabling external data access on the metastore and do not grant EXTERNAL USE SCHEMA.
  • Group management. A principal with the Manage permission on a Databricks group (including account and workspace admins, who have it automatically) can change group membership, which can change who inherits access through that group. To restrict this, limit who has the Manage permission on groups.

Limitations

  • Only the MANAGE ACCESS CONTROL privilege can be denied. Other privileges, such as SELECT and MODIFY, are not supported by DENY policies.
  • The MANAGE ACCESS CONTROL privilege can be denied, but not granted.
  • A policy can be attached to a catalog or a schema, not to an individual securable object.
  • A policy applies to one securable object type. To deny the privilege on more than one securable object type in the same scope, create a separate policy for each type, or create a policy FOR SCHEMAS so that MANAGE ACCESS CONTROL is denied on all object types within the schema.
  • SHOW GRANTS, GetPermissions, and GetEffectivePermissions do not reflect DENY policies. To see the DENY policies in effect, use SHOW EFFECTIVE POLICIES on the object's catalog or schema.

More information