Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
This split is deliberate, not an implementation detail to work around:

- Applying a Harness, AgentTemplate, or Agent is a **Kubernetes-native operation**, governed by Kubernetes RBAC, exactly like any other CRD.
- Creating, suspending, resuming, sharing, or deleting a Session, and holding a conversation with it, are **kagent-native operations**, governed by kagent's own gRPC authentication and authorization, independent of who can `kubectl apply` an Agent.
- Creating, sharing, or deleting a Session, and holding a conversation with that Session, are **kagent-native operations**, governed by kagent's own gRPC authentication and authorization, independent of who can `kubectl apply` an Agent.
4 changes: 2 additions & 2 deletions docs-site/content/kagent/1.x/about/architecture/kagent.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The previous page defined the [core concepts]({{< link path="about/core-concepts
kagent 1.0 splits authorization across two planes:

- The **Kubernetes plane** governs the {{< gloss "Harness" >}}Harness{{< /gloss >}} and {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} custom resources. Kubernetes Role-Based Access Control (RBAC) decides who can create, read, or edit the resources with `kubectl`, exactly as it would for any other Custom Resource Definition (CRD).
- The **kagent control plane** governs any interactions involving {{< gloss "Session" >}}Sessions{{< /gloss >}}, such as creating, suspending, resuming, sharing, deleting, and holding a conversation with a Session. kagent's own gRPC authentication and authorization decide who can complete these interactions, independent of Kubernetes RBAC.
- The **kagent control plane** governs any interactions involving {{< gloss "Session" >}}Sessions{{< /gloss >}}, such as creating, sharing, or deleting a Session, or holding a conversation with one. kagent's own gRPC authentication and authorization decide who can complete these interactions, independent of Kubernetes RBAC.

Someone with Kubernetes RBAC access to apply an Agent and the resources it names does not automatically have access to create or talk to Sessions on it. The separation runs in one direction only. kagent's gRPC API also writes those Kubernetes resources, so a caller on the kagent control plane reaches both planes. For more information on that second path, see [Identity]({{< link path="about/substrate-runtime/identity#the-kubernetes-plane" >}}).

Expand Down Expand Up @@ -74,6 +74,6 @@ From there, the caller holds a conversation over the {{< gloss "A2A" >}}A2A{{< /

## Why two planes

Kubernetes RBAC is designed to authorize configuration changes: who can create a Deployment, edit a ConfigMap, or in this case, apply a Harness, an AgentTemplate, or an Agent. It is not designed to authorize a running conversation, share access to it with another user, or scope who can suspend it. kagent's gRPC plane exists to authorize exactly those actions, at the granularity of a single Session rather than a namespace or a resource kind.
Kubernetes RBAC is designed to authorize configuration changes: who can create a Deployment, edit a ConfigMap, or in this case, apply a Harness, an AgentTemplate, or an Agent. It is not designed to authorize a running conversation, share access to it with another user, or scope who can read, rename, or delete it. kagent's gRPC plane exists to authorize exactly those actions, at the granularity of a single Session rather than a namespace or a resource kind.

This split also keeps the two lifecycles independent. Editing an Agent, or either resource it names, does not affect Sessions already running against the ActorTemplate that they were created from. It only affects new Sessions, created after the edit is compiled.
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,14 @@ The `config.server.auth.mode` Helm value selects which authenticator the control
| Mode | How a principal is resolved |
| ---- | --------------------------- |
| `insecure` | Every request is admitted. The caller's identity is read from the `X-User-Id` header, or from a `user_id` query parameter that takes precedence over it. A caller that supplies neither is named `admin@kagent.dev`. |
| `trusted-proxy` | The request must carry a bearer token in the `Authorization` header. The identity comes from the claim that `config.server.auth.userIdClaim` names, defaulting to `sub`. A missing custom claim falls back to `sub`, and a request with no identity is rejected. |
| `trusted-proxy` | The request must carry a bearer token in the `Authorization` header. The identity comes from the claim that `config.server.auth.userIdClaim` names, defaulting to `sub`. A missing custom claim falls back to `sub`, and a request with no identity is rejected. The resulting `Principal.ID` is an opaque value that includes the issuer and selected subject. |

Any other value fails controller startup rather than falling back to a default.

Set `config.server.auth.serviceAccount.authority` to let machine callers authenticate with Kubernetes ServiceAccount tokens. The controller checks the bearer token with the local TokenReview API and the `kagent-invocation` audience. The resulting `Principal.ID` combines the configured authority and the verified ServiceAccount UID. Token rotation keeps the same identity, and recreating the ServiceAccount changes it.

> [!WARNING]
> **`trusted-proxy` decodes the token without verifying it.** The authenticator reads the bearer token's payload and checks neither its signature nor its expiry, because it assumes that an upstream boundary already validated the credential. A caller that reaches the controller directly can therefore present a token that it wrote itself. This mode is safe only where ingress validates every token before forwarding it, and network policy stops anything else from reaching port `8083`.
> **`trusted-proxy` parses token claims without verifying the signature.** The authenticator rejects a malformed or expired `exp` claim when the token has one, but it still assumes that an upstream boundary validated the signature, issuer, audience, and other required claims. A caller that reaches the controller directly can therefore present a token that it wrote itself. This mode is safe only where ingress validates every token before forwarding it, and network policy stops anything else from reaching port `8083`.

> [!WARNING]
> **`insecure` lets a caller select its own principal.** It verifies neither the header nor the query parameter, and the same authenticator guards the controller's `/mcp` endpoint. Treat the principal on a call as a label that the caller chose, and restrict network access to both endpoints rather than relying on it.
Expand Down Expand Up @@ -87,6 +89,8 @@ The runtime, the Agent Substrate egress gateway, and the controller each take on

An authenticated Actor can read its own Agent and use its own task state and memories. The Actor can also read, update, and send messages to its own Session. The Actor cannot create or delete a Session, use a share, reach any other Session, or act with its owner's permissions. That restriction includes other Sessions of the same agent and the same owner.

A verified runtime token creates a principal with a `RuntimeBinding` to the current Session. `Principal.ID` identifies the Actor. `RuntimeBinding.CreatorID` selects the Session's data partition. The binding does not grant the creator's permissions.

The controller trusts the issuer in the `config.substrate.actorJwtIssuer` Helm value, which must match the `ateApi.actorJWTIssuer` value of the Agent Substrate chart. Both values default to `https://idp.ate-system.svc`, so change them only together. The controller fetches the issuer's signing keys at startup, and a controller that cannot reach the issuer does not start.

Upgrade the controller and the runtime images together. An Actor snapshot from an earlier runtime image still sends an identity header that the controller no longer accepts, so you must recreate that snapshot after an upgrade.
Expand Down
2 changes: 2 additions & 0 deletions docs-site/content/kagent/1.x/observability/launch-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ The **Agents** tab authors the Agent custom resource directly. Create one to pai

Opening an agent and sending a message creates a {{< gloss "Session" >}}Session{{< /gloss >}}, which is one conversation scheduled onto an Agent Substrate {{< gloss "Actor" >}}Actor{{< /gloss >}}. The conversation view shows the transcript, the tool calls the agent made along the way, and the checkpoint controls for the conversation.

The UI does not offer suspend or resume controls for a conversation. After a turn, the Actor gives back its capacity, and the next message wakes the Actor while the Session remains ready. When the UI shows who started a conversation, it shows the opaque creator ID from controller authentication rather than a display name.

{{< reuse-image-light src="img/kagent-ui-chat.png" alt="A conversation with an agent, showing a named snapshot and the controls on its mark" caption="Figure: A conversation with an agent" >}}
{{< reuse-image-dark srcDark="img/kagent-ui-chat-dark.png" alt="A conversation with an agent, showing a named snapshot and the controls on its mark" caption="Figure: A conversation with an agent" >}}

Expand Down