Langage CEL (Common Expression Language)

Le 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 CEL seul ou l'intégrer à un produit plus vaste. CEL est parfaitement adapté à un large éventail d'applications, du routage des appels de procédure à distance (RPC) à la définition des règles de sécurité. CEL est extensible, indépendant de la plate-forme et optimisé pour les workflows de compilation unique/évaluation multiple.

CEL a été conçu spécifiquement pour exécuter le code utilisateur de manière sécurisée. Bien qu'il soit dangereux d'appeler aveuglément eval() sur le code Python d'un utilisateur, vous pouvez exécuter en toute sécurité le code CEL d'un utilisateur. Étant donné que CEL empêche les comportements qui réduiraient ses performances, il effectue des évaluations sécurisées en nanosecondes ou microsecondes. La vitesse et la sécurité de CEL en font un choix idéal pour les applications critiques en termes de performances.

CEL évalue les expressions qui sont semblables à des fonctions sur une seule ligne ou à des expressions lambda. Bien que le langage 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 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 de plus de puissance d'expression. C'est là que CEL entre en jeu.

Pour illustrer l'extension d'une configuration déclarative avec CEL, prenons l'exemple des fonctionnalités de Identity and Access Management (IAM) de Google Cloud. Bien que le RBAC soit le cas le plus courant, IAM propose des expressions CEL pour permettre aux utilisateurs de limiter davantage la portée de l'autorisation basée sur les rôles en fonction des propriétés du message proto de la requête ou des ressources auxquelles ils accèdent. Décrire de telles conditions à l'aide du modèle de données entraînerait une surface d'API complexe et difficile à utiliser. En revanche, l'utilisation de CEL avec le contrôle des accès basé sur les attributs (ABAC) constitue une extension expressive et puissante du RBAC.

Concepts de base de CEL

Dans CEL, une expression est compilée par rapport à un environnement. L'étape de compilation produit un arbre syntaxique abstrait (AST) au format protocol buffer. Les expressions compilées sont stockées pour une utilisation ultérieure afin de rendre l'évaluation aussi rapide que possible. Une même 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 fonction ou aux expressions lambda sur une seule ligne. La signature de fonction qui déclare l'entrée est écrite en dehors de l'expression CEL, et la bibliothèque de fonctions disponible pour CEL est importée automatiquement.

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

Exemple d'expression CEL pour authentifier un jeton de revendications

// 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 les services. Les services et applications qui intègrent CEL déclarent l'environnement d'expression. L'environnement est l'ensemble des variables et des fonctions qui peuvent être utilisées dans les 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 les fichiers proto sont utilisées par le vérificateur de type CEL pour s'assurer que toutes les références d'identifiants et de fonctions dans une expression sont déclarées et utilisées correctement.

Phases du traitement des expressions

Les expressions CEL sont traitées en trois phases :

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

Le modèle d'utilisation le plus courant 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 à plusieurs reprises 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.

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

Une fois qu'une expression est analysée, elle est ensuite vérifiée par rapport à l'environnement pour s'assurer que tous les identifiants de variables et de fonctions de l'expression ont été déclarés et sont utilisés correctement. Le vérificateur de type produit un fichier checked.proto qui inclut des métadonnées de résolution de type, de variable et de fonction, ce qui peut améliorer considérablement l'efficacité de l'évaluation.

Enfin, une fois qu'une expression a été analysée et vérifiée, l'AST stocké est évalué.

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

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

Les liaisons de fonctions et de variables doivent correspondre à celles utilisées pour compiler l'AST. Chacune de ces entrées peut être réutilisée dans plusieurs évaluations, par exemple un AST évalué sur plusieurs ensembles de liaisons de variables, les mêmes variables utilisées sur plusieurs AST ou les liaisons de fonctions utilisées tout au long d'un processus (cas courant).