Common Expression Language(CEL)は、高速で移植可能で安全な実行を目的とした汎用式言語です。CEL は単独で使用することも、より大きなプロダクトに埋め込むこともできます。CEL は、リモート プロシージャ コール(RPC)のルーティングからセキュリティ ポリシーの定義まで、さまざまなアプリケーションに最適です。CEL は拡張可能で、プラットフォームに依存せず、コンパイル 1 回/評価複数回のワークフロー用に最適化されています。
CEL は、ユーザーコードの実行に安全であるように特別に設計されています。ユーザーの Python コードで eval()
を盲目的に呼び出すのは危険ですが、ユーザーの CEL コードは安全に実行できます。また、CEL はパフォーマンスを低下させる動作を防ぐため、ナノ秒またはマイクロ秒単位で安全に評価します。CEL は高速で安全であるため、パフォーマンスが重要なアプリケーションに最適です。
CEL は、単一行関数やラムダ式に似た式を評価します。CEL は通常ブール判定に使用されますが、JSON やプロトコル バッファ メッセージなどのより複雑なオブジェクトを構築するために使用することもできます。
CEL を選ぶ理由
多くのサービスとアプリケーションは、宣言型構成を評価します。たとえば、ロールベース アクセス制御(RBAC)は、ユーザーロールとユーザーのセットを指定するとアクセス決定を生成する宣言型構成です。宣言型構成はほとんどの場合に十分ですが、より表現力が必要になることもあります。そこで CEL が役立ちます。
CEL で宣言型構成を拡張する例として、Google Cloud Identity and Access Management(IAM)の機能について考えてみましょう。RBAC が一般的なケースですが、IAM は CEL 式を提供し、ユーザーがリクエストの proto メッセージ プロパティまたはアクセスされるリソースに従って、ロールベースの付与のスコープをさらに制限できるようにします。このような条件をデータモデルで記述すると、複雑で扱いにくい API サーフェスになります。代わりに、属性ベースのアクセス制御(ABAC)で CEL を使用すると、RBAC の表現力と強力な拡張機能が実現します。
CEL の基本コンセプト
CEL では、式は環境に対してコンパイルされます。コンパイル ステップでは、プロトコル バッファ形式の抽象構文ツリー(AST)が生成されます。コンパイルされた式は、評価をできるだけ高速に保つために、将来の使用に備えて保存されます。コンパイルされた 1 つの式を、さまざまな入力で評価できます。
これらのコンセプトについて詳しく見ていきましょう。
式
式はユーザーが記述します。式は、単一行の関数本体またはラムダ式に似ています。入力を宣言する関数シグネチャは 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
コードは、CEL サービスの CompileRequest
メッセージを使用して request
変数と now
変数を含む環境を宣言します。
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" }
}
}
proto ベースの宣言は、CEL 型チェッカーによって使用され、式内のすべての識別子と関数参照が正しく宣言され、使用されていることを確認します。
式の処理フェーズ
CEL 式は次の 3 つのフェーズで処理されます。
- 解析
- 小切手
- 評価
CEL の最も一般的な使用パターンは、構成時に式を解析してチェックし、AST を保存してから、実行時に AST を繰り返し取得して評価することです。
CEL 処理フェーズの図
CEL は、ANTLR の字句解析と構文解析の文法を使用して、人間が読める式から AST に解析されます。解析フェーズでは、proto ベースの AST が出力されます。AST の各 Expr
ノードには、解析とチェック中に生成されたメタデータへのインデックス付けに使用される整数 ID が含まれています。解析中に生成される syntax.proto
ファイルは、式の文字列形式で入力された内容の抽象表現を表します。
式が解析されると、環境に対して型チェックが行われ、式内のすべての変数と関数識別子が宣言され、正しく使用されていることが確認されます。型チェッカーは、評価効率を大幅に向上させる型、変数、関数解決メタデータを含む checked.proto
ファイルを生成します。
最後に、式が解析されてチェックされた後、保存された AST が評価されます。
CEL エバリュエータには次の 3 つが必要です。
- カスタム拡張機能の関数バインディング
- バリエーション バインディング
- 評価する AST
関数と変数のバインディングは、AST のコンパイルに使用されたものと一致している必要があります。これらの入力は、複数の評価で再利用できます。たとえば、多くの変数バインディングのセットで評価される AST、多くの AST で使用される同じ変数、プロセスのライフサイクル全体で使用される関数バインディング(一般的なケース)などです。