授权用户和会话用户

适用于:勾选“是” 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_invSQL SECURITY INVOKER 阿拉米斯 (继承自调用方) 阿拉米斯
3 SELECT f_p() p_defSQL 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 的会话。