023a89bf71
catalog-agent was one rename too aggressive: 'catalogue' is accepted, and the Keycloak client, its audience scope and the Vault key that names it were never renamed to match — leaving an inconsistency between what Kubernetes and Keycloak call the same agent. Keycloak carries more weight to move, so this side moves back. k8s/namespace.yaml is out of this Kustomization's inventory. It was in 2026-08-31 when renaming the Kustomization pruned the old one — which owned the namespace three agents share — and took all three down. A namespace shared across repos should not be owned by any one of them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
71 lines
2.6 KiB
YAML
71 lines
2.6 KiB
YAML
# Reaching this agent from outside the cluster.
|
|
#
|
|
# Until now nothing did: an agent answered only what could call its Service, so
|
|
# every conversation with it went through `kubectl run curl`. An orchestrator
|
|
# nobody can talk to is not finished.
|
|
#
|
|
# Peer traffic does **not** come through here — this agent calls, and is called by,
|
|
# other agents on their in-cluster Service names. This is the human door.
|
|
#
|
|
# ## It is not an open door
|
|
#
|
|
# A2A carries the end user's token in `Authorization`, and this agent forwards it
|
|
# and exchanges it; a forged one fails at the realm. But "fails downstream" is
|
|
# not the same as "refused", and an unauthenticated caller could still make the
|
|
# agent do work — inference costs money and a request that reaches an LLM is a
|
|
# prompt-injection surface. So the same authentication subrequest that guards the
|
|
# n8n endpoints guards this one: Keycloak's userinfo answers 200 for a valid
|
|
# bearer in the realm and 401 otherwise, which is the auth-request contract
|
|
# exactly.
|
|
#
|
|
# It authenticates, it does not authorise. What the caller may actually reach is
|
|
# decided further down, by the exchange and by the roles in their token.
|
|
#
|
|
# **The agent card is behind it too.** A2A discovery is normally public; here it
|
|
# is not, because a client that cannot send an `Authorization` header cannot use
|
|
# the agent anyway, and the card names the skills.
|
|
apiVersion: cert-manager.io/v1
|
|
kind: Certificate
|
|
metadata:
|
|
name: catalogue-agent-tls
|
|
namespace: agents
|
|
spec:
|
|
secretName: catalogue-agent-tls
|
|
dnsNames:
|
|
- catalogue-agent.sttlab.local
|
|
issuerRef:
|
|
name: sttlab-local-ca
|
|
kind: ClusterIssuer
|
|
---
|
|
apiVersion: networking.k8s.io/v1
|
|
kind: Ingress
|
|
metadata:
|
|
name: catalogue-agent
|
|
namespace: agents
|
|
annotations:
|
|
nginx.ingress.kubernetes.io/auth-url: http://keycloak.keycloak.svc.cluster.local:8080/realms/classic-models/protocol/openid-connect/userinfo
|
|
# A2A streams a task's progress; buffering it defeats that.
|
|
nginx.ingress.kubernetes.io/proxy-buffering: "off"
|
|
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
|
|
# An agent turn is a model call and several hops. The nginx default of 60s
|
|
# cuts a working answer off mid-flight.
|
|
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
|
|
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
|
|
spec:
|
|
ingressClassName: nginx
|
|
tls:
|
|
- hosts:
|
|
- catalogue-agent.sttlab.local
|
|
secretName: catalogue-agent-tls
|
|
rules:
|
|
- host: catalogue-agent.sttlab.local
|
|
http:
|
|
paths:
|
|
- path: /
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: catalogue-agent
|
|
port:
|
|
number: 8080
|