Langage CEL (Common Expression Language)

Le langage CEL (Common Expression Language) est un langage d'expression à usage général conçu pour être rapide, portable et sûr à exécuter. Vous pouvez utiliser le CEL seul ou l'intégrer dans un produit plus vaste. Le CEL convient parfaitement à de nombreuses applications, du routage des appels de procédure à distance (RPC) à la définition de stratégies de sécurité. Le CEL est extensible, indépendant de la plate-forme et optimisé pour les workflows de compilation unique ou d'évaluation de plusieurs.

Le langage CEL a été conçu spécifiquement pour exécuter sans risque le code utilisateur. Bien qu'il soit dangereux d'appeler eval() à l'aveugle sur le code Python d'un utilisateur, vous pouvez exécuter en toute sécurité le code CEL d'un utilisateur. Étant donné que le CEL empêche tout comportement qui le rendrait moins performant, il effectue une évaluation sécurisée en nanosecondes ou en microsecondes. Grâce à sa rapidité et à sa sécurité, le CEL est idéal pour les applications critiques.

Le langage CEL évalue les expressions semblables aux fonctions à ligne unique ou aux expressions lambda. Bien que le CEL soit couramment utilisé pour prendre des décisions booléennes, vous pouvez également l'utiliser pour construire des objets plus complexes tels que des messages JSON ou de tampon de protocole.

Pourquoi utiliser le CEL ?

De nombreux services et applications évaluent les configurations déclaratives. Par exemple, le contrôle des accès basé sur les rôles (RBAC) est une configuration déclarative qui produit une décision d'accès en fonction d'un rôle utilisateur et d'un ensemble d'utilisateurs. Bien que les configurations déclaratives soient suffisantes dans la plupart des cas, vous avez parfois besoin d'une puissance d'expression plus élevée. C'est là que CEL entre en jeu.

Comme exemple d'extension d'une configuration déclarative à l'aide du CEL, considérez les fonctionnalités de Identity and Access Management (IAM) de Google Cloud. Bien que RBAC soit le cas courant, IAM propose des expressions CEL pour permettre aux utilisateurs de limiter davantage le champ d'application de l'attribution basée sur les rôles en fonction des propriétés du message proto de la requête ou des ressources consultées. La description de ces conditions à l'aide du modèle de données générerait une surface d'API compliquée avec laquelle il est difficile de travailler. À la place, l'utilisation de CEL avec le contrôle des accès basé sur les attributs (ABAC) est une extension expressive et puissante du contrôle d'accès RBAC.

Concepts fondamentaux du CEL

Dans le langage CEL, une expression est compilée par rapport à un environnement. L'étape de compilation produit une arborescence de syntaxe abstraite (AST) au format de tampon de protocole. Les expressions compilées sont stockées pour une utilisation ultérieure afin que l'évaluation soit aussi rapide que possible. Une seule expression compilée peut être évaluée avec de nombreuses entrées différentes.

Examinons de plus près certains de ces concepts.

Expressions

Les expressions sont écrites par les utilisateurs. Les expressions sont semblables aux corps de fonctions à ligne unique ou aux expressions lambda. La signature de la fonction qui déclare l'entrée est écrite en dehors de l'expression CEL, et la bibliothèque de fonctions disponibles pour le CEL est importée automatiquement.

Par exemple, l'expression CEL suivante utilise un objet de requête, qui inclut un jeton claims. L'expression renvoie une valeur booléenne qui indique si le jeton claims est toujours valide.

Exemple d'expression CEL pour authentifier un jeton de revendication

// Check whether a JSON Web Token has expired by inspecting the 'exp' claim.
//
// Args:
//   claims - authentication claims.
//   now    - timestamp indicating the current system time.
// Returns: true if the token has expired.
//
timestamp(claims["exp"]) < now

Alors que les utilisateurs définissent l'expression CEL, les services et les applications définissent l'environnement dans lequel elle s'exécute.

Environnements

Les environnements sont définis par des services. Les services et les applications qui intègrent le langage CEL déclarent l'environnement d'expression. L'environnement est la collection de variables et de fonctions pouvant être utilisées dans des expressions CEL.

Par exemple, le code textproto suivant déclare un environnement contenant les variables request et now à l'aide du message CompileRequest d'un service CEL.

Exemple de déclaration d'environnement CEL

# Format: $SOURCE_PATH/service.proto#CompileRequest
declarations {
  name: "request"
  ident {
    type { message_type: "google.rpc.context.AttributeContext.Request" }
  }
}
declarations {
  name: "now"
  ident {
    type { well_known: "TIMESTAMP" }
  }
}

Les déclarations basées sur proto sont utilisées par le vérificateur de type CEL pour garantir que toutes les références d'identifiant et de fonction au sein d'une expression sont déclarées et utilisées correctement.

Phases de traitement des expressions

Les expressions CEL sont traitées en trois phases:

  1. Analyser
  2. Vérifier
  3. Évaluer

Le modèle le plus courant d'utilisation de CEL consiste à analyser et vérifier les expressions au moment de la configuration, à stocker l'AST, puis à récupérer et à évaluer l'AST de manière répétée au moment de l'exécution.

Illustration des phases de traitement CEL

Les expressions sont analysées et vérifiées sur les chemins de configuration, stockées, puis évaluées par rapport à un ou plusieurs contextes sur les chemins de lecture.

Le CEL est analysé à partir d'une expression lisible vers un AST à l'aide d'un lexer et d'une grammaire d'analyseur ANTLR. La phase d'analyse émet un AST basé sur un protocole proto où chaque nœud Expr de l'AST contient un ID entier qui permet d'indexer les métadonnées générées lors de l'analyse et de la vérification. Le fichier syntax.proto généré lors de l'analyse représente la représentation abstraite de la saisie sous forme de chaîne de l'expression.

Une fois l'expression analysée, son type est vérifié dans l'environnement pour s'assurer que tous les identifiants de variable et de fonction qu'elle contient ont été déclarés et sont correctement utilisés. Le vérificateur de type génère un fichier checked.proto qui inclut des métadonnées de type, de variable et de résolution de fonction qui peuvent considérablement améliorer l'efficacité de l'évaluation.

Enfin, après l'analyse et la vérification d'une expression, l'AST stockée est évaluée.

L'évaluateur CEL a besoin de trois éléments:

  • Liaisons de fonctions pour toutes les extensions personnalisées
  • Liaisons de variables
  • Une AST à évaluer

Les liaisons de fonction et de variable doivent correspondre à celles utilisées pour compiler l'AST. Chacune de ces entrées peut être réutilisée pour plusieurs évaluations, telles qu'un AST en cours d'évaluation sur de nombreux ensembles de liaisons de variables, les mêmes variables utilisées pour de nombreux AST ou les liaisons de fonctions utilisées pendant la durée de vie d'un processus (cas courant).