Skip to content

Clarify AgentCube authentication and authorization model #441

Description

@acsoto

Background

AgentCube currently has several authentication and authorization mechanisms at different boundaries: external OIDC at Router, optional Kubernetes ServiceAccount authentication and SPIFFE mTLS between control-plane components, Router-signed identity assertions, Router-signed sandbox JWTs, and session ownership checks.

These mechanisms were introduced at different times, and we do not yet have one shared description of the overall model: who authenticates whom, which identity authorizes an operation, and which Kubernetes identity ultimately executes it.

This became visible in PR #433. Enabling the existing WorkloadManager auth path did more than authenticate Router: WM also started using Router's ServiceAccount token as its Kubernetes client credential. As a result, Router needed create/delete permissions for Sandboxes and SandboxClaims, potentially across namespaces. It was unclear whether this permission expansion matched the intended architecture.

Before addressing #432 or reopening #433, it would be useful to first align on the current and intended auth model.

Current auth flow

Solid arrows are used in the normal request path. Dashed arrows are optional or configuration-dependent.

flowchart LR
    Client["External client / SDK"]
    IdP["OIDC provider"]
    Router["Router"]
    WM["WorkloadManager"]
    K8s["Kubernetes API"]
    Store["Redis / Valkey"]
    Sandbox["Sandbox / PicoD"]

    Client -.->|"OAuth2 token acquisition"| IdP
    IdP -.->|"OIDC access token"| Client

    Client -->|"Bearer OIDC JWT<br/>optional"| Router
    Router -->|"signature + issuer + audience<br/>role + OwnerID"| Router

    Router -->|"Router ServiceAccount token"| WM
    Router -.->|"optional SPIFFE mTLS"| WM
    Router -->|"Router-signed user identity JWT"| WM

    WM -->|"TokenReview when EnableAuth=true"| K8s
    WM -->|"authenticated caller token<br/>used as K8s client credential"| K8s
    WM -.->|"when EnableAuth=false:<br/>WM ServiceAccount credential"| K8s

    Router -->|"Router-signed JWT<br/>session_id + optional user_sub"| Sandbox
    WM -->|"inject Router public key"| Sandbox

    Router <--> Store
    WM <--> Store
Loading

Some relevant current behavior:

  • Router OIDC auth is disabled unless an issuer is configured.
  • WorkloadManager supports TokenReview auth, but the base chart does not currently enable it.
  • When WM auth is enabled, authentication and Kubernetes credential delegation happen together.
  • AgentRuntime session creation goes through Router, while the Python CodeInterpreter client creates and deletes sessions by calling WM directly.
  • Router enforces ownership when invoking existing sessions, while other lifecycle operations do not necessarily use the same ownership check.
  • Router-to-WM mTLS and Router-to-sandbox JWT authentication are separate, optional mechanisms with their own identity and key assumptions.

Why this needs discussion

The current implementation leaves multiple reasonable interpretations of the intended architecture. For example, WM could authenticate Router and continue operating with its own ServiceAccount, or it could intentionally execute with a delegated caller credential. Likewise, WM could be an internal service used only by Router, or a supported API for external SDK clients. Those choices lead to very different RBAC, namespace, ownership, and compatibility requirements.

This issue is not intended to propose a complete solution. The goal is to verify whether the diagram above accurately represents the current system and to establish a shared high-level model before making further auth or RBAC changes.

In particular, it would be helpful to align on the external API boundary, the distinction between authenticated identity and Kubernetes execution identity, and where namespace and session ownership authorization should live. Once those boundaries are clear, follow-up changes can be split into focused and independently reviewable issues.

Related: #432, #433.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions