# 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: catalog-agent-tls namespace: agents spec: secretName: catalog-agent-tls dnsNames: - catalog-agent.sttlab.local issuerRef: name: sttlab-local-ca kind: ClusterIssuer --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: catalog-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: - catalog-agent.sttlab.local secretName: catalog-agent-tls rules: - host: catalog-agent.sttlab.local http: paths: - path: / pathType: Prefix backend: service: name: catalog-agent port: number: 8080