Ngôn ngữ diễn đạt phổ biến (CEL)

Ngôn ngữ biểu thức chung (CEL) là một ngôn ngữ biểu thức có mục đích chung, được thiết kế để thực thi nhanh chóng, linh hoạt và an toàn. Bạn có thể sử dụng riêng CEL hoặc nhúng vào một sản phẩm lớn hơn. CEL rất phù hợp với nhiều ứng dụng, từ việc định tuyến các lệnh gọi quy trình từ xa (RPC) cho đến việc xác định các chính sách bảo mật. CEL có thể mở rộng, độc lập với nền tảng và được tối ưu hoá cho quy trình biên dịch một lần/đánh giá nhiều lần.

CEL được thiết kế riêng để đảm bảo an toàn khi thực thi mã người dùng. Mặc dù việc gọi eval() trên mã python của người dùng sẽ rất nguy hiểm, nhưng bạn có thể thực thi mã CEL của người dùng một cách an toàn. Vì CEL ngăn chặn hành vi làm giảm hiệu suất, nên CEL sẽ đánh giá an toàn sau nano giây hoặc micrô giây. Tốc độ và độ an toàn của CEL giúp giải pháp này trở nên lý tưởng cho các ứng dụng đòi hỏi hiệu suất cao.

CEL đánh giá các biểu thức tương tự như hàm một dòng hoặc biểu thức lambda. Mặc dù CEL thường được dùng cho các quyết định về boolean, bạn cũng có thể sử dụng CEL để tạo các đối tượng phức tạp hơn như JSON hoặc thông điệp vùng đệm giao thức.

Tại sao nên chọn CEL?

Nhiều dịch vụ và ứng dụng đánh giá cấu hình khai báo. Ví dụ: chế độ kiểm soát quyền truy cập dựa trên vai trò (RBAC) là một cấu hình khai báo đưa ra quyết định về quyền truy cập cho một vai trò của người dùng và một nhóm người dùng. Mặc dù cấu hình khai báo là đủ cho hầu hết các trường hợp, nhưng đôi khi bạn cần có nhiều khả năng biểu đạt hơn. Đó là lúc CEL phát huy tác dụng.

Ví dụ về việc mở rộng cấu hình khai báo bằng CEL, hãy xem xét chức năng của dịch vụ Quản lý danh tính và quyền truy cập (IAM) của Google Cloud. Mặc dù RBAC là trường hợp phổ biến, nhưng IAM cung cấp biểu thức CEL để cho phép người dùng ràng buộc thêm phạm vi cấp quyền dựa trên vai trò theo thuộc tính thông báo proto của yêu cầu hoặc tài nguyên đang được truy cập. Việc mô tả các điều kiện như vậy thông qua mô hình dữ liệu sẽ dẫn đến một nền tảng API phức tạp rất khó xử lý. Thay vào đó, việc sử dụng CEL với chế độ kiểm soát quyền truy cập dựa trên thuộc tính (ABAC) là một tiện ích đầy ý nghĩa và mạnh mẽ cho RBAC.

Các khái niệm chính về CEL

Trong CEL, một biểu thức sẽ được biên dịch dựa trên một môi trường. Bước biên dịch sẽ tạo ra một cây cú pháp trừu tượng (AST) ở định dạng vùng đệm giao thức. Biểu thức biên dịch được lưu trữ để sử dụng trong tương lai nhằm đảm bảo quá trình đánh giá nhanh nhất có thể. Một biểu thức đã biên dịch có thể được đánh giá bằng nhiều dữ liệu đầu vào.

Sau đây là thông tin chi tiết hơn về một số khái niệm này.

Biểu thức

Biểu thức do người dùng viết. Biểu thức tương tự như phần nội dung hàm một dòng hoặc biểu thức lambda. Chữ ký hàm khai báo dữ liệu đầu vào được ghi bên ngoài biểu thức CEL và thư viện hàm có sẵn cho CEL sẽ được nhập tự động.

Ví dụ: biểu thức CEL sau đây lấy một đối tượng yêu cầu và yêu cầu bao gồm mã thông báo claims. Biểu thức này sẽ trả về một giá trị boolean cho biết liệu mã thông báo claims còn hợp lệ hay không.

Biểu thức CEL mẫu để xác thực mã thông báo xác nhận quyền sở hữu

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

Mặc dù người dùng xác định biểu thức CEL, nhưng các dịch vụ và ứng dụng sẽ xác định môi trường mà biểu thức này chạy.

Môi trường

Môi trường được xác định theo dịch vụ. Các dịch vụ và ứng dụng nhúng CEL khai báo môi trường biểu thức. Môi trường là tập hợp các biến và hàm có thể dùng trong biểu thức CEL.

Ví dụ: mã textproto sau đây khai báo môi trường chứa các biến requestnow bằng cách sử dụng thông báo CompileRequest từ dịch vụ CEL.

Ví dụ về khai báo môi trường 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" }
  }
}

Trình kiểm tra loại CEL sử dụng các nội dung khai báo dựa trên proto để đảm bảo rằng tất cả các giá trị nhận dạng và tham chiếu hàm trong một biểu thức được khai báo và sử dụng đúng cách.

Các giai đoạn xử lý biểu thức

Biểu thức CEL được xử lý theo ba giai đoạn:

  1. Phân tích cú pháp
  2. Kiểm tra
  3. Đánh giá

Mẫu sử dụng CEL phổ biến nhất là phân tích cú pháp và kiểm tra biểu thức tại thời điểm định cấu hình, lưu trữ AST, sau đó truy xuất và đánh giá AST nhiều lần trong thời gian chạy.

Hình minh hoạ các giai đoạn xử lý CEL

Biểu thức được phân tích cú pháp và kiểm tra trên đường dẫn cấu hình, được lưu trữ, sau đó được đánh giá theo một hoặc nhiều ngữ cảnh trên đường dẫn đọc.

CEL được phân tích cú pháp từ biểu thức mà con người có thể đọc được thành AST bằng cú pháp lexer và phân tích cú pháp ANTLR. Giai đoạn phân tích cú pháp sẽ phát ra AST dựa trên proto, trong đó mỗi nút Expr trong AST chứa một mã nhận dạng số nguyên dùng để lập chỉ mục siêu dữ liệu được tạo trong quá trình phân tích cú pháp và kiểm tra. Tệp syntax.proto được tạo trong quá trình phân tích cú pháp biểu thị bản trình bày trừu tượng của nội dung đã nhập ở dạng chuỗi của biểu thức.

Sau khi được phân tích cú pháp một biểu thức, biểu thức đó sẽ được kiểm tra kiểu dựa trên môi trường để đảm bảo tất cả giá trị nhận dạng biến và giá trị nhận dạng hàm trong biểu thức đã được khai báo và đang được sử dụng đúng cách. Trình kiểm tra loại sẽ tạo một tệp checked.proto bao gồm siêu dữ liệu về loại, biến và độ phân giải hàm có thể cải thiện đáng kể hiệu quả đánh giá.

Cuối cùng, sau khi một biểu thức được phân tích cú pháp và kiểm tra, AST đã lưu trữ sẽ được đánh giá.

Người đánh giá CEL cần 3 yếu tố:

  • Liên kết hàm cho mọi tiện ích tuỳ chỉnh
  • Các liên kết biến
  • AST để đánh giá

Các liên kết hàm và biến phải khớp với nội dung dùng để biên dịch AST. Bạn có thể sử dụng lại bất kỳ dữ liệu đầu vào nào trong số này trong nhiều lần đánh giá, chẳng hạn như AST được đánh giá trên nhiều tập hợp liên kết biến, cùng các biến được sử dụng trong nhiều AST hoặc các liên kết hàm được sử dụng trong suốt thời gian của một quy trình (một trường hợp phổ biến).