Feature policies¶
A feature policy controls which object types can be created in a given context. You can apply a feature policy to all native apps in an account, to a specific native app, to all personal databases in an account, to all regular databases in an account, or to a specific database.
You can block every creation of a listed object type with
BLOCKED_OBJECT_TYPES_FOR_CREATION, or attach a YAML policy body with
conditional creation rules that fire only when a SQL expression
you supply evaluates to TRUE. For example, a feature policy can permit tables in general but
block temporary tables, or permit tasks but block serverless (no-warehouse) tasks.
Feature policies are schema-level objects. Before creating one, create a dedicated database and schema to store it.
For details on using feature policies with native apps, see Use feature policies to limit the objects an app can create.
For details on using feature policies with personal databases, see Use feature policies with personal databases.
Blockable object types¶
Account-level objects (native apps only)¶
When a native app is installed with automated granting of privileges, the app can receive privileges that let it create account-level objects such as warehouses, compute pools, and databases. Once granted, these privileges can’t be directly revoked by the consumer. A feature policy lets administrators prevent apps from exercising those privileges to create specific object types, without revoking the underlying privilege.
The following account-level object types can be blocked:
- COMPUTE_POOLS
- DATABASES
- WAREHOUSES
Note
Account-level object types have no effect when a feature policy is bound to personal databases. They apply only in a native app context.
Other blockable types¶
The following object types can be blocked in any context the policy is bound to (native apps, regular databases, or personal databases) that supports creating that object type:
- AGENTS
- APPLICATION_SERVICE
- ARTIFACT_REPOSITORY
- CORTEX_SEARCH_SERVICES
- DYNAMIC_TABLES
- FILE_FORMATS
- FUNCTIONS
- GIT_REPOSITORY
- ICEBERG_TABLES
- MATERIALIZED_VIEWS
- MCP_SERVERS
- PROCEDURES
- SCHEMA
- SECRET
- STAGES
- TABLES
- TASKS
- VIEWS
- WORKSPACE
Each type is accepted in either singular or plural form (for example, both TABLE and
TABLES). Conditional creation rules can reference the
same object types; see Supported object types.
Privileges required to use feature policies¶
A role used to execute this operation must have the following privileges at a minimum:
| Privilege | Object | Notes |
|---|---|---|
| CREATE FEATURE POLICY | SCHEMA | Required to create a feature policy. This privilege must be granted on the schema containing the feature policy. |
| APPLY FEATURE POLICY | ACCOUNT | |
| APPLY or OWNERSHIP | FEATURE POLICY |
For instructions on creating a custom role with a specified set of privileges, see Creating custom roles.
For general information about roles and privilege grants for performing SQL actions on securable objects, see Overview of Access Control.
Create a feature policy¶
Use the CREATE FEATURE POLICY command to create a feature policy. The following example creates a policy that blocks task creation:
Note
Feature policies must be created within a schema.
You can also create a policy that doesn’t restrict any object types. This is useful for overriding a more general account-level policy on a specific app:
To create a policy with conditional creation rules, see Feature policy rules.
Apply a feature policy¶
To all native apps¶
To apply a feature policy to all native apps in the account, use the ALTER ACCOUNT command:
To replace an existing account-level policy without unsetting it first, use FORCE:
To unapply the policy from all native apps:
To a specific application¶
To apply a feature policy when installing an application, use the WITH FEATURE POLICY clause of
the CREATE APPLICATION command:
To apply a feature policy to an existing application, use the ALTER APPLICATION command:
To unapply the policy from a specific application:
A per-application policy overrides the account-level FOR ALL APPLICATIONS policy for that
application. See Feature policy precedence for details.
To all databases¶
To apply a feature policy to all regular databases in the account, use the
ALTER ACCOUNT command with FOR ALL DATABASES:
This policy also applies to personal databases as a fallback when no FOR ALL PERSONAL DATABASES
policy is set. It does not apply to native apps (application instances or application packages).
To replace an existing FOR ALL DATABASES policy without unsetting it first, use FORCE:
To unapply the policy from all databases:
To a specific database¶
To apply a feature policy to a specific database, use the ALTER DATABASE command:
To replace an existing database-level policy without unsetting it first, use FORCE:
To unapply the policy from the database:
A policy applied directly to a database overrides any account-level policy for that database. See Feature policy precedence for details.
To all personal databases¶
To apply a feature policy to all personal databases in the account, use the
ALTER ACCOUNT command with FOR ALL PERSONAL DATABASES:
To unapply the policy from all personal databases:
Note
The FOR ALL APPLICATIONS, FOR ALL PERSONAL DATABASES, and FOR ALL DATABASES bindings are
independent. Setting or unsetting one has no effect on the others.
Feature policy precedence¶
When an object is created, Snowflake walks the following hierarchy and enforces the first matching policy it finds. A more specific policy always wins over a more general one.
Regular databases¶
For objects created inside a regular database (not a personal database or application instance):
- A policy applied directly to the database (
ALTER DATABASE ... SET FEATURE POLICY) - The account-level
FOR ALL DATABASESpolicy - No policy applies: the creation is allowed.
Personal databases¶
For objects created inside a personal database:
- A policy applied directly to the database (
ALTER DATABASE ... SET FEATURE POLICY) - The account-level
FOR ALL PERSONAL DATABASESpolicy - The account-level
FOR ALL DATABASESpolicy (personal databases fall under this context when noFOR ALL PERSONAL DATABASESpolicy is set) - No policy applies: the creation is allowed.
Native apps (application instances)¶
For objects created inside a native app:
- A policy applied directly to the app (
ALTER APPLICATION ... SET FEATURE POLICYorCREATE APPLICATION ... WITH FEATURE POLICY) - The account-level
FOR ALL APPLICATIONSpolicy - No policy applies: the creation is allowed.
FOR ALL DATABASES does not apply to native apps (application instances or application packages).
Using an empty policy to lift restrictions¶
A policy with no blocked object types can be applied at any specific level to explicitly allow creation of all types, overriding a more general policy. For example, you can block a type for all databases at the account level while exempting a specific database from that restriction:
Feature policy rules¶
With blocked_creation_rules, a feature policy can stop users from creating
objects in ways you don’t allow. Each rule applies to an object type and blocks
a CREATE statement only when a condition you define is true. This lets you allow
users to create objects of a type in general but block specific uses, such as a
particular creation option or a property value you don’t permit.
For example, a feature policy can:
- Block temporary or transient tables.
- Require request logging on Cortex Search Services.
- Restrict object creation to a specific schema.
To block every creation of an object type, regardless of the statement, list the
type in BLOCKED_OBJECT_TYPES_FOR_CREATION instead.
Attention
blocked_creation_rules apply only to statements that create an object,
including CREATE OR ALTER. They don’t prevent a later standalone ALTER
statement from modifying the properties of an existing object, including
properties that a rule required at creation. For example, a rule that requires
REQUEST_LOGGING = TRUE when a Cortex Search Service is created doesn’t stop a
user from later running
ALTER CORTEX SEARCH SERVICE ... SET REQUEST_LOGGING = FALSE.
Policy body syntax¶
The body is a YAML document attached to the policy with an AS clause:
The YAML body has the following structure:
The policy body supports the following top-level keys:
conditions: Optional. A list of named, reusable expressions that rules reference throughblock_when_any. See Condition properties.blocked_creation_rules: Optional. A list of rules that block matchingCREATEstatements. See Rule properties.
Condition properties¶
The conditions list is optional. Each condition gives a name to a SQL Boolean
expression, so you can define the expression once and reuse it across multiple
rules instead of repeating it in each rule’s block_when. A rule references
conditions by name in its block_when_any list.
Each entry in conditions supports these properties:
name: Required. The name that rules use to reference the condition inblock_when_any. Must be unique withinconditions.expression: Required. A SQL Boolean expression. See Blocking expressions.
Rule properties¶
Each entry in blocked_creation_rules supports these properties:
object_type: Required. The object type that the rule applies to, such asTABLE,TASK, orCORTEX_SEARCH_SERVICE, or theALLwildcard. Snowflake rejects an unsupported type when the policy is created or altered. See Supported object types.block_when: Optional. A SQL Boolean expression. The rule blocks the statement when the expression evaluates toTRUE. Can’t be an empty string.block_when_any: Optional. A list of condition names. The rule blocks the statement when any of the named conditions evaluates toTRUE. Must contain at least one name, and each name must match an entry inconditions.error_message: Optional. Text that Snowflake appends to the error for a blockedCREATE. See Custom error messages.
A rule can specify block_when or block_when_any, but not both. If a rule
specifies neither, it blocks every CREATE of its object_type. An ALL rule
must specify one of them.
An ALL rule applies to every supported object type, not to every object type
in Snowflake. For the list of supported types, see
Supported object types.
The expression in an ALL rule can use only the following properties:
TYPEREQUEST_OPERATIONIS_TEMPORARYIS_TRANSIENTDATABASESCHEMA
To use a property that applies only to specific object types, such as
WAREHOUSE on TASK, write a rule for that object type instead.
Supported object types¶
A rule’s object_type can name any of the following types, in either singular
or plural form (for example, both TABLE and TABLES are accepted):
| Category | Object types |
|---|---|
| Account-level | DATABASE |
| Database-level | SCHEMA |
| Schema-level | TABLE, ICEBERG_TABLE, DYNAMIC_TABLE, VIEW, STAGE, FILE_FORMAT, FUNCTION, PROCEDURE, SECRET, TASK, AGENT, CORTEX_SEARCH_SERVICE |
Each of these types has at least one object property that a blocking expression
can test. For the properties that apply to each type, see
Object properties. The ALL
wildcard covers every supported type.
To block every creation of other object types, list them in
BLOCKED_OBJECT_TYPES_FOR_CREATION. See Blockable object types.
Blocking expressions¶
This section applies to both a rule’s block_when expression and a
condition’s expression. Each is a SQL Boolean expression written as a quoted
string. Snowflake validates the expression when the policy is created or
altered.
Object properties¶
A blocking expression can refer to properties of the object that the CREATE
statement creates, such as the values that the statement sets. It can also
refer to properties of the request itself, such as the type of object. Refer to
a property in either of the following ways:
$<PROPERTY>: Resolves the property directly. The variable has the same type as the property. For example,$IS_TRANSIENTis a Boolean, so use it directly or compare it with an unquotedTRUEorFALSE(for example,$IS_TRANSIENTorNOT $IS_TRANSIENT).$SCHEMAis a string, so compare it with a string literal (for example,$SCHEMA = 'STAGING'). Using an unrecognized name, or a property that doesn’t apply to the rule’sobject_type, is a compilation error when the policy is created or altered.SYS_CONTEXT('SNOWFLAKE$REQUEST', 'GET_OBJECT_PROPERTY', '<property>'): The full form. Always returns a string, so Boolean comparisons require= 'TRUE'. A property that doesn’t apply to the rule’sobject_typereturnsNULLat runtime instead of causing an error when the policy is created.
For example, the following two rules are equivalent:
The following properties describe the request itself. They apply to every object type:
| Property | $ shorthand | Returns |
|---|---|---|
TYPE | $TYPE | The type of the object being created, using the same name as a rule’s object_type, for example TABLE, AGENT, or TASK. Useful in ALL rules and in shared conditions. |
REQUEST_OPERATION | $REQUEST_OPERATION | The kind of statement being evaluated. Always CREATE in blocked_creation_rules, including for CREATE OR ALTER. |
The following properties describe the object being created:
| Property | $ shorthand | Type | Returns |
|---|---|---|---|
IS_TEMPORARY | $IS_TEMPORARY | Boolean | TRUE for CREATE TEMPORARY ... of TABLE, VIEW, STAGE, FILE_FORMAT, FUNCTION, PROCEDURE, SECRET, AGENT. FALSE otherwise. |
IS_TRANSIENT | $IS_TRANSIENT | Boolean | TRUE for CREATE TRANSIENT ... of TABLE, ICEBERG_TABLE, DYNAMIC_TABLE, SCHEMA, DATABASE. FALSE otherwise. |
REQUEST_LOGGING | $REQUEST_LOGGING | Boolean | For CORTEX_SEARCH_SERVICE: TRUE when the statement sets REQUEST_LOGGING = TRUE. FALSE when it sets FALSE or omits the property. FALSE for other object types. |
WAREHOUSE | $WAREHOUSE | String | For TASK: the warehouse named in the request, or NULL if none (serverless task). NULL for other object types. |
EXTERNAL_VOLUME | $EXTERNAL_VOLUME | String | For ICEBERG_TABLE: the external volume resolved for the request (table, schema, database, or account level), or NULL if none. NULL for other object types. |
DATABASE | $DATABASE | String | The name of the database containing the object being created. NULL for account-level object types. |
SCHEMA | $SCHEMA | String | The name of the schema containing the object being created. NULL for account-level and database-level object types (those not contained in a schema, including SCHEMA itself). |
Boolean properties are FALSE for object types that don’t support that
creation option, so a single rule applied across mixed object types behaves
predictably. For example, $IS_TRANSIENT is FALSE for STAGE.
Properties on CREATE and CREATE OR ALTER¶
A blocking expression can read the properties that the statement explicitly sets. It can also read properties that the statement doesn’t set but that have a default or a resolved value for the object type. Those properties report that value.
- Boolean properties are always present. If the statement omits one, the value
is that property’s default.
IS_OBJECT_PROPERTY_PRESENTreturnsTRUE. - Other properties that have a default or a resolved value for the object type,
such as
EXTERNAL_VOLUMEonICEBERG_TABLE, are present at that value when the statement omits them.IS_OBJECT_PROPERTY_PRESENTreturnsTRUE. - Properties without a default are
NULLwhen the statement omits them or sets them toNULL.IS_OBJECT_PROPERTY_PRESENTreturnsTRUEonly when the statement supplies a value. TYPE,REQUEST_OPERATION,DATABASE, andSCHEMAare always present when they apply to the object type.
Safely handling missing properties¶
A string property can be NULL, for example WAREHOUSE on a serverless task.
A comparison against NULL is itself NULL, and a rule whose expression
evaluates to NULL blocks the statement. For example,
$WAREHOUSE NOT IN ('CORP_M', 'CORP_XL') is NULL for a serverless task, so
the rule blocks every serverless task, even if you intended to allow them.
To write a rule that behaves predictably for every statement, use one of the following approaches instead of comparing the property directly.
Using NULL checks¶
Test whether a property is NULL before comparing its value. An IS NOT NULL
check makes the expression FALSE instead of NULL when the property has no
value.
The following rule requires that a task’s warehouse, when set, is CORP_M or
CORP_XL. A task without a warehouse is allowed:
The rule handles each statement as follows:
CREATE TASKwithWAREHOUSE = CORP_MorWAREHOUSE = CORP_XL: allowed.CREATE TASKwith a different warehouse: blocked.CREATE TASKwith no warehouse (a serverless task): allowed.
Using IS_ OBJECT_ PROPERTY_ SET_ TO¶
Use IS_OBJECT_PROPERTY_SET_TO to require that a property has a specific value
whenever a statement supplies it. The function returns TRUE when the
statement sets the property to the value, or when the statement doesn’t supply
the property at all. The value is compared case-insensitively, and an explicit
NULL doesn’t match any value. An omitted Boolean is present at its default,
so the function compares that default. The function returns NULL for an
unrecognized property name.
The following rule requires that a task that names a warehouse uses
CORP_M:
The rule handles each statement as follows:
CREATE TASKwithWAREHOUSE = CORP_M: allowed.CREATE TASKwith a different warehouse: blocked.CREATE TASKwith no warehouse (a serverless task): allowed.
Using IS_ OBJECT_ PROPERTY_ PRESENT¶
Use IS_OBJECT_PROPERTY_PRESENT to block a statement based on whether a
property is present, regardless of its value. The function returns TRUE when
the property is present and FALSE when it isn’t. For the properties that
count as present, see
Properties on CREATE and CREATE OR ALTER.
The function returns NULL for an unrecognized property name.
The following rule allows only serverless tasks:
The rule handles each statement as follows:
CREATE TASKwith anyWAREHOUSE: blocked.CREATE TASKwith no warehouse (a serverless task): allowed.
Each of these expressions evaluates to TRUE or FALSE for every statement,
so a missing property never causes it to block the statement.
Validation rules¶
Snowflake rejects the following expressions when the policy is created or altered:
- Expressions that don’t evaluate to a Boolean type (for example, a numeric literal or a string literal).
- Expressions that reference tables or other database objects (for example,
(SELECT COUNT(*) FROM t) > 0). - Expressions that call functions with side effects (for example,
SYSTEM$RUN_QUERY_SYNC). - Expressions that call functions that must run in a warehouse.
- Expressions that call a function that doesn’t exist.
- Expressions that use
$<NAME>where<NAME>isn’t a recognized object property, or where the property doesn’t apply to the rule’sobject_type(for example,$WAREHOUSEin aTABLErule).
Attention
An expression that compares a property can evaluate to NULL at runtime, and
a rule whose expression evaluates to NULL blocks the statement. Validation
doesn’t catch the following cases:
- The property has no value for the statement, for example
WAREHOUSEon a serverless task. - The expression uses
SYS_CONTEXTto read a property that doesn’t apply to the rule’sobject_type, or a misspelled property name. - The statement explicitly sets the property to
NULL.
To avoid these failures, check for NULL before comparing a property’s value.
See Using NULL checks.
Custom error messages¶
When a rule blocks the statement, the statement is denied. By default, the error names the object type and points to the effective feature policy, for example:
Add an error_message to a rule to tell the user why the statement was blocked
and what to do instead:
When this policy is applied to the account, a CREATE TRANSIENT TABLE statement
fails with an error that includes the rule’s text after Your policy::
The following rules apply to error_message:
- The value is trimmed of leading and trailing whitespace. The trimmed text must be 1 to 512 characters long.
- The value must be a single line. Newlines, tabs, and other control characters aren’t allowed.
- The sequence
${, followed later by}, is reserved and isn’t allowed. - Snowflake validates the value when the policy is created or altered. An invalid value causes the statement to fail.
Snowflake shows the message from the first rule in the list that blocks the
statement. If a statement is blocked because its object type is listed in
BLOCKED_OBJECT_TYPES_FOR_CREATION, Snowflake shows the generic error without any
rule’s error_message, even if a rule for the same object type also matches.
Examples¶
The following examples assume the feature policy is attached to an account, an application, or a database after creation. For attachment syntax, see Apply a feature policy.
Each example includes an error_message. Adding one to every rule is
recommended, so that users who are blocked understand why and know what to do
instead. For more information, see
Custom error messages.
Block all temporary tables¶
Block all transient tables¶
Transient tables don’t carry the same Time Travel and Fail-safe protections as
permanent tables. A policy that requires only permanent tables can block
CREATE TRANSIENT TABLE statements:
To block both temporary and transient tables in one rule, see the example in Custom error messages.
Block transient and temporary objects across multiple object types¶
A single named condition can be reused across object types, including object
types that don’t support TRANSIENT (such as STAGE, VIEW, FUNCTION,
PROCEDURE). For those types, $IS_TRANSIENT is FALSE, so the rule fires
only on temporary creations:
Block serverless tasks¶
Serverless tasks are tasks created without a WAREHOUSE. The following policy
permits warehouse-attached tasks but blocks serverless ones:
Require request logging for Cortex Search Services¶
The following policy blocks creating a Cortex Search Service unless the statement
sets REQUEST_LOGGING = TRUE. Because REQUEST_LOGGING defaults to FALSE, a
statement that omits the property is also blocked. For more information about
request logging, see
Enable request logging.
This rule applies only when a service is created. It doesn’t block an
ALTER CORTEX SEARCH SERVICE statement that later disables request logging.
Block a property across every object type with ALL¶
Use the ALL wildcard to apply one rule to every supported object type without
listing each one. Because Boolean properties such as $IS_TEMPORARY are FALSE
for object types that can’t be temporary, the following policy blocks every
temporary creation across all types and permits everything else:
To exempt specific types from an ALL rule, test $TYPE. The following policy
blocks every temporary creation except temporary tables:
Restrict object creation to a specific schema¶
Use the $SCHEMA variable to block creations outside an approved schema.
A schema-level object such as a table always carries a SCHEMA value, so the
comparison never evaluates to NULL:
The $SCHEMA variable returns the schema name as stored in the catalog (uppercase
unless the schema was created with a quoted, case-sensitive identifier). The
companion $DATABASE variable restricts by containing database in the same way.
Block every table¶
Omit block_when to block every creation of an object type, regardless of
request attributes:
Unlike listing TABLE in BLOCKED_OBJECT_TYPES_FOR_CREATION, this rule shows
its error_message when it blocks a statement.
Reuse a condition across rules¶
Combine type-level blocks and rules¶
BLOCKED_OBJECT_TYPES_FOR_CREATION and blocked_creation_rules can be used
together in a single policy. Listing an object type in
BLOCKED_OBJECT_TYPES_FOR_CREATION blocks every creation of that type
regardless of any rule. Rules covering different object types are evaluated
independently. The following policy blocks every warehouse creation and also
blocks temporary tables:
Modify or remove a policy body¶
Use ALTER FEATURE POLICY to set, replace, or clear the body of an existing policy.
To replace the body, use the AS clause, with or without other SET clauses:
To remove the body but keep any BLOCKED_OBJECT_TYPES_FOR_CREATION clause:
To inspect the current body, use
DESCRIBE FEATURE POLICY. The body appears as the
policy_definition property in the result.
Delete a feature policy¶
Use the DROP FEATURE POLICY command:
A feature policy can’t be dropped if it’s currently applied to an object. Unapply it first using ALTER ACCOUNT, ALTER APPLICATION, or ALTER DATABASE, then drop it.
View feature policies¶
To list the feature policies in the account that you have access to:
To list the feature policies applied to a specific application:
To list the feature policies applied to a specific database:
To view the details of a specific feature policy:
Identify feature policy references¶
The POLICY_REFERENCES Information Schema table function can identify feature policy references. There are two different syntax options:
-
Return a row for each object that has the specified feature policy assigned to it:
-
Return each feature policy assigned to the account:
Replication considerations¶
Feature policy references at the account level are replicated when the database containing the
policy is included in the replication group, for example by setting
ALLOWED_DATABASES = feature_policy_db.
If the account has already been replicated to a target account, do the following:
- Update the replication or failover group in the source account to include the databases and object types required to replicate the feature policy.
- Execute a refresh operation to update the target account.
Note
The feature policy must be in the same account as the account-level policy assignment.
If you don’t include the policy database in the replication group, Snowflake creates a dangling reference in the target account. The fully qualified policy name points to the source account’s database, which doesn’t exist in the target account, so the policy isn’t enforced there.
For more information, see Replication considerations.