Skip to content

Phase 8: resolve ACL scope from identity instead of trusting the caller #16

Description

@monthop-gmail

resolve_policy() ตอนนี้เป็น pure constructor — คนเรียกส่ง allowed_metadata มาเองได้ตามใจ
ใน production ค่านี้ต้องมาจาก policy plane ไม่ใช่จาก caller

งาน

  • แปลง principal (roles/groups/attributes) → allowed_metadata ตามกฎที่กำหนด
  • กำหนดว่า role ไหนเห็น classification ระดับใดได้บ้าง แล้วเขียนเป็น policy ที่ทดสอบได้
  • ทำให้ caller ไม่สามารถ ส่ง allowed_metadata ที่กว้างกว่าที่ policy ให้
  • MCP tool argument ต้องตั้ง tenant_id ไม่ได้ (ต่อกับ Phase 5: MCP stdio integrity — stdout must carry JSON-RPC only #10)

งานที่เพิ่มจากการอ่าน identity/v1 จริง (2026-08-21)

เจอตอนทำ #17 · identity.schema.yaml

  • บังคับกฎ on_behalf_of: delegation ต้องไม่ทำให้สิทธิ์กว้างขึ้นกว่า principal ต้นสาย
    schema เขียนไว้เป็นกฎ ไม่ใช่คำแนะนำ · Principal.on_behalf_of ถูกเพิ่มเข้า contracts.py แล้วใน 424e183
    แต่ model ไว้เฉย ๆ ยังไม่มีใครบังคับ — ที่บังคับต้องเป็น resolve_policy() ตัวนี้
    เคสจริงของโดเมนนี้เลย: agent ค้นแทนคน · scope ที่ได้ต้องแคบกว่าหรือเท่ากับของคนต้นสายเสมอ
    ต้องมี test ที่ agent พยายามได้สิทธิ์กว้างกว่าคนที่มันทำงานแทน แล้วโดนปฏิเสธ
  • validate id ตาม pattern ของ platform: ^[a-z0-9][a-z0-9_-]{0,62}$
    ตอนนี้ Principal("U-1") ผ่านสบาย แต่จะ fail ตอน validate payload จริงใน CI (Phase 10: CI — unit + lint + typecheck, and integration with a pgvector service #18 / Phase 9: conform to the agent-platform contracts that exist, and earn knowledge/v1 #17 งาน B)
    ใช้ได้ทั้ง principal_id และ tenant_id (TenantId เป็น $ref ของ Id ตัวเดียวกัน)
  • เผื่อทาง Request.consent ของ policy/v1 (ADR-0016)
    🔒 policy ไม่ได้เป็นคนประเมิน consent — ผู้เรียกประเมินแล้วส่งผลเข้ามาให้ policy ใช้ประกอบ
    consent/v1.conditions คือเงื่อนไขที่ต้องยังจริง ตอนเข้าถึง ไม่ใช่แค่ตอนออกใบ (ADR-0014)
    ถ้า ACL จะผูกกับสังกัด/บทบาทที่เปลี่ยนได้ อันนี้คือกลไกที่มีอยู่แล้ว ไม่ต้องคิดใหม่
  • ถ้าใช้ consent: แนบ consent ไปกับ event ของการค้นเอง — ห้ามยิง event แยก
    ADR-0020 · consent/v1 v1.3.0 · event/v1 v1.6.0 (cb031bc, 2026-08-21)
    consent_rules ข้อ 2 เขียนไว้ตรง ๆ ว่า การใช้ consent ไม่มี event type ของตัวเองโดยเจตนา
    ให้แนบ field consent ($defs.Evaluation) ไปกับ event ที่เกิดการเข้าถึงจริง — ซึ่งของเราคือ event ของการค้น

    ไม่งั้นจะมีสองบันทึกของเหตุการณ์เดียวกัน และ query ด้วย event_type จะตกหล่นการใช้ที่บันทึกบน event ของโดเมน
    ⚠️ ถ้าเข้าใจผิดข้อนี้จะสร้าง audit ซ้ำโดยไม่รู้ตัว และไปรู้ตอน audit review ซึ่งสายแล้ว

  • ยืนยันว่า group/สังกัด ไม่ให้สิทธิ์โดยอัตโนมัติ
    consent_rules: "ความสัมพันธ์ (ญาติ · ผู้ดูแล · ทีมเดียวกัน) ไม่ให้สิทธิ์อะไรโดยอัตโนมัติ"
    ตรงกับ deny-by-default ที่ build_scope_predicate() ทำอยู่แล้ว — เขียนเป็นเทสยืนยันไว้ กันคนแก้ทีหลังให้ groups กลายเป็นสิทธิ์

⚠️ ถ้า #23 (workspace) ตอบว่า "ต้องมี" งานในนี้จะเพิ่มอีกชั้น — resolve_policy() ต้องคืน workspace scope ด้วย

เงื่อนไขว่าเสร็จ

  • มี test ที่พยายาม escalate สิทธิ์ผ่าน argument แล้วโดนปฏิเสธ
  • มี test ที่ delegation (on_behalf_of) พยายามขยายสิทธิ์แล้วโดนปฏิเสธ
  • tests/mcp/test_tool_arguments_cannot_set_tenant_id ผ่าน

ทำไมสำคัญ

ถ้า agent ตั้ง tenant ให้ตัวเองได้ boundary ใน §4.3 จะกลายเป็นแค่คำแนะนำ ไม่ใช่ boundary
และถ้า agent ได้สิทธิ์กว้างกว่าคนที่มันทำงานแทน delegation ก็กลายเป็นช่องยกระดับสิทธิ์

อ้างอิง: §4.3, §11 · ADR-0007, ADR-0014, ADR-0016 · src/enterprise_knowledge/security.py

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    securityACL, tenant isolation, policy boundary (§4.2, §4.3)

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions