Utilisateur autorisé et utilisateur de session

S’applique à :case cochée oui Databricks SQL case cochée oui Databricks Runtime

Quand Azure Databricks exécute une instruction SQL, elle effectue le suivi de deux utilisateurs distincts :

  • Utilisateur de session : utilisateur connecté à Azure Databricks et qui a émis l’instruction. L’utilisateur de session est fixe pour la durée de vie de la connexion SQL. Elle ne change pas lorsqu’une instruction est en cours d’exécution, même lorsque l’instruction atteint des vues, des fonctions définies par l’utilisateur SQL ou des procédures stockées.
  • Utilisateur autorisé : l’utilisateur dont les privilèges sont vérifiés lorsque l’instruction en cours d’exécution lit ou écrit des objets. L’utilisateur autorisé peut changer en tant qu’exécution croisée dans un corps d’affichage, un corps UDF SQL ou un SQL SECURITY DEFINER corps de procédure.

La fonction session_user retourne l’utilisateur de session.

Warning

Les fonctions current_user et utilisateur sont des alias qui retournent également l’utilisateur de session, et non l’utilisateur autorisé. Dans SQL standard, CURRENT_USER retourne l’utilisateur autorisé ; dans Azure Databricks ce n’est pas le cas. Utilisez session_user pour faire référence explicitement à l’utilisateur de session.

Évolution de l’utilisateur autorisé

Chaque appel d’une vue, d’une fonction UDF SQL ou d’une procédure stockée envoie (push) une nouvelle entrée sur la pile des appels. L’utilisateur autorisé pour une instruction est déterminé par l’entrée de pile la plus haute qui corrige un propriétaire :

Object Utilisateur autorisé à l’intérieur du corps
Affichage Propriétaire de l’affichage
SQL UDF Propriétaire de la fonction
CREATE PROCEDURE ... SQL SECURITY DEFINER Propriétaire de la procédure (definer)
CREATE PROCEDURE ... SQL SECURITY INVOKER Utilisateur autorisé de l’instruction appelante (héritée)

Les vues, les fonctions définies par l’utilisateur SQL et SQL SECURITY DEFINER les procédures définissent l’utilisateur autorisé sur son propriétaire pour toutes les instructions du corps. Une SQL SECURITY INVOKER procédure hérite de l’utilisateur autorisé de son appelant.

Lorsqu’un corps termine l’exécution et le contrôle retourne à l’appelant, l’utilisateur autorisé revient à ce qu’il était sur le site d’appel.

L’utilisateur de session, en revanche, ne change jamais pendant une seule connexion. Dans un corps de SQL SECURITY DEFINER procédure, session_user() retourne toujours l’utilisateur qui a émis l’instruction d’origine.

Privilèges vérifiés à chaque couche

Azure Databricks vérifie les privilèges par rapport à l’utilisateur autorisé à chaque couche d’exécution :

  • L’utilisateur de session doit contenir EXECUTE la procédure ou la fonction de niveau supérieur et SELECT la vue de niveau supérieur. L’utilisateur de session doit également avoir USE CATALOG et USE SCHEMA sur les conteneurs parents.
  • Dans un corps de SQL SECURITY INVOKER procédure, toutes les instructions utilisent les privilèges de l’utilisateur de session, y compris les appels imbriqués EXECUTE à d’autres routines.
  • À l’intérieur d’un corps de procédure, d’un SQL SECURITY DEFINER corps d’affichage ou d’un corps UDF SQL, toutes les instructions utilisent les privilèges du propriétaire. L’utilisateur de session a uniquement besoin du privilège d’appeler la routine externe, et non des privilèges sur les objets auxquels le corps fait référence.

Example

Cet exemple montre comment chaîner des vues, des fonctions définies par l’utilisateur SQL et des procédures stockées appartenant à différents utilisateurs. Chaque couche lit à partir de la couche ci-dessous, de sorte que l’autorisation traverse la pile complète. L’exemple utilise trois utilisateurs (Athos, Porthos et Aramis) et trace ce qui se passe quand Aramis, qui a accès uniquement aux procédures de niveau supérieur, appelle la chaîne.

Paramétrage

Athos crée une table à deux colonnes et accorde l’accès en lecture à 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 `porthos@musketeers.fr`;

Porthos crée une vue sur la table d’Athos et accorde à Athos l’accès en lecture sur la vue :

-- Run as Porthos.
> CREATE VIEW v_p AS
    SELECT a, b * 100 AS b100 FROM t;

> GRANT SELECT ON VIEW v_p TO `athos@musketeers.fr`;

Athos crée une fonction UDF SQL qui lit à partir de l’affichage de Porthos et lui accorde 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 `porthos@musketeers.fr`;

Porthos crée une fonction UDF SQL qui agrège les résultats de l’UDF d’Athos et une SQL SECURITY DEFINER procédure qui expose le résultat :

-- 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 crée une SQL SECURITY INVOKER procédure qui appelle la procédure de Porthos :

-- Run as Athos.
> CREATE PROCEDURE p_inv()
    LANGUAGE SQL
    SQL SECURITY INVOKER
    AS BEGIN
      CALL p_def();
    END;

Enfin, Athos et Porthos accordent à Aramis ce qu’il doit appeler la chaîne. Étant donné qu’il p_inv s’agit d’une SQL SECURITY INVOKER procédure, son corps s’exécute en tant qu’utilisateur qui l’a appelé (Aramis), et donc Aramis doit disposer EXECUTE indépendamment des éléments suivants p_def:

-- Run as Athos.
> GRANT EXECUTE ON PROCEDURE p_inv TO `aramis@musketeers.fr`;

-- Run as Porthos.
> GRANT EXECUTE ON PROCEDURE p_def TO `aramis@musketeers.fr`;

Aramis n’a aucun privilège sur t, f_a, v_pou f_p.

Aramis appelle la chaîne

Problèmes d’Aramis :

-- Run as Aramis.
> CALL p_inv();

La chaîne d’appels se déroule comme suit, chaque flèche se croisant dans un nouveau corps :

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)

Le tableau suivant décrit les instructions à mesure qu’elles s’exécutent.

Step Déclaration Elle s’exécute… Utilisateur autorisé session_user()
1 CALL p_inv() Session d’Aramis Aramis Aramis
2 CALL p_def() Corps de p_inv (SQL SECURITY INVOKER) Aramis (hérité de l’appelant) Aramis
3 SELECT f_p() Corps de p_def (SQL SECURITY DEFINER) Porthos (propriétaire de procédure) Aramis
4 RETURN f_a(1) + f_a(2) + f_a(3) Corps de la fonction UDF SQL f_p Porthos (propriétaire de fonction) Aramis
5 RETURN (SELECT b100 FROM v_p WHERE a = p) Corps de la fonction UDF SQL f_a Athos (propriétaire de fonction) Aramis
6 SELECT a, b * 100 AS b100 FROM t Corps de la vue v_p Porthos (propriétaire de la vue) Aramis

Lorsque l’exécution se déroule, l’utilisateur autorisé retourne la couche arrière par couche jusqu’à ce que le contrôle retourne à la session d’Aramis à l’étape 1.