Общий язык выражений (CEL)

Common Expression Language (CEL) — это язык выражений общего назначения, предназначенный для быстрого, переносимого и безопасного выполнения. Вы можете использовать CEL отдельно или встроить его в более крупный продукт. CEL отлично подходит для самых разных приложений: от маршрутизации удаленных вызовов процедур (RPC) до определения политик безопасности. CEL является расширяемым, независимым от платформы и оптимизированным для рабочих процессов с однократной компиляцией и множественной оценкой.

CEL был разработан специально для обеспечения безопасности выполнения пользовательского кода. Хотя слепо вызывать eval() для пользовательского кода Python опасно, вы можете безопасно выполнить пользовательский CEL-код. А поскольку CEL предотвращает поведение, которое могло бы снизить его производительность, он безопасно оценивается за наносекунды или микросекунды. Скорость и безопасность CEL делают его идеальным для приложений, где производительность критически важна.

CEL оценивает выражения, похожие на однострочные функции или лямбда-выражения. Хотя CEL обычно используется для логических решений, вы также можете использовать его для создания более сложных объектов, таких как JSON или сообщения буфера протокола.

Почему CEL?

Многие службы и приложения оценивают декларативные конфигурации. Например, управление доступом на основе ролей (RBAC) — это декларативная конфигурация, которая принимает решение о доступе с учетом роли пользователя и набора пользователей. Хотя в большинстве случаев декларативных конфигураций достаточно, иногда вам требуется больше выразительных возможностей. Вот здесь и появляется CEL.

В качестве примера расширения декларативной конфигурации с помощью CEL рассмотрим возможности Google Cloud Identity and Access Management (IAM) . Хотя RBAC является распространенным случаем, IAM предлагает выражения CEL, позволяющие пользователям дополнительно ограничивать объем ролевого гранта в соответствии со свойствами прото-сообщения запроса или ресурсами, к которым осуществляется доступ. Описание таких условий через модель данных приведет к усложнению поверхности API, с которой будет сложно работать. Вместо этого использование CEL с контролем доступа на основе атрибутов (ABAC) является выразительным и мощным расширением RBAC.

Основные концепции CEL

В CEL выражение компилируется с учетом среды. На этапе компиляции создается абстрактное синтаксическое дерево (AST) в формате буфера протокола . Скомпилированные выражения сохраняются для использования в будущем, чтобы обеспечить максимально быструю оценку. Одно скомпилированное выражение может быть оценено с использованием множества различных входных данных.

Вот более детальный взгляд на некоторые из этих концепций.

Выражения

Выражения пишут пользователи. Выражения аналогичны телам однострочных функций или лямбда-выражениям. Сигнатура функции, объявляющая входные данные, записывается вне выражения CEL, а библиотека функций, доступных для CEL, импортируется автоматически.

Например, следующее выражение CEL принимает объект запроса, а запрос включает токен claims . Выражение возвращает логическое значение, указывающее, действителен ли токен claims .

Пример выражения CEL для аутентификации токена утверждений

// 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

В то время как пользователи определяют выражение CEL, службы и приложения определяют среду, в которой оно работает.

Окружающая среда

Среды определяются службами . Службы и приложения, встраивающие CEL, объявляют среду выражения. Среда — это набор переменных и функций, которые можно использовать в выражениях CEL.

Например, следующий код textproto объявляет среду, содержащую request , а now и переменные, используя сообщение CompileRequest от службы CEL.

Пример объявления среды 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" }
  }
}

Объявления на основе прототипов используются средством проверки типов CEL, чтобы гарантировать, что все ссылки на идентификаторы и функции внутри выражения объявлены и используются правильно.

Фазы обработки выражения

Выражения CEL обрабатываются в три этапа:

  1. Разобрать
  2. Проверять
  3. Оценивать

Наиболее распространенный шаблон использования CEL — анализ и проверка выражений во время настройки, сохранение AST, а затем повторное получение и оценка AST во время выполнения.

Иллюстрация этапов обработки CEL

Выражения анализируются и проверяются на путях конфигурации, сохраняются, а затем оцениваются по одному или нескольким контекстам на путях чтения.

CEL анализируется из удобочитаемого выражения в AST с использованием лексера ANTLR и грамматики синтаксического анализатора. На этапе анализа создается AST на основе прототипа, где каждый узел Expr в AST содержит целочисленный идентификатор, который используется для индексации метаданных, сгенерированных во время анализа и проверки. Файл syntax.proto , созданный во время синтаксического анализа, представляет собой абстрактное представление того, что было введено в строковую форму выражения.

После анализа выражения его тип проверяется на соответствие среде, чтобы убедиться, что все идентификаторы переменных и функций в выражении объявлены и используются правильно. Средство проверки типов создает файл checked.proto , содержащий метаданные типа, переменной и разрешения функций, которые могут значительно повысить эффективность оценки.

Наконец, после анализа и проверки выражения оценивается сохраненный AST.

Оценщику CEL нужны три вещи:

  • Привязки функций для любых пользовательских расширений
  • Привязки переменных
  • AST для оценки

Привязки функций и переменных должны соответствовать тому, что использовалось для компиляции AST. Любой из этих входных данных можно повторно использовать в нескольких оценках, например, AST оценивается по множеству наборов привязок переменных, одни и те же переменные используются для многих AST, или привязки функций используются на протяжении всего жизненного цикла процесса (частый случай).