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, позволяющие пользователям дополнительно ограничивать область действия ролевого гранта в соответствии со свойствами сообщения proto запроса или доступными ресурсами. Описание таких условий через модель данных привело бы к созданию сложной поверхности 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 { we
ll_known: "TIMESTAMP" }
}
}
Основанные на прототипах объявления используются средством проверки типов CEL для обеспечения того, чтобы все ссылки на идентификаторы и функции в выражении были объявлены и использовались правильно.
Фазы обработки выражения
Выражения CEL обрабатываются в три этапа:
- Анализировать
- Проверять
- Оценивать
Наиболее распространенный шаблон использования CEL — это разбор и проверка выражений во время конфигурации, сохранение AST, а затем повторное извлечение и оценка AST во время выполнения.
Иллюстрация фаз обработки CEL
CEL-код разбирается из человекочитаемого выражения в AST с помощью лексера ANTLR и грамматики парсера. На этапе разбора формируется AST на основе прото, где каждый узел Expr
в AST содержит целочисленный идентификатор, используемый для индексации метаданных, сгенерированных в ходе разбора и проверки. Файл syntax.proto
, создаваемый в процессе разбора, представляет собой абстрактное представление того, что было введено в строковой форме выражения.
После разбора выражения выполняется проверка его типов в соответствии с окружением, чтобы убедиться, что все идентификаторы переменных и функций в выражении объявлены и используются корректно. Проверка типов создаёт файл checked.proto
, содержащий метаданные разрешения типов, переменных и функций, которые могут значительно повысить эффективность вычисления.
Наконец, после анализа и проверки выражения оценивается сохраненное AST.
Оценщику CEL нужны три вещи:
- Привязки функций для любых пользовательских расширений
- Переменные привязки
- AST для оценки
Связывания функций и переменных должны соответствовать тем, которые использовались при компиляции AST. Любые из этих входных данных могут быть повторно использованы в нескольких вычислениях, например, AST, оцениваемый с использованием нескольких наборов связываний переменных, одни и те же переменные, используемые для нескольких AST, или связывания функций, используемые на протяжении всего жизненного цикла процесса (распространённый случай).