Skip to content

Commit 4230ba6

Browse files
committed
Docs: update documentation and samples for VAP enforcement
Remove manual kagenti.io/type labeling from docs, samples, and comments. All examples now use AgentRuntime CRs, matching the ValidatingAdmissionPolicy that prevents direct label application. Fix auto-created AgentCard naming to use the {name}-{kind}-card pattern produced by AgentCardSync. Signed-off-by: Daniels Nagornuks <dnagornu@redhat.com>
1 parent 57f9f19 commit 4230ba6

10 files changed

Lines changed: 79 additions & 143 deletions

File tree

kagenti-operator/GETTING_STARTED.md

Lines changed: 19 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,14 @@ This scenario demonstrates the complete lifecycle of an AI agent deployment on t
4040
## Overview
4141
4242
### Kagenti Operator
43-
The Kagenti Operator discovers, indexes, and secures AI agents deployed in Kubernetes. There are two ways to enroll workloads:
43+
The Kagenti Operator discovers, indexes, and secures AI agents deployed in Kubernetes. Enroll workloads by creating an `AgentRuntime` CR:
4444

45-
1. **AgentRuntime CR (Recommended)** — Create a Deployment with a `protocol.kagenti.io/a2a` label and an `AgentRuntime` CR pointing to it. The controller applies `kagenti.io/type` labels and triggers sidecar injection automatically. The protocol label enables automatic AgentCard creation for agent discovery.
46-
2. **Manual labels** — Add the `kagenti.io/type: agent` label directly to your Deployment or StatefulSet. This is simpler for quick tests but does not provide identity or observability configuration.
45+
1. Create a Deployment with a `protocol.kagenti.io/a2a` label
46+
2. Create an `AgentRuntime` CR pointing to it
47+
3. The controller applies `kagenti.io/type` labels and triggers sidecar injection automatically
48+
4. The protocol label enables automatic AgentCard creation for agent discovery
49+
50+
A `ValidatingAdmissionPolicy` prevents the `kagenti.io/type` label from being set directly on Deployments or StatefulSets — it can only be applied by the operator via an AgentRuntime CR.
4751

4852
> **Note:** The `Agent` Custom Resource is deprecated and will be removed in a future release.
4953

@@ -180,86 +184,6 @@ kubectl delete agentruntime weather-agent-runtime -n team1
180184

181185
---
182186

183-
## Deploy an Agent with Manual Labels (Alternative)
184-
185-
Deploy an agent as a standard Kubernetes Deployment with the required `kagenti.io/type: agent` label. The operator will automatically discover the workload and create an AgentCard for it. This approach does not provide AgentRuntime's identity or observability configuration.
186-
187-
### Quick Example Deployment
188-
189-
```yaml
190-
kubectl apply -f - <<EOF
191-
apiVersion: apps/v1
192-
kind: Deployment
193-
metadata:
194-
name: weather-agent
195-
namespace: team1
196-
labels:
197-
app.kubernetes.io/name: weather-agent
198-
kagenti.io/type: agent
199-
protocol.kagenti.io/a2a: ""
200-
kagenti.io/framework: LangGraph
201-
spec:
202-
replicas: 1
203-
selector:
204-
matchLabels:
205-
app.kubernetes.io/name: weather-agent
206-
template:
207-
metadata:
208-
labels:
209-
app.kubernetes.io/name: weather-agent
210-
kagenti.io/type: agent
211-
spec:
212-
containers:
213-
- name: agent
214-
image: "ghcr.io/kagenti/agent-examples/weather_service:v0.0.1-alpha.3"
215-
ports:
216-
- containerPort: 8000
217-
imagePullPolicy: Always
218-
env:
219-
- name: PORT
220-
value: "8000"
221-
- name: UV_CACHE_DIR
222-
value: /app/.cache/uv
223-
- name: MCP_URL
224-
value: http://weather-tool-mcp.team1.svc.cluster.local:8000/mcp
225-
- name: LLM_API_BASE
226-
value: http://host.docker.internal:11434/v1
227-
- name: LLM_API_KEY
228-
value: dummy
229-
- name: LLM_MODEL
230-
value: llama3.2:3b-instruct-fp16
231-
---
232-
apiVersion: v1
233-
kind: Service
234-
metadata:
235-
name: weather-agent
236-
namespace: team1
237-
spec:
238-
selector:
239-
app.kubernetes.io/name: weather-agent
240-
ports:
241-
- name: http
242-
port: 8000
243-
targetPort: 8000
244-
EOF
245-
246-
```
247-
248-
**Check Status**:
249-
```bash
250-
251-
# Check discovered agent cards
252-
kubectl get agentcards -n team1
253-
254-
# Check deployment status
255-
kubectl get deployment weather-agent -n team1
256-
257-
# View logs
258-
kubectl logs -l app.kubernetes.io/name=weather-agent -n team1
259-
```
260-
261-
---
262-
263187
## Deploy an MCP Server
264188

265189
MCP (Model Context Protocol) servers provide tools and resources that your agents can use. Deploy an MCP server after your agent is running.
@@ -273,18 +197,15 @@ metadata:
273197
name: weather-tool
274198
labels:
275199
app.kubernetes.io/name: weather-tool
276-
kagenti.io/type: tool
277200
spec:
278201
replicas: 1
279202
selector:
280203
matchLabels:
281204
app.kubernetes.io/name: weather-tool
282-
kagenti.io/type: tool
283205
template:
284206
metadata:
285207
labels:
286208
app.kubernetes.io/name: weather-tool
287-
kagenti.io/type: tool
288209
spec:
289210
containers:
290211
- name: mcp
@@ -306,6 +227,18 @@ spec:
306227
- name: cache
307228
emptyDir: {}
308229
---
230+
apiVersion: agent.kagenti.dev/v1alpha1
231+
kind: AgentRuntime
232+
metadata:
233+
name: weather-tool
234+
namespace: team1
235+
spec:
236+
type: tool
237+
targetRef:
238+
apiVersion: apps/v1
239+
kind: Deployment
240+
name: weather-tool
241+
---
309242
apiVersion: v1
310243
kind: Service
311244
metadata:
@@ -315,7 +248,6 @@ metadata:
315248
app.kubernetes.io/name: weather-service
316249
kagenti.io/framework: LangGraph
317250
kagenti.io/inject: enabled
318-
kagenti.io/type: agent
319251
kagenti.io/workload-type: deployment
320252
protocol.kagenti.io/a2a: ""
321253
name: weather-service

kagenti-operator/config/samples/agent_v1alpha1_agentruntime_skill_discovery.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ metadata:
2929
name: my-agent
3030
labels:
3131
app.kubernetes.io/name: my-agent
32-
kagenti.io/type: agent
3332
protocol.kagenti.io/a2a: ""
3433
annotations:
3534
kagenti.io/skills: '["openshift-review"]'

kagenti-operator/demos/agentcard-spire-signing/k8s/agent-deployment.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,10 @@ spec:
6969
selector:
7070
matchLabels:
7171
app.kubernetes.io/name: weather-agent
72-
kagenti.io/type: agent
7372
template:
7473
metadata:
7574
labels:
7675
app.kubernetes.io/name: weather-agent
77-
kagenti.io/type: agent
7876
protocol.kagenti.io/a2a: ""
7977
istio.io/dataplane-mode: none
8078
spec:

kagenti-operator/docs/api-reference.md

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,9 @@ Represents the A2A agent card structure based on the [A2A specification](https:/
149149

150150
### Examples
151151

152-
#### Deploy Agent as a Standard Deployment (Recommended)
152+
#### Deploy Agent with AgentRuntime (Recommended)
153153

154-
Create a standard Deployment with agent labels, and an AgentCard with `targetRef`:
154+
Create a Deployment with a protocol label and an `AgentRuntime` CR to enroll it. The operator applies `kagenti.io/type: agent` to the Deployment, and the AgentCardSync controller auto-creates an AgentCard named `weather-agent-deployment-card` (pattern: `{name}-{kind}-card`):
155155

156156
```yaml
157157
apiVersion: apps/v1
@@ -161,7 +161,6 @@ metadata:
161161
namespace: default
162162
labels:
163163
app.kubernetes.io/name: weather-agent
164-
kagenti.io/type: agent
165164
protocol.kagenti.io/a2a: ""
166165
spec:
167166
replicas: 1
@@ -183,25 +182,27 @@ spec:
183182
value: "8000"
184183
---
185184
apiVersion: agent.kagenti.dev/v1alpha1
186-
kind: AgentCard
185+
kind: AgentRuntime
187186
metadata:
188-
name: weather-agent-card
187+
name: weather-agent
189188
namespace: default
190189
spec:
191-
syncPeriod: 30s
190+
type: agent
192191
targetRef:
193192
apiVersion: apps/v1
194193
kind: Deployment
195194
name: weather-agent
196195
```
197196
198-
#### AgentCard with Identity Binding
197+
#### Manual AgentCard with Identity Binding
198+
199+
If you need `identityBinding.strict: true` (enforcement mode), create the AgentCard before the workload is labeled. The sync controller will skip auto-creation when it finds an existing card targeting the same workload:
199200

200201
```yaml
201202
apiVersion: agent.kagenti.dev/v1alpha1
202203
kind: AgentCard
203204
metadata:
204-
name: weather-agent-card
205+
name: weather-agent-deployment-card
205206
namespace: default
206207
spec:
207208
syncPeriod: "30s"
@@ -213,8 +214,6 @@ spec:
213214
strict: true
214215
```
215216

216-
The AgentCard can also be automatically created by the operator when agent labels are present on the Deployment.
217-
218217
#### View Discovered Agents
219218

220219
```bash
@@ -308,23 +307,23 @@ status:
308307

309308
```bash
310309
# Get agent name from card
311-
kubectl get agentcard weather-agent-card \
310+
kubectl get agentcard weather-agent-deployment-card \
312311
-o jsonpath='{.status.card.name}'
313312
314313
# List all skills
315-
kubectl get agentcard weather-agent-card \
314+
kubectl get agentcard weather-agent-deployment-card \
316315
-o jsonpath='{.status.card.skills[*].name}'
317316
318317
# Get agent endpoint
319-
kubectl get agentcard weather-agent-card \
318+
kubectl get agentcard weather-agent-deployment-card \
320319
-o jsonpath='{.status.card.url}'
321320
322321
# Check signature verification
323-
kubectl get agentcard weather-agent-card \
322+
kubectl get agentcard weather-agent-deployment-card \
324323
-o jsonpath='{.status.validSignature}'
325324
326325
# Check identity binding
327-
kubectl get agentcard weather-agent-card \
326+
kubectl get agentcard weather-agent-deployment-card \
328327
-o jsonpath='{.status.bindingStatus.bound}'
329328
```
330329

@@ -366,13 +365,13 @@ spec:
366365

367366
## Required Labels for Workload-Based Agents
368367

369-
For Deployments and StatefulSets to be automatically discovered by the operator, the following labels are required:
368+
For Deployments and StatefulSets to be automatically discovered by the operator, the following labels are needed on the workload. `kagenti.io/type` is applied by the operator via an AgentRuntime CR (a `ValidatingAdmissionPolicy` prevents setting it directly). Protocol labels are set by the user:
370369

371-
| Label | Value | Required | Description |
372-
|-------|-------|----------|-------------|
373-
| `kagenti.io/type` | `agent` | Yes | Identifies the workload as an agent |
374-
| `protocol.kagenti.io/<name>` | `""` (existence implies support) | Yes (at least one) | Protocol(s) the agent speaks (e.g., `protocol.kagenti.io/a2a`, `protocol.kagenti.io/mcp`) |
375-
| `app.kubernetes.io/name` | `<agent-name>` | Recommended | Standard Kubernetes app name label |
370+
| Label | Value | Set By | Description |
371+
|-------|-------|--------|-------------|
372+
| `kagenti.io/type` | `agent` or `tool` | Operator (via AgentRuntime) | Classifies the workload. Applied automatically when an AgentRuntime CR targets it. |
373+
| `protocol.kagenti.io/<name>` | `""` (existence implies support) | User | Protocol(s) the agent speaks (e.g., `protocol.kagenti.io/a2a`, `protocol.kagenti.io/mcp`). Required for AgentCard auto-creation. |
374+
| `app.kubernetes.io/name` | `<agent-name>` | User | Standard Kubernetes app name label (recommended) |
376375

377376
---
378377

kagenti-operator/docs/controller-webhook-interaction.md

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ The webhook performs its own merge at Pod CREATE time, including CR overrides, t
160160
161161
## Global and Cluster Configuration
162162

163-
When workloads are deployed with the right labels (`kagenti.io/type: agent` or `tool`), the webhook uses two levels of global configuration regardless of whether an AgentRuntime CR exists:
163+
When workloads have the `kagenti.io/type` label (applied by the operator via an AgentRuntime CR), the webhook uses two levels of global configuration:
164164

165165
### PlatformConfig (Global Defaults)
166166

@@ -195,17 +195,9 @@ When `perWorkloadConfigResolution` is **false** (default), the webhook builds si
195195

196196
When `perWorkloadConfigResolution` is **true**, the webhook resolves all config values at admission time by reading namespace ConfigMaps and AgentRuntime CR overrides, then injects literal environment variable values into the sidecar containers.
197197

198-
## Defaults-Only Path (No AgentRuntime CR)
198+
## AgentRuntime Required — Admission Policy
199199

200-
When a workload has `kagenti.io/type` labels applied manually (without an AgentRuntime CR):
201-
202-
- The webhook still evaluates the workload for injection using PlatformConfig and feature gates
203-
- Configuration comes from PlatformConfig (layer 1) and namespace ConfigMaps (layer 2) only
204-
- No controller manages the config hash — configuration drift is not detected automatically, and changes to cluster/namespace defaults do not trigger rolling updates
205-
- The controller does not watch or reconcile these workloads
206-
- Per-workload identity (SPIFFE trust domain) overrides are not available
207-
208-
The AgentRuntime CR is the recommended approach because it provides:
200+
A `ValidatingAdmissionPolicy` prevents the `kagenti.io/type` label from being set directly on Deployments or StatefulSets. Only the operator's service account (via the AgentRuntime controller) can apply this label. This ensures every enrolled workload has a corresponding AgentRuntime CR, which provides:
209201
- Automatic rolling updates on config change (any layer)
210202
- Per-workload identity overrides
211203
- Status reporting (phase, conditions, configured pod count)

kagenti-operator/docs/dynamic-agent-discovery.md

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,39 @@ Exposes /.well-known/ Enables kubectl get agentcards
4040

4141
## How It Works
4242

43-
### 1. Workload Labeling
43+
### 1. Workload Enrollment via AgentRuntime
4444

45-
Agent workloads (Deployments or StatefulSets) must be labeled to enable discovery:
45+
Agent workloads (Deployments or StatefulSets) are enrolled by creating an `AgentRuntime` CR. The operator's controller applies the `kagenti.io/type` label automatically — a `ValidatingAdmissionPolicy` prevents setting it directly on workloads.
46+
47+
The workload itself carries a protocol label to declare which protocol it speaks:
4648

4749
```yaml
4850
apiVersion: apps/v1
4951
kind: Deployment
5052
metadata:
5153
name: weather-agent
5254
labels:
53-
kagenti.io/type: agent # Identifies as an agent
5455
protocol.kagenti.io/a2a: "" # Speaks A2A protocol
5556
app.kubernetes.io/name: weather-agent
5657
spec:
5758
# ... standard Deployment spec
59+
---
60+
apiVersion: agent.kagenti.dev/v1alpha1
61+
kind: AgentRuntime
62+
metadata:
63+
name: weather-agent
64+
spec:
65+
type: agent
66+
targetRef:
67+
apiVersion: apps/v1
68+
kind: Deployment
69+
name: weather-agent
5870
```
5971
60-
Multiple protocols can be declared simultaneously:
72+
Multiple protocols can be declared simultaneously on the Deployment:
6173
6274
```yaml
6375
labels:
64-
kagenti.io/type: agent
6576
protocol.kagenti.io/a2a: "" # Speaks A2A
6677
protocol.kagenti.io/mcp: "" # Also speaks MCP
6778
```
@@ -204,7 +215,6 @@ kind: Deployment
204215
metadata:
205216
name: assistant-agent
206217
labels:
207-
kagenti.io/type: agent
208218
protocol.kagenti.io/a2a: ""
209219
app.kubernetes.io/name: assistant-agent
210220
spec:
@@ -234,9 +244,20 @@ spec:
234244
- name: http
235245
port: 8000
236246
targetPort: 8000
247+
---
248+
apiVersion: agent.kagenti.dev/v1alpha1
249+
kind: AgentRuntime
250+
metadata:
251+
name: assistant-agent
252+
spec:
253+
type: agent
254+
targetRef:
255+
apiVersion: apps/v1
256+
kind: Deployment
257+
name: assistant-agent
237258
```
238259

239-
The AgentCard is created automatically by the AgentCardSync controller when agent labels are present, or can be created explicitly with `targetRef`.
260+
The operator applies the `kagenti.io/type: agent` label to the Deployment, and the AgentCard is created automatically by the AgentCardSync controller when both `kagenti.io/type` and a protocol label are present.
240261

241262
### Query Agent Cards
242263

kagenti-operator/docs/operator-managed-client-registration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ Other workloads are ignored by this controller.
104104
### 3.2 Workload
105105

106106
- **Deployment** or **StatefulSet** (not bare Pods for operator ownership of Secrets).
107-
- Pod template labels: `kagenti.io/type: agent` or `tool` (subject to `injectTools`). Do **not** set `kagenti.io/client-registration-inject: "true"` unless you require the legacy sidecar.
107+
- An **AgentRuntime** CR targeting the workload — the operator applies `kagenti.io/type` to the Deployment/StatefulSet and its PodTemplateSpec (a `ValidatingAdmissionPolicy` prevents manual application). Do **not** set `kagenti.io/client-registration-inject: "true"` unless you require the legacy sidecar.
108108
- For **SPIRE-enabled** namespaces: `spec.template.spec.serviceAccountName` must be a **dedicated** ServiceAccount (not `default`).
109109

110110
### 3.3 Operator configuration

0 commit comments

Comments
 (0)