ภาษาของนิพจน์ทั่วไป (CEL)

Common Expression Language (CEL) เป็นภาษาสำหรับนิพจน์ที่ใช้เพื่อวัตถุประสงค์ทั่วไปซึ่งออกแบบมาให้รวดเร็ว พกพาง่าย และใช้งานได้อย่างปลอดภัย คุณจะใช้ CEL เพียงอย่างเดียว หรือฝังลงในผลิตภัณฑ์ที่มีขนาดใหญ่กว่าก็ได้ CEL เหมาะสำหรับแอปพลิเคชันที่หลากหลาย ตั้งแต่การกำหนดเส้นทางการเรียกใช้โพรซีเยอร์ระยะไกล (RPC) ไปจนถึงการกำหนดนโยบายความปลอดภัย CEL สามารถยืดหยุ่น ทำงานเป็นอิสระจากแพลตฟอร์ม และเพิ่มประสิทธิภาพสำหรับเวิร์กโฟลว์แบบคอมไพล์/ประเมินผลจำนวนมาก

CEL ออกแบบมาเพื่อความปลอดภัยในการรันรหัสผู้ใช้โดยเฉพาะ แม้ว่าการเรียกใช้ eval() ในโค้ด Python ของผู้ใช้จะตกอยู่ในอันตราย แต่คุณก็เรียกใช้โค้ด CEL ของผู้ใช้ได้อย่างปลอดภัย และเนื่องจาก CEL ป้องกันพฤติกรรมที่จะทำให้ประสิทธิภาพลดลง จึงประเมินอย่างปลอดภัยในระดับนาโนวินาทีหรือไมโครวินาที ความเร็วและความปลอดภัยของ CEL ทำให้เหมาะสำหรับแอปพลิเคชันที่ต้องการประสิทธิภาพสูงสุด

CEL จะประเมินนิพจน์ที่คล้ายกับฟังก์ชันบรรทัดเดียวหรือนิพจน์ lambda แม้ว่าโดยทั่วไปจะใช้ CEL สำหรับการตัดสินใจแบบบูลีน แต่คุณก็ใช้เพื่อสร้างออบเจ็กต์ที่ซับซ้อนมากขึ้นได้ เช่น JSON หรือข้อความบัฟเฟอร์โปรโตคอล

สาเหตุที่ควรใช้ CEL

บริการและแอปพลิเคชันจํานวนมากประเมินการกำหนดค่าที่ประกาศ ตัวอย่างเช่น การควบคุมการเข้าถึงตามบทบาท (RBAC) เป็นการกำหนดค่าแบบประกาศที่สร้างการตัดสินใจเกี่ยวกับการเข้าถึงตามบทบาทของผู้ใช้และกลุ่มผู้ใช้ แม้ว่าการกำหนดค่าแบบประกาศจะเพียงพอสำหรับกรณีส่วนใหญ่แล้ว แต่บางครั้งคุณต้องการประสิทธิภาพในการแสดงออกมากขึ้น ซึ่ง CEL จะเข้ามาช่วยในเรื่องนี้

ลองพิจารณาความสามารถของ Identity and Access Management (IAM) เป็นตัวอย่างของการขยายการกำหนดค่าแบบประกาศด้วย CEL แม้ว่า 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 { well_known: "TIMESTAMP" }
  }
}

เครื่องมือตรวจสอบประเภท CEL จะใช้การประกาศแบบ Proto เพื่อให้แน่ใจว่าตัวระบุและการอ้างอิงฟังก์ชันทั้งหมดภายในนิพจน์ได้รับการประกาศและใช้อย่างถูกต้อง

เฟสของการประมวลผลนิพจน์

ระบบจะประมวลผลนิพจน์ CEL เป็น 3 ระยะ ดังนี้

  1. แยกวิเคราะห์
  2. ตรวจสอบ
  3. ประเมิน

รูปแบบการใช้ CEL ที่พบบ่อยที่สุดคือการแยกวิเคราะห์และตรวจสอบนิพจน์เมื่อทำการกำหนดค่า จัดเก็บ AST แล้วจึงดึงและประเมิน AST ซ้ำๆ ในรันไทม์

ภาพขั้นตอนการประมวลผล CEL

ระบบจะแยกวิเคราะห์และตรวจสอบนิพจน์ในเส้นทางการกําหนดค่า จัดเก็บ และประเมินกับบริบทอย่างน้อย 1 รายการในเส้นทางการอ่าน

CEL จะแยกวิเคราะห์จากนิพจน์ที่มนุษย์อ่านได้เป็น AST โดยใช้ไวยากรณ์และไวยากรณ์ ANTLR ส่วนการแยกวิเคราะห์จะปล่อย AST แบบโปรโต ซึ่งแต่ละโหนด Expr ใน AST จะมีรหัสจำนวนเต็มที่ใช้เพื่อจัดทำดัชนีในข้อมูลเมตาที่สร้างขึ้นระหว่างการแยกวิเคราะห์และการตรวจสอบ ไฟล์ syntax.proto ที่สร้างขึ้นระหว่างการแยกวิเคราะห์แสดงถึงการแทนนามธรรมของสิ่งที่พิมพ์ในรูปแบบสตริงของนิพจน์

หลังจากแยกวิเคราะห์นิพจน์แล้ว ระบบจะตรวจสอบประเภทเทียบกับสภาพแวดล้อมเพื่อให้แน่ใจว่าตัวระบุฟังก์ชันและตัวแปรทั้งหมดในนิพจน์ได้รับการประกาศและใช้อย่างถูกต้อง เครื่องมือตรวจสอบประเภทจะสร้างไฟล์ checked.proto ที่มีข้อมูลเมตาเกี่ยวกับประเภท ตัวแปร และการแก้ปัญหาด้านฟังก์ชันที่ช่วยปรับปรุงประสิทธิภาพในการประเมินได้อย่างมาก

สุดท้าย หลังจากแยกวิเคราะห์และตรวจสอบนิพจน์แล้ว ระบบจะประเมิน AST ที่จัดเก็บไว้

ผู้ประเมิน CEL ต้องการ 3 สิ่งคือ

  • การเชื่อมโยงฟังก์ชันสำหรับส่วนขยายที่กำหนดเอง
  • การเชื่อมโยงตัวแปร
  • AST เพื่อประเมิน

การเชื่อมโยงฟังก์ชันและตัวแปรควรตรงกับที่ใช้ในการคอมไพล์ AST อินพุตเหล่านี้สามารถใช้ซ้ำได้ในการประเมินหลายรายการ เช่น การประเมิน AST ในการเชื่อมโยงตัวแปรหลายชุด ตัวแปรเดียวกันที่ใช้กับ AST จำนวนมาก หรือการเชื่อมโยงฟังก์ชันที่ใช้ตลอดอายุของกระบวนการ (กรณีที่พบบ่อย)