向使用者请求引用和对象级权限¶
本主题介绍提供商如何配置 Snowflake Native App,以请求访问使用者账户中存在于应用程序外部的对象。
关于引用¶
在某些情况下,已安装的 Snowflake Native App 需要访问使用者账户中存在于应用程序外部的现有对象。例如,应用程序可能需要访问使用者数据库中的现有表。
在这种情况下,使用者仅向应用程序授予对象的访问权限并不够,因为应用程序无法确定使用者账户中的架构和对象的名称。
为了让应用程序访问应用程序外部的现有对象,Snowflake Native App Framework 使用引用,使客户能够指定对象的名称和架构,并启用对该对象的访问权限。
在使用者账户中定义引用的工作流程¶
要请求引用和对象级权限,提供商需在开发和发布 Snowflake Native App 时执行以下操作:
在安装脚本中添加存储过程,以处理清单文件中定义的每个引用的回调。
安装 Snowflake Native App 之后,使用者执行以下操作:
查看 Snowflake Native App 所需的引用。
通过调用 SYSTEM$REFERENCE 系统函数来创建引用。
运行回调存储过程,传递引用的 ID。
使用者运行回调存储过程后, Snowflake Native App 可以访问请求的对象。
此工作流程概述使用者手动创建引用的过程。请参阅 创建用户界面以请求权限和引用,详细了解如何创建用户界面,以允许使用者使用 Snowsight 创建引用并授予权限。
引用中可以包含的对象类型和权限¶
下表列出了引用可以包含的对象类型以及每个对象允许的权限:
对象类型 |
允许的权限 |
---|---|
TABLE |
SELECT、INSERT、UPDATE、DELETE、TRUNCATE、REFERENCES |
VIEW |
SELECT、REFERENCES |
EXTERNAL TABLE |
SELECT、REFERENCES |
FUNCTION |
USAGE |
PROCEDURE |
USAGE |
WAREHOUSE |
MODIFY、MONITOR、USAGE、OPERATE |
API INTEGRATION |
USAGE |
EXTERNAL ACCESS INTEGRATION |
USAGE |
SECRET |
USAGE、READ |
在清单文件中定义引用¶
以下示例演示如何在 manifest.yml
文件中为 APPLICATION 对象外部存在的使用者账户中的表定义引用:
references:
- consumer_table:
label: "Consumer table"
description: "A table in the consumer account that exists outside the APPLICATION object."
privileges:
- INSERT
- SELECT
object_type: TABLE
multi_valued: false
register_callback: config.register_single_reference
此示例定义了名为 consumer_table
的引用,它需要具有使用者账户中表的 INSERT 和 SELECT 权限。register_callback
属性指定用于将使用者表绑定到此引用定义的存储过程。
使用 multi_valued
将多个使用者对象绑定到同一引用。当指定此属性时,将对具有单个值引用的对象执行相同的操作。该属性还可以用于具有多值引用的对象。请参阅 支持的引用函数 以了解有关 Snowflake Native App Framework 引用操作的更多信息。
删除引用定义¶
备注
Snowflake 建议,在新版本的应用程序中,不要删除清单文件内的引用定义。如果需要删除定义的引用,请更新同一版本中使用已移除的引用的任何代码,并在 README 文件中通知使用者。
如果某个应用程序定义了引用,那么稍后会从该应用程序的后续版本中删除引用定义,调用依然使用已删除引用的任何函数或过程会导致使用者出错。例如,应用程序 my_app
版本 V1 的清单文件包括 REF_TO_TABLE 的引用定义,以及使用 REF_TO_TABLE 表引用创建 VIEW_SELECT_FROM_DEFINED_REF 视图的 CREATE_VIEW_FROM_TABLE 存储过程。
在 my_app
V2 版本中,REF_TO_TABLE 的引用定义已从清单文件中移除。当使用者将其安装的应用程序 my_app
升级到版本 V2 时,调用 CREATE_VIEW_FROM_TABLE 过程会导致以下错误:
Reference definition '<REF_DEF_NAME>' cannot be found in the current version of the application '<APP_NAME>'
为引用创建回调存储过程¶
在 manifest.yml
文件中定义引用后,提供商必须向安装脚本添加存储过程,以注册引用的回调。
以下示例演示用于处理 在清单文件中定义引用 中所示引用的回调的存储过程:
CREATE APPLICATION ROLE app_admin;
CREATE OR ALTER VERSIONED SCHEMA config;
GRANT USAGE ON SCHEMA config TO APPLICATION ROLE app_admin;
CREATE PROCEDURE CONFIG.REGISTER_SINGLE_REFERENCE(ref_name STRING, operation STRING, ref_or_alias STRING)
RETURNS STRING
LANGUAGE SQL
AS $$
BEGIN
CASE (operation)
WHEN 'ADD' THEN
SELECT SYSTEM$SET_REFERENCE(:ref_name, :ref_or_alias);
WHEN 'REMOVE' THEN
SELECT SYSTEM$REMOVE_REFERENCE(:ref_name, :ref_or_alias);
WHEN 'CLEAR' THEN
SELECT SYSTEM$REMOVE_ALL_REFERENCES(:ref_name);
ELSE
RETURN 'unknown operation: ' || operation;
END CASE;
RETURN NULL;
END;
$$;
GRANT USAGE ON PROCEDURE CONFIG.REGISTER_SINGLE_REFERENCE(STRING, STRING, STRING)
TO APPLICATION ROLE app_admin;
此示例创建名为 REGISTER_SINGLE_REFERENCE
的存储过程,用于调用系统函数,对作为实参传递给存储过程的引用执行特定操作。
备注
由于该存储过程使用 SYSTEM$SET_REFERENCE 系统函数,因此存储过程仅对描述中具有单个值的引用发挥作用。要将引用与多个值关联,请使用 SYSTEM$ADD_REFERENCE 系统函数。
创建用于请求对象配置的回调存储过程¶
对于某些对象类型,提供商必须向安装脚本添加存储过程以提供其他配置。当使用者允许引用使用 Snowsight 时,将使用此回调。
以下示例演示如何为 在清单文件中定义引用 中所示的引用定义配置回调存储过程:
CREATE OR REPLACE CONFIG.GET_CONFIGURATION_FOR_REFERENCE(ref_name STRING)
RETURNS STRING
LANGUAGE SQL
AS
$$
BEGIN
CASE (ref_name)
WHEN 'CONSUMER_EXTERNAL_ACCESS' THEN
RETURN '{
"type": "CONFIGURATION",
"payload":{
"host_ports":["google.com"],
"allowed_secrets" : "LIST",
"secret_references":["CONSUMER_SECRET"]}}';
WHEN 'CONSUMER_SECRET' THEN
RETURN '{
"type": "CONFIGURATION",
"payload":{
"type" : "OAUTH2",
"security_integration": {
"oauth_scopes": ["https://www.googleapis.com/auth/analytics.readonly"],
"oauth_token_endpoint": "https://oauth2.googleapis.com/token",
"oauth_authorization_endpoint":
"https://accounts.google.com/o/oauth2/auth"}}}';
END CASE;
RETURN '';
END;
$$;
GRANT USAGE ON PROCEDURE CONFIG.GET_CONFIGURATION_FOR_REFERENCE(STRING)
TO APPLICATION ROLE app_admin;
此示例创建名为 GET_CONFIGURATION_FOR_REFERENCE
的存储过程,该存储过程返回 JSON 格式的配置,用于构建类型为 EXTERNAL ACCESS INTEGRATION 的引用或 SECRET 引用。Switch 语句中的条目应该映射到 manifest.yml
文件中的引用名称。
备注
类型为 EXTERNAL ACCESS INTEGRATION 和 SECRET 的引用需要使用此回调函数。它只适用于这些类型的引用。
查看应用程序中定义的引用¶
当提供商在 manifest.yml
文件中定义引用时,它们将作为已安装的 Snowflake Native App 包含在内。
要查看为 Snowflake Native App 定义的引用,请运行 SHOW REFERENCES 命令,如以下示例所示:
SHOW REFERENCES IN APPLICATION hello_snowflake_app;
将对象绑定到应用程序¶
在查看 Snowflake Native App 的引用定义后,使用者可以运行 SYSTEM$REFERENCE 系统函数来创建引用,如以下示例所示:
SELECT SYSTEM$REFERENCE('table', 'db1.schema1.table1', 'persistent', 'select', 'insert');
此命令会返回引用的标识符。使用者可以将标识符传递给引用的回调存储过程,如以下示例所示:
CALL app.config.register_single_reference(
'consumer_table' , 'ADD', SYSTEM$REFERENCE('TABLE', 'db1.schema1.table1', 'PERSISTENT', 'SELECT', 'INSERT'));
在本例中,consumer_table
是 manifest.yml
文件中定义的引用的名称。使用者运行关联引用的存储过程后,Snowflake Native App 可访问使用者账户中的表。
:ref:` 上一部分 <label-native_apps_reference_create_callback>` 中的回调存储过程调用 SYSTEM$SET_REFERENCE 系统函数,如以下示例所示:
SELECT SYSTEM$SET_REFERENCE(:ref_name, :ref_or_alias);
有关与引用相关的其他系统功能,请参阅 支持的引用函数。
使用引用时的注意事项¶
Snowflake 建议您不要跨版本修改引用定义。要在新版本中更新引用定义(例如,要将权限更改为 SELECT、SELECT 中的 INSERT),您必须定义具有不同名称的新引用定义。已更新的 Snowflake Native App 可以在新版本的应用程序中使用此新引用。
要在另一个对象中嵌入引用(例如,将引用分配给变量),该引用必须已绑定到使用者账户中的对象。例如,除非您首先将引用绑定到使用者仓库,否则无法创建任务。
在 Snowflake Native App 中使用引用的示例¶
以下部分提供在不同上下文中使用引用的示例。
备注
以下示例中的 reference()
函数只能在 APPLICATION 对象内的存储过程中调用。
使用引用运行查询¶
以下示例演示如何使用引用运行查询:
SELECT * FROM reference('consumer_table');
SELECT reference('encrypt_func')(t.c1) FROM consumer_table t;
使用引用调用存储过程¶
以下示例演示如何使用引用调用存储过程:
CALL reference('consumer_proc')(11, 'hello world');
使用引用运行 DML 命令¶
以下示例演示如何使用引用修改表中的数据:
INSERT INTO reference('data_export')(C1, C2)
SELECT T.C1, T.C2 FROM reference('other_table')
COPY INTO reference('the_table') ...
使用引用运行 DESCRIBE 命令¶
以下示例演示如何使用引用运行 DESCRIBE 操作:
DESCRIBE TABLE reference('the_table')
在任务中使用引用¶
CREATE TASK app_task
WAREHOUSE = reference('consumer_warehouse')
...;
ALTER TASK app_task SET WAREHOUSE = reference('consumer_warehouse');
在视图定义中使用引用¶
CREATE VIEW app_view
AS SELECT reference('function')(T.C1) FROM reference('table') AS T;
在函数正文中使用引用¶
CREATE FUNCTION app.func(x INT)
RETURNS STRING
AS $$ select reference('consumer_func')(x) $$;
在外部函数中使用引用¶
CREATE EXTERNAL FUNCTION app.func(x INT)
RETURNS STRING
...
API_INTEGRATION = reference('app_integration');
在函数或过程中使用引用¶
CREATE FUNCTION app.func(x INT)
RETURNS STRING
...
EXTERNAL_ACCESS_INTEGRATIONS = (reference('consumer_external_access_integration'), ...);
SECRETS = ('cred1' = reference('consumer_secret'), ...);
备注
如果函数或存储过程使用对外部访问集成或密钥的引用,则使用者不能直接调用这些函数或存储过程。
但是,该应用程序的其他组件(包括 Streamlit 应用程序、任务以及其他函数和存储过程)可以使用这些引用。
为了允许使用者调用使用对外部访问集成或密钥的引用的函数或存储过程,提供商可以执行以下操作:
在安装脚本中,创建使用引用的函数或存储过程,例如:
function_with_eai_secret_reference
,如以下示例所示:CREATE FUNCTION app_schema.function_with_eai_secret_reference(arg1 STRING) RETURNS string LANGUAGE python RUNTIME_VERSION = 3.8 HANDLER = 'my_handler' EXTERNAL_ACCESS_INTEGRATIONS = (reference('eai_ref')) PACKAGES = ('snowflake-snowpark-python','requests') SECRETS = ('cred' = reference('secret_ref') ) ... AS $$
在安装脚本中,创建一个名为
my_wrapper_procedure
的包装器存储过程。CREATE OR REPLACE PROCEDURE app_schema.my_wrapper_procedure(arg1 STRING) RETURNS STRING LANGUAGE SQL AS $$ BEGIN ... END; $$;
备注
包装器必须是存储过程,而不是函数。
在
my_wrapper_procedure
中,添加对function_with_eai_secret_reference
的调用,如以下示例所示:BEGIN RETURN app_schema.function_with_eai_secret_reference(arg1); END;
向应用程序角色授予
my_wrapper_procedure
,以允许使用者调用该过程,如以下示例所示:GRANT USAGE ON PROCEDURE app_schema.my_wrapper_procedure(STRING) TO APPLICATION ROLE app_role;
安装该应用程序后,使用者可以调用 my_wrapper_procedure
,然后该存储过程再调用 function_with_eai_secret_reference
。
在策略中使用引用¶
CREATE ROW ACCESS POLICY app_policy
AS (sales_region varchar) RETURNS BOOLEAN ->
'sales_executive_role' = reference('get_sales_team')
or exists (
select 1 from reference('sales_table')
where sales_manager = reference('get_sales_team')()
and region = sales_region
);
配置回调响应的 JSON 格式¶
配置回调函数返回一个 JSON 格式的响应。外部访问集成和密钥引用返回的 JSON 格式不同。
外部访问集成的 JSON 格式¶
对于 EXTERNAL ACCESS INTEGRATION 引用,JSON 响应的预期结构是:
{
"type": "CONFIGURATION",
"payload": {
"host_ports": ["host_port_1", ...],
"allowed_secrets": "NONE|ALL|LIST",
"secret_references": ["ref_name_1", ...]
}
}
host_ports
字符串数组。每个值都必须是有效的域。
或者,它还可以包括一个端口。有效端口范围为 1 至 65535(含 1 和 65535)。如果未指定端口,则默认为 443。如果外部网络位置支持动态端口,则需要指定所有可能的端口。
要允许访问所有端口,请将端口指定为 0,例如:
example.com:0
。
这些值用于为外部访问集成创建出口网络规则。有关更多信息,请参阅 CREATE NETWORK RULE。
allowed_secrets
指定 EXTERNAL ACCESS INTEGRATION 引用允许的密钥。有效值为:
NONE
:不允许密钥。ALL
:允许任何现有的密钥。LIST
:允许在secret_references
属性中指定的一组特定密钥。
allowed_secrets
的值用于创建外部访问集成。有关更多信息,请参阅 CREATE EXTERNAL ACCESS INTEGRATION。secret_references
:指定外部访问集成允许的密钥引用的列表。
此处指定的值必须与清单中定义的密钥引用相同。
此属性仅在
allowed_secrets
设置为LIST
时适用。在此上下文中,secret_references
为必需的。
密钥引用的 JSON 格式¶
对于密钥引用,JSON 响应的预期结构为:
{
"type": "CONFIGURATION",
"payload": {
"type": "OAUTH2",
"security_integration": {
"oauth_scopes": ["scope_1", "scope_2"],
"oauth_token_endpoint" : "token_endpoint",
"oauth_authorization_endpoint" : "auth_endpoint"
}
}
}
payload.type
密钥的类型。有效值为:
OAUTH2
:指定要用于 OAuth2 授予流程的密钥。有关更多信息,请参阅 CREATE SECRET。
payload.security_integration
指定为 OAuth 密钥配置 API 身份验证 所需的值。
JSON 格式错误响应¶
如果出现错误或引用尚未准备好进行配置,则错误响应的预期结构为:
{
"type": "ERROR",
"payload":{
"message": "The reference is not available for configuration ..."
}
}
message
:Snowsight 中显示的应用程序的错误消息。
支持的引用函数¶
Snowflake Native App Framework 支持以下函数执行与引用相关的不同操作: