适用于:
Databricks SQL
Databricks Runtime
Azure Databricks运行 SQL 语句时,它会跟踪两个不同的用户:
- 会话用户 — 连接到Azure Databricks并发出声明的用户。 会话用户在 SQL 连接的生存期内是固定的。 即使在语句进入视图、SQL UDF 或存储过程时,它也不会更改。
-
已授权用户 — 在当前正在执行的语句读取或写入对象时检查其特权的用户。 授权用户可以随着执行交叉进入视图正文、SQL UDF 正文或
SQL SECURITY DEFINER过程正文而更改。
session_user函数返回会话用户。
Warning
current_user和用户函数是也返回会话用户的别名,而不是授权用户。 在标准 SQL 中,CURRENT_USER返回授权用户;在Azure Databricks它不返回。 使用 session_user 显式引用会话用户。
授权用户的发展方式
每次调用视图、SQL UDF 或存储过程都会在调用堆栈上推送一个新条目。 语句的授权用户由修复所有者的最顶层堆栈条目确定:
| 对象 | 正文中的授权用户 |
|---|---|
| 查看 | 视图所有者 |
| SQL UDF | 函数所有者 |
CREATE PROCEDURE ... SQL SECURITY DEFINER |
过程所有者(定义者) |
CREATE PROCEDURE ... SQL SECURITY INVOKER |
调用语句的授权用户(继承) |
视图、SQL UDF 和 SQL SECURITY DEFINER 过程将授权的用户设置为其主体中的所有语句的所有者。 过程 SQL SECURITY INVOKER 从其调用方继承授权用户。
当正文完成执行和控制返回到调用方时,授权用户会弹出回呼叫站点上的任何操作。
相比之下,会话用户不会在单个连接期间更改。
SQL SECURITY DEFINER在过程正文中,session_user()仍返回发出原始语句的用户。
在每个层检查的权限
Azure Databricks在每个执行层检查针对授权用户的权限:
- 会话用户必须保留
EXECUTE顶级过程或函数以及SELECT顶级视图。 会话用户还必须具有USE CATALOG父容器和USE SCHEMA父容器。 -
SQL SECURITY INVOKER在过程正文中,所有语句都使用会话用户的权限,包括对其他例程的任何嵌套EXECUTE调用。 - 在
SQL SECURITY DEFINER过程正文、视图正文或 SQL UDF 正文中,所有语句都使用所有者的权限。 会话用户只需要调用外部例程的权限,而不需要对正文引用的对象具有特权。
示例
此示例将视图、SQL UDF 和不同用户拥有的存储过程链接在一起。 每个层从下面的层读取,因此授权会遍历整个堆栈。 该示例使用三个用户(Athos、Porthos 和 Aramis),并跟踪仅有权访问顶级过程的 Aramis 调用链时会发生什么情况。
Setup
Athos 创建一个双列表,并授予 Porthos 读取访问权限:
-- Run as Athos.
> CREATE TABLE t(a INT, b INT);
> INSERT INTO t VALUES (1, 10), (2, 20), (3, 30);
> GRANT SELECT ON TABLE t TO `[email protected]`;
Porthos 基于 Athos 表创建视图,并授予 Athos 对视图的读取访问权限:
-- Run as Porthos.
> CREATE VIEW v_p AS
SELECT a, b * 100 AS b100 FROM t;
> GRANT SELECT ON VIEW v_p TO `[email protected]`;
Athos 创建从 Porthos 视图读取的 SQL UDF,并向其授予 Porthos EXECUTE :
-- Run as Athos.
> CREATE FUNCTION f_a(p INT) RETURNS INT
RETURN (SELECT b100 FROM v_p WHERE a = p);
> GRANT EXECUTE ON FUNCTION f_a TO `[email protected]`;
Porthos 创建一个 SQL UDF,用于聚合 Athos 的 UDF 的结果,以及公开 SQL SECURITY DEFINER 结果的过程:
-- Run as Porthos.
> CREATE FUNCTION f_p() RETURNS INT
RETURN f_a(1) + f_a(2) + f_a(3);
> CREATE PROCEDURE p_def()
LANGUAGE SQL
SQL SECURITY DEFINER
AS BEGIN
SELECT f_p();
END;
Athos 创建调用 SQL SECURITY INVOKER Porthos 过程的过程:
-- Run as Athos.
> CREATE PROCEDURE p_inv()
LANGUAGE SQL
SQL SECURITY INVOKER
AS BEGIN
CALL p_def();
END;
最后,阿托斯和波托斯都向阿拉米斯授予他需要调用链的东西。 因为它是p_inv一个SQL SECURITY INVOKER过程,它的正文作为调用它的用户运行(Aramis),因此阿拉米必须独立拥有EXECUTEp_def:
-- Run as Athos.
> GRANT EXECUTE ON PROCEDURE p_inv TO `[email protected]`;
-- Run as Porthos.
> GRANT EXECUTE ON PROCEDURE p_def TO `[email protected]`;
阿拉米斯没有特权,f_av_p也没有f_p特权t。
Aramis 调用链
Aramis 问题:
-- Run as Aramis.
> CALL p_inv();
调用链按如下所示展开,每个箭头交叉到一个新正文中:
Aramis's session
│
│ CALL
▼
p_inv() (Athos, SQL SECURITY INVOKER)
│
│ CALL
▼
p_def() (Porthos, SQL SECURITY DEFINER)
│
│ SELECT
▼
f_p() (Porthos's SQL UDF)
│
│ invokes
▼
f_a(p) (Athos's SQL UDF)
│
│ SELECT
▼
v_p (Porthos's view)
│
│ SELECT
▼
t (Athos's table)
下表演练执行语句。
| 步骤 | 声明 | 运行位置 | 授权用户 | session_user() |
|---|---|---|---|---|
| 1 | CALL p_inv() |
阿拉米斯的会话 | 阿拉米斯 | 阿拉米斯 |
| 2 | CALL p_def() |
p_inv (SQL SECURITY INVOKER) |
阿拉米斯 (继承自调用方) | 阿拉米斯 |
| 3 | SELECT f_p() |
p_def (SQL SECURITY DEFINER) |
Porthos (过程所有者) | 阿拉米斯 |
| 4 | RETURN f_a(1) + f_a(2) + f_a(3) |
SQL UDF 正文 f_p |
Porthos (函数所有者) | 阿拉米斯 |
| 5 | RETURN (SELECT b100 FROM v_p WHERE a = p) |
SQL UDF 正文 f_a |
Athos (函数所有者) | 阿拉米斯 |
| 6 | SELECT a, b * 100 AS b100 FROM t |
视图正文 v_p |
Porthos (视图所有者) | 阿拉米斯 |
执行展开时,授权用户逐层弹出层,直到控制在步骤 1 返回到 Aramis 的会话。