Common Expression Language (CEL)

Common Expression Language (CEL)는 빠르고 이동 가능하며 안전하게 실행하도록 설계된 범용 표현식 언어입니다. CEL은 단독으로 사용하거나 더 큰 제품에 삽입할 수 있습니다. CEL은 리모트 프로시져 콜 (RPC) 라우팅에서 보안 정책 정의에 이르기까지 다양한 애플리케이션에 적합합니다. CEL은 확장 가능하고, 플랫폼과 독립적이며, 한 번 컴파일/평가하는 여러 워크플로에 최적화되어 있습니다.

CEL은 사용자 코드를 안전하게 실행하도록 특별히 설계되었습니다. 사용자의 Python 코드에서 맹목적으로 eval()를 호출하는 것은 위험하지만 사용자의 CEL 코드를 안전하게 실행할 수 있습니다. 또한 CEL은 성능이 저하되는 동작을 방지하므로 나노초 또는 마이크로초 단위로 안전하게 평가됩니다. CEL은 속도와 안전성이 뛰어나 성능이 중요한 애플리케이션에 이상적입니다.

CEL은 단일 행 함수 또는 람다 표현식과 유사한 표현식을 평가합니다. CEL은 불리언 결정에 일반적으로 사용되지만 JSON 또는 프로토콜 버퍼 메시지와 같은 더 복잡한 객체를 구성할 수도 있습니다.

CEL을 사용해야 하는 이유

많은 서비스와 애플리케이션에서 선언적 구성을 평가합니다. 예를 들어 역할 기반 액세스 제어 (RBAC)는 사용자 역할과 사용자 집합을 고려하여 액세스 결정을 내리는 선언적 구성입니다. 대부분의 경우 선언적 구성으로 충분하지만 표현 능력이 더 필요한 경우도 있습니다. 그래서 CEL이 도움이 됩니다.

CEL을 사용하여 선언적 구성을 확장하는 예로 Google Cloud Identity and Access Management (IAM)의 기능을 고려하세요. RBAC가 일반적인 경우이지만 IAM은 사용자가 요청의 proto 메시지 속성 또는 액세스하는 리소스에 따라 역할 기반 권한의 범위를 추가로 제한할 수 있도록 CEL 표현식을 제공합니다. 데이터 모델을 통해 이러한 조건을 설명하면 API 노출 영역이 복잡하여 다루기 어려워집니다. 대신 속성 기반 액세스 제어 (ABAC)와 함께 CEL을 사용하면 표현력이 뛰어나고 강력한 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을 삽입하는 서비스 및 애플리케이션은 표현식 환경을 선언합니다. 환경은 CEL 표현식에 사용할 수 있는 변수와 함수의 모음입니다.

예를 들어 다음 textproto 코드는 CEL 서비스의 CompileRequest 메시지를 사용하여 requestnow 변수가 포함된 환경을 선언합니다.

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" }
  }
}

proto 기반 선언은 표현식 내의 모든 식별자와 함수 참조가 선언되고 올바르게 사용되도록 CEL 유형 검사기에서 사용됩니다.

표현식 처리 단계

CEL 표현식은 3단계로 처리됩니다.

  1. Parse
  2. 확인
  3. 평가

CEL 사용의 가장 일반적인 패턴은 구성 시점에 표현식을 파싱 및 확인하고, AST를 저장한 다음, 런타임에 반복적으로 AST를 검색하고 평가하는 것입니다.

CEL 처리 단계 이미지

표현식은 구성 경로에서 파싱 및 확인되고 저장된 후 읽기 경로에서 하나 이상의 컨텍스트에 대해 평가됩니다.

CEL은 ANTLR 어휘서 및 파서 문법을 사용하여 사람이 읽을 수 있는 표현식에서 AST로 파싱됩니다. 파싱 단계에서는 proto 기반 AST를 내보냅니다. 이때 AST의 각 Expr 노드는 파싱 및 검사 중에 생성된 메타데이터의 색인을 생성하는 데 사용되는 정수 ID를 포함합니다. 파싱 중에 생성된 syntax.proto 파일은 표현식의 문자열 형식으로 입력된 내용의 추상적 표현을 나타냅니다.

표현식이 파싱된 후에는 환경과 비교하여 유형을 검사하여 표현식의 모든 변수 및 함수 식별자가 선언되었고 올바르게 사용되고 있는지 확인합니다. 유형 검사기는 평가 효율성을 크게 개선할 수 있는 유형, 변수, 함수 결정 메타데이터가 포함된 checked.proto 파일을 생성합니다.

마지막으로 표현식이 파싱되고 검사된 후 저장된 AST가 평가됩니다.

CEL 평가자는 다음 3가지가 필요합니다.

  • 커스텀 확장 프로그램의 함수 바인딩
  • 변수 결합
  • 평가할 AST

함수 결합과 변수 결합은 AST 컴파일에 사용된 결합과 일치해야 합니다. 이러한 입력은 여러 평가에서 재사용될 수 있습니다. 예를 들어 AST가 여러 변수 결합 세트에서 평가되거나 여러 AST에 사용되는 동일한 변수 또는 프로세스의 전체 기간에 사용되는 함수 결합이 있습니다 (일반적인 사례).