From 1b96121528b0cdb62907bd100ed2211ae57b36f2 Mon Sep 17 00:00:00 2001 From: Mariusz Sabath Date: Fri, 28 Aug 2026 18:09:09 -0400 Subject: [PATCH 1/2] Docs: Fix weather-agent AuthBridge demo from a verified run Corrections found while running the demo end-to-end on Kind/macOS with Ollama: - Installer-Provided Resources: the per-workload rossoctl-keycloak-client-credentials- Secret is written at workload registration time, not install time. Stop presenting the "kubectl get secret | grep" as an install-time check (it returns nothing before Steps 1-2, which reads as a failure); point to Step 3. - Workload Type defaults to Sandbox in the UI, so the agent is a bare pod owned by a Sandbox CR, not a Deployment. Replace all deploy/weather-service exec/logs commands with label selectors / resolved pod name (deploy/... returns NotFound). - Step 6a: agent card name is "Weather Assistant"; note both /.well-known/agent-card.json and /.well-known/agent.json are served. - Step 6b/6c: actual error body is {"error":"auth.unauthorized",...,"plugin":"jwt-validation"}. - Prerequisites: make Ollama the default provider (easiest, no cloud key); OpenAI as the noted alternative. examples#173 (Ollama+crewai) is closed and did not affect the weather agent in this run. - Agent may bind :8001 depending on build; note it. Assisted-By: Claude (Anthropic AI) Signed-off-by: Mariusz Sabath --- authbridge/demos/weather-agent/demo-ui.md | 56 ++++++++++++++--------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/authbridge/demos/weather-agent/demo-ui.md b/authbridge/demos/weather-agent/demo-ui.md index 3646a19f..295e486b 100644 --- a/authbridge/demos/weather-agent/demo-ui.md +++ b/authbridge/demos/weather-agent/demo-ui.md @@ -94,10 +94,11 @@ including the Rossoctl UI. You should also have: - The Rossoctl UI running at `http://rossoctl-ui.localtest.me:8080` - An LLM provider — either: - - **Ollama** running locally with a model (e.g. `llama3.2:3b-instruct-fp16`), or - - **OpenAI API key** (recommended for most reliable results; see - [agent-examples#173](https://github.com/rossoctl/examples/issues/173) for - known Ollama + crewai compatibility issues) + - **Ollama** (default, easiest — no cloud key needed) running locally with the + model the agent expects: `ollama pull llama3.2:3b-instruct-fp16`, and an Ollama + server running (`ollama serve`), or + - **OpenAI API key** as an alternative (uses the `openai-secret` you configured at + install time in `deployments/envs/.secret_values.yaml`) --- @@ -111,13 +112,16 @@ passthrough; inbound JWT uses issuer/signature checks). current operator (v0.7.0) the operator registers Keycloak clients using its own **SPIFFE workload identity** (federated into Keycloak by the `rossoctl-operator-client-bootstrap` post-install job in the `keycloak` namespace), not an admin username/password Secret. -A `NotFound` for `keycloak-admin-secret` in **either** namespace is expected. Confirm -registration by the per-workload client credentials the operator writes instead: +A `NotFound` for `keycloak-admin-secret` in **either** namespace is expected. + +The operator writes one per-workload client-credentials Secret +(`rossoctl-keycloak-client-credentials-`) **when each workload registers** — +so at install time, before you deploy anything in Steps 1-2, this Secret does not +exist yet. That is expected, not a failure; you verify it in +[Step 3](#check-operator-managed-client-registration) after the agent is deployed. +To watch registrations as they happen once you start deploying: ```bash -# One Secret per registered workload: -kubectl get secret -n team1 | grep rossoctl-keycloak-client-credentials -# ...and/or watch the operator apply registrations: kubectl logs -n rossoctl-system deployment/rossoctl-controller-manager \ | grep "client registration applied" | tail ``` @@ -182,7 +186,9 @@ kubectl get pods -n team1 | grep weather-tool 5. **Protocol**: `A2A` -6. **Workload Type** select `Deployment`. +6. **Workload Type**: leave the default `Sandbox (recommended)`. The agent then + runs as a bare pod owned by a `Sandbox` CR (verify/exec commands below use a + label selector rather than `deploy/...` for this reason). 7. **Secure with AuthBridge** is checked by default for agents. Leave it checked. @@ -291,13 +297,19 @@ kubectl get pod -n team1 -l app.kubernetes.io/name=weather-service \ # Expect a Secret name starting with: rossoctl-keycloak-client-credentials- ``` +> **Note:** the UI defaults **Workload Type** to `Sandbox`, so the agent runs as a +> bare pod (owned by a `Sandbox` CR), not a `Deployment`. Address it by pod name or +> label selector — `kubectl exec deploy/weather-service ...` fails with `NotFound`. + Inspect the actual SPIFFE-derived client ID written to /shared/client-id.txt: ```bash -SIDECAR=$(kubectl get pod -n team1 -l app.kubernetes.io/name=weather-service \ - -o jsonpath='{.items[0].spec.containers[*].name}' | tr ' ' '\n' \ +AGENT_POD=$(kubectl get pod -n team1 -l app.kubernetes.io/name=weather-service \ + -o jsonpath='{.items[0].metadata.name}') +SIDECAR=$(kubectl get pod "$AGENT_POD" -n team1 \ + -o jsonpath='{.spec.containers[*].name}' | tr ' ' '\n' \ | grep -E '^(authbridge-proxy|envoy-proxy)$' | head -1) -kubectl exec deploy/weather-service -n team1 -c "$SIDECAR" -- cat /shared/client-id.txt +kubectl exec "$AGENT_POD" -n team1 -c "$SIDECAR" -- cat /shared/client-id.txt ``` Expected — just the SPIFFE ID (the `Created Keycloak client …` log line @@ -318,10 +330,10 @@ kubectl logs -n rossoctl-system deployment/rossoctl-controller-manager \ ### Check agent logs ```bash -kubectl logs deployment/weather-service -n team1 -c agent +kubectl logs -n team1 -l app.kubernetes.io/name=weather-service -c agent ``` -Expected: +Expected (the port may be 8000 or 8001 depending on the agent build): ``` INFO: Started server process [17] @@ -454,8 +466,10 @@ and `/livez` by default: ```bash kubectl exec test-client -n team1 -- curl -s \ - http://weather-service:8080/.well-known/agent.json | jq .name -# Expected: "weather_service" + http://weather-service:8080/.well-known/agent-card.json | jq .name +# Expected: "Weather Assistant" +# (Both /.well-known/agent-card.json and /.well-known/agent.json are served — +# the bypass matches the /.well-known/ prefix, not a specific filename.) ``` ### 6b. Inbound Rejection - No Token @@ -465,7 +479,7 @@ Non-public endpoints require a valid JWT: ```bash kubectl exec test-client -n team1 -- curl -s \ http://weather-service:8080/ -# Expected: {"error":"unauthorized","message":"missing Authorization header"} +# Expected: {"error":"auth.unauthorized","message":"missing Authorization header","plugin":"jwt-validation"} ``` ### 6c. Inbound Rejection - Invalid Token @@ -476,7 +490,7 @@ A malformed or tampered token fails the JWKS signature check: kubectl exec test-client -n team1 -- curl -s \ -H "Authorization: Bearer invalid-token" \ http://weather-service:8080/ -# Expected: {"error":"unauthorized","message":"token validation failed: failed to parse/validate token: ..."} +# Expected: {"error":"auth.unauthorized","message":"token validation failed","plugin":"jwt-validation"} ``` ### 6d. End-to-End Test with Valid Token @@ -550,10 +564,10 @@ Check the authbridge logs to confirm inbound validation is working: ```bash # For envoy-sidecar mode: -kubectl logs deployment/weather-service -n team1 -c envoy-proxy 2>&1 | grep "inbound authorized" +kubectl logs -n team1 -l app.kubernetes.io/name=weather-service -c envoy-proxy 2>&1 | grep "inbound authorized" # For proxy-sidecar mode: -kubectl logs deployment/weather-service -n team1 -c authbridge-proxy 2>&1 | grep "inbound authorized" +kubectl logs -n team1 -l app.kubernetes.io/name=weather-service -c authbridge-proxy 2>&1 | grep "inbound authorized" ``` Expected: From 3bd3e691f817d37639eb8c2eaf515d48f958341c Mon Sep 17 00:00:00 2001 From: Mariusz Sabath Date: Mon, 31 Aug 2026 13:48:31 -0400 Subject: [PATCH 2/2] =?UTF-8?q?Docs:=20Address=20review=20=E2=80=94=20Sand?= =?UTF-8?q?box=20commands=20and=20port=20ambiguity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to review on PR #818: - Convert remaining kubectl exec/logs commands from deploy/weather-service to label selectors / resolved pod name (Verify env vars, Troubleshooting logs, Debug Logging SIGUSR1). These are the exec/logs cases CodeRabbit and @esnible flagged that still targeted a Deployment. - Add a note before Step 4: kubectl set env / patch / rollout commands assume a Deployment and fail on a Sandbox-backed agent; edit the Sandbox CR or re-import instead. (Left those mutation commands as-is rather than ship unverified Sandbox equivalents.) - Reconcile the agent port ambiguity: drop 'may be 8000 or 8001' and instead tell users to set the Pod Configuration Target Port to whatever port the agent log actually shows, so it matches Step 9's 8080->target mapping. - Reconcile the OpenAI secret prerequisite with Step 2: openai-secret comes either from install-time .secret_values.yaml or the manual Step 2 note. Assisted-By: Claude (Anthropic AI) Signed-off-by: Mariusz Sabath --- authbridge/demos/weather-agent/demo-ui.md | 37 ++++++++++++++++++----- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/authbridge/demos/weather-agent/demo-ui.md b/authbridge/demos/weather-agent/demo-ui.md index 295e486b..ba2e597b 100644 --- a/authbridge/demos/weather-agent/demo-ui.md +++ b/authbridge/demos/weather-agent/demo-ui.md @@ -97,8 +97,10 @@ You should also have: - **Ollama** (default, easiest — no cloud key needed) running locally with the model the agent expects: `ollama pull llama3.2:3b-instruct-fp16`, and an Ollama server running (`ollama serve`), or - - **OpenAI API key** as an alternative (uses the `openai-secret` you configured at - install time in `deployments/envs/.secret_values.yaml`) + - **OpenAI API key** as an alternative, provided via a `team1` Secret named + `openai-secret`. This is created either at install time (from + `deployments/envs/.secret_values.yaml`) or manually in Step 2 — see the + OpenAI prerequisite note there. --- @@ -333,7 +335,7 @@ kubectl logs -n rossoctl-system deployment/rossoctl-controller-manager \ kubectl logs -n team1 -l app.kubernetes.io/name=weather-service -c agent ``` -Expected (the port may be 8000 or 8001 depending on the agent build): +Expected: ``` INFO: Started server process [17] @@ -342,6 +344,13 @@ INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit) ``` +> **Check the bound port matches the target port.** Step 9 maps the service's +> target port to `8000`. Some agent builds bind Uvicorn on a different port +> (e.g. `8001`). If the log line above shows a port other than `8000`, the +> `weather-service:8080` requests below will not reach the agent — go back to +> **Pod Configuration** and set the **Target Port** to the port actually shown +> in the log. + ### Check the service endpoint ```bash @@ -363,6 +372,15 @@ The service maps **port 8080** to the agent's internal port 8000. The agent uses an LLM for inference. Follow the section that matches your chosen provider. +> **If your agent runs as a `Sandbox` (the UI default):** the +> `kubectl set env deployment/...`, `kubectl patch deployment ...`, and +> `kubectl rollout restart|status deployment/...` commands in the sections below +> assume a `Deployment` and will fail with `NotFound`. To change env vars or +> restart a Sandbox-backed agent, edit the `Sandbox` CR's pod template +> (`kubectl edit sandbox weather-service -n team1`) or re-import via the UI. +> The `kubectl exec`/`kubectl logs` commands work as written (they use a label +> selector / resolved pod name). + ### Option A: Ollama (local models) Verify Ollama is running: @@ -412,7 +430,7 @@ kubectl get secret openai-secret -n team1 Verify the agent has the correct environment variables: ```bash -kubectl exec deployment/weather-service -n team1 -c agent -- env | grep -E "LLM_|OPENAI" +kubectl exec -n team1 "$(kubectl get pod -n team1 -l app.kubernetes.io/name=weather-service -o jsonpath='{.items[0].metadata.name}')" -c agent -- env | grep -E "LLM_|OPENAI" ``` Expected: @@ -671,8 +689,8 @@ as described there). # AuthBridge sidecar — name depends on resolved mode: # proxy-sidecar (default): authbridge-proxy # envoy-sidecar: envoy-proxy -kubectl logs deployment/weather-service -n team1 -c authbridge-proxy -kubectl logs deployment/weather-service -n team1 -c agent +kubectl logs -n team1 -l app.kubernetes.io/name=weather-service -c authbridge-proxy +kubectl logs -n team1 -l app.kubernetes.io/name=weather-service -c agent # If the issue is operator-managed client registration not finishing, # the workload pod waits on /shared/client-{id,secret}.txt. Inspect: @@ -759,12 +777,15 @@ Send `SIGUSR1` to the authbridge process. The container image is minimal (no standalone `kill` or `grep` binaries), so use bash builtins to locate the PID: ```bash +AGENT_POD=$(kubectl get pod -n team1 -l app.kubernetes.io/name=weather-service \ + -o jsonpath='{.items[0].metadata.name}') + # For envoy-sidecar mode: -kubectl exec deploy/weather-service -n team1 -c envoy-proxy -- \ +kubectl exec "$AGENT_POD" -n team1 -c envoy-proxy -- \ bash -c 'for f in /proc/[0-9]*/cmdline; do [ -r "$f" ] || continue; c=$(<"$f"); [[ "$c" == /usr/local/bin/authbridge* ]] && kill -USR1 "${f//[!0-9]/}" && break; done' # For proxy-sidecar mode: -kubectl exec deploy/weather-service -n team1 -c authbridge-proxy -- \ +kubectl exec "$AGENT_POD" -n team1 -c authbridge-proxy -- \ bash -c 'for f in /proc/[0-9]*/cmdline; do [ -r "$f" ] || continue; c=$(<"$f"); [[ "$c" == /usr/local/bin/authbridge* ]] && kill -USR1 "${f//[!0-9]/}" && break; done' ```