Skip to content

feat(authz): add standalone authorization service - #2395

Open
sriaradhyula wants to merge 14 commits into
mainfrom
prebuild/docs/openfga-tool-expression-policies
Open

feat(authz): add standalone authorization service#2395
sriaradhyula wants to merge 14 commits into
mainfrom
prebuild/docs/openfga-tool-expression-policies

Conversation

@sriaradhyula

@sriaradhyula sriaradhyula commented Aug 17, 2026

Copy link
Copy Markdown
Member

Important

Architecture and rollout discussion: Introducing caipe-authz — Discussion #2406. Please use the discussion for design feedback and this PR for implementation review.

Summary

Introduces caipe-authz, a standalone Python authorization service that CAIPE can adopt without replacing the existing BFF and AgentGateway authorization paths in one release.

This PR delivers:

  • HTTP, batch HTTP, and Envoy ext_authz gRPC authorization APIs.
  • OpenFGA relationship checks with OpenFGA-native CEL conditions.
  • Server-owned, typed request context and versioned policy templates.
  • Independent BFF and gateway migration through LEGACY, SHADOW, CANARY, AUTHZ, and AUTHZ_ONLY modes.
  • Policy administration, audit delivery, inspection APIs, and CAIPE UI comparison/graph views.
  • Helm, Docker Compose, CI, operational documentation, and live OpenFGA validation.

Why

Authorization is currently evaluated in more than one runtime. Adding conditional policy directly to those paths would duplicate context construction, policy behavior, audit semantics, and rollback logic.

caipe-authz provides one policy decision point while preserving the existing paths during migration.

Architecture

flowchart LR
    BFF["CAIPE BFF"] --> BR["BFF migration router"]
    GW["Envoy / AgentGateway"] --> GR["Gateway migration router"]

    BR --> LEGACY["Existing evaluators"]
    GR --> LEGACY
    BR --> AUTHZ["caipe-authz"]
    GR --> AUTHZ

    AUTHZ --> CONTEXT["Trusted context construction"]
    AUTHZ --> POLICY["Typed policy templates"]
    CONTEXT --> FGA["OpenFGA relationships + CEL"]
    POLICY --> FGA
    AUTHZ --> AUDIT["Durable audit outbox"]
    AUDIT --> AUDITSVC["Audit Service"]
    AUTHZ --> INSPECT["Sanitized inspection graph"]
    AUDITSVC --> UI["CAIPE admin comparison UI"]
    INSPECT --> UI
Loading
Layer Implementation
Universal authorization service One caipe-authz service
Application transport HTTP and batch HTTP
Gateway transport Envoy ext_authz gRPC
Relationship authorization OpenFGA
Conditional expressions OpenFGA-native CEL
Context construction Trusted and bounded inside caipe-authz
Policy authoring Typed, versioned templates; no caller-supplied CEL
Future providers Cedar and OPA extension points, disabled in v1
Persistence MongoDB policy metadata plus conditional OpenFGA tuples
Audit Transactional outbox and normalized Audit Service events

Parallel migration

BFF and gateway scopes move independently. A routing-mode change never writes or deletes OpenFGA tuples.

Mode Authoritative path Legacy behavior
LEGACY Existing evaluator Only path invoked
SHADOW Existing evaluator caipe-authz compared asynchronously
CANARY Deterministic per-subject cohort Non-canary traffic stays legacy-authoritative
AUTHZ caipe-authz Legacy remains available for comparison/rollback
AUTHZ_ONLY caipe-authz Legacy is not invoked

Promotion is blocked unless the scope has explicit evidence for:

  • OpenFGA model compatibility and trusted context-schema compatibility.
  • Audit delivery health, semantic parity, provider error rate, and latency SLOs.
  • A named owner and a compatible rollback release.
  • Required retention in AUTHZ_ONLY before legacy retirement.

Conditional-policy lifecycle

  1. Developers review named CEL conditions and typed template versions at build/release time.
  2. Administrators instantiate templates at policy-administration runtime.
  3. caipe-authz validates schema pins and reconciles condition constants on OpenFGA tuples.
  4. At request time, caipe-authz constructs bounded trusted context and OpenFGA evaluates the condition.

Expression enforcement stays unavailable until the exact caller and agent-tool scopes are Authz-authoritative and have an owner, pinned model descriptor, and trusted schema hash.

Safety and rollback invariants

  • The Helm and Compose deployment is disabled/dark by default.
  • A denied exact-tool request is rejected before the MCP server and is never forwarded.
  • Routing rollback changes only routing state; tuple snapshots remain identical.
  • Policy rollback removes only the targeted conditional policy tuple and does not recreate broad legacy grants.
  • AUTHZ_ONLY never calls the legacy evaluator.
  • Missing, malformed, oversized, type-invalid, or stale-schema expression context fails closed for the conditional grant without breaking an existing unconditional grant during parallel migration.
  • Raw argument values and condition constants are excluded from logs, audit events, fixtures, and graph responses.
  • Audit delivery uses an idempotent durable outbox; strict allow decisions fail closed if required audit persistence is unavailable.

Admin UI and inspection

The existing CAIPE admin surfaces now include:

  • Side-by-side legacy and caipe-authz decisions, reasons, provider codes, errors, and durations.
  • Filters for rollout revision, authoritative path, and mismatch class.
  • Evidence summaries for sample size, semantic parity, provider errors, and complete latency.
  • Graph layers for current conditional relationships, policy/relationship history, migration comparisons, rollout revisions, schema drift, exclusive policies, and shadow warnings.
  • Sanitized projections that show policy structure and revisions without exposing protected values.

Verification

  • Authorization/migration: 67 tests passed against pinned OpenFGA v1.15.1; 87.69% coverage.
  • Live migration: verified LEGACY → SHADOW → CANARY → AUTHZ → AUTHZ_ONLY, routing rollback, and policy rollback using a real caipe-authz gRPC server and OpenFGA container.
  • Gateway boundary: an in-process MCP recorder proves denied exact-tool calls never reach the MCP server.
  • OpenFGA bridge: 44 affected migration, gRPC, condition, and OpenFGA tests passed; one environment-gated test skipped outside its live job.
  • Audit Service: 44 tests passed.
  • CAIPE UI: 568 Jest suites / 6,872 tests passed; lint and production build passed.
  • Packaging: Helm lint, Compose rendering, authorization-service container build, OpenFGA model validation, Ruff, Actionlint, Docusaurus build, and git diff --check passed.
  • GitHub: DCO, CodeQL Actions, CodeQL Python, and CodeQL JavaScript/TypeScript checks pass; no unresolved code-quality threads.

The implementation also fixed two integration defects found by live testing: OpenFGA unfiltered reads no longer send an invalid empty tuple key, and read page sizes are capped at the server-supported limit.

Deliberately deferred

Physical removal of the legacy authorization paths is not part of this PR. It is permitted only after deployed scopes complete the AUTHZ_ONLY retention window and satisfy the rollback-release gate.

The remaining SpecKit items are:

  • T025–T029: dedicated contract/event test decomposition; the underlying behavior is covered by the integrated suites.
  • T071–T073: dedicated shadow simulation and effectiveness test decomposition.
  • T100–T102: legacy implementation removal after production retention criteria are met.

Type of Change

  • Bugfix
  • New Feature
  • Refactor
  • Documentation
  • Breaking Change
  • Other

Checklist

  • I have read the contributing guidelines.
  • Existing issues have been referenced; no issue was supplied.
  • I have verified this change is not present in another open pull request.
  • Functionality and operations are documented.
  • Applicable code-style checks pass.
  • New behavior is covered by automated tests.
  • Affected test suites pass.

Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ No proprietary content detected. This PR is clear for review!

Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
@sriaradhyula sriaradhyula changed the title docs(rbac): specify OpenFGA tool expression policies docs(authz): specify standalone CAS and expression policies Aug 17, 2026
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
@sriaradhyula sriaradhyula changed the title docs(authz): specify standalone CAS and expression policies docs(authz): specify caipe-authz and expression policies Aug 17, 2026
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
@sriaradhyula sriaradhyula changed the title docs(authz): specify caipe-authz and expression policies docs(authz): specify parallel caipe-authz migration Aug 18, 2026
Implement the first additive exact-tool expression-policy slice across the OpenFGA model, ext_authz bridge, deployment configuration, documentation, and real OpenFGA E2E coverage.

Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
@sriaradhyula sriaradhyula changed the title docs(authz): specify parallel caipe-authz migration feat(authz): add conditional tool policy evaluation Aug 18, 2026
Comment thread deploy/openfga/bridge/tests/test_conditions_e2e.py Fixed
@sriaradhyula
sriaradhyula marked this pull request as ready for review August 18, 2026 03:45
Document the intentional health-check retry that Code Quality flagged as an empty exception handler.

Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
@sriaradhyula sriaradhyula changed the title feat(authz): add conditional tool policy evaluation feat(authz): add standalone authorization service Aug 18, 2026
Comment thread ai_platform_engineering/authz/providers/base.py Fixed
Comment thread ai_platform_engineering/authz/providers/base.py Fixed
Comment thread ai_platform_engineering/authz/providers/base.py Fixed
Comment thread ai_platform_engineering/authz/providers/base.py Fixed
Comment thread ai_platform_engineering/authz/providers/base.py Fixed
Comment thread ai_platform_engineering/authz/providers/base.py Fixed
Comment thread ai_platform_engineering/authz/providers/base.py Fixed
Comment thread ai_platform_engineering/authz/main.py Fixed
Comment thread ai_platform_engineering/authz/policy/repository.py Fixed
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Comment thread ai_platform_engineering/authz/tests/integration/test_openfga_e2e.py Fixed
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Comment thread tests/authz/test_live_migration_sequence.py Fixed
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Signed-off-by: Sri Aradhyula <sraradhy@cisco.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

1 participant