8f1f0245da
The standing authority the autonomous runs act under: an offline refresh token issued by a new classic-models-mandate client for the user who authorised the agent, stored in Vault, redeemed at trigger time. The mandate client holds no domain audience. It cannot reach data; it can only say who authorised whom. Direct access grants on it is a lab shortcut, noted as such — mandating an agent is a decision a person takes, and a password grant records no consent where the authorization code flow would. Verified end to end: refresh gives sub=pm-user azp=classic-models-mandate with the agent in the audience, the agent exchanges it to azp=itself and aud=mcp-catalog, and the MCP call answers 200. sub stays the person who mandated, azp says which agent acted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
31 lines
1.1 KiB
YAML
31 lines
1.1 KiB
YAML
# The agents' Keycloak client secrets, for the workflows that act as those
|
|
# agents. Read from the realm's own Vault entry rather than copied into n8n's
|
|
# path: there is one source for a client secret, and rotating it in Vault
|
|
# rotates it everywhere instead of leaving a stale twin behind.
|
|
#
|
|
# A narrow grant — this names the properties it wants, so the namespace receives
|
|
# those and nothing else of the realm.
|
|
apiVersion: external-secrets.io/v1
|
|
kind: ExternalSecret
|
|
metadata:
|
|
name: n8n-agent-secrets
|
|
namespace: n8n
|
|
spec:
|
|
refreshInterval: 1h
|
|
secretStoreRef:
|
|
kind: ClusterSecretStore
|
|
name: vault-keycloak
|
|
target:
|
|
name: n8n-agent-secrets
|
|
data:
|
|
- secretKey: APPROVISIONNEMENT_CLIENT_SECRET
|
|
remoteRef:
|
|
key: keycloak/classic-models-realm
|
|
property: KC_SECRET_CLASSIC_MODELS_AGENT_APPROVISIONNEMENT
|
|
# Redeems a mandate. Held by the workflow rather than by the adapter because
|
|
# it is the workflow that acts as the agent.
|
|
- secretKey: MANDATE_CLIENT_SECRET
|
|
remoteRef:
|
|
key: keycloak/classic-models-realm
|
|
property: KC_SECRET_MANDATE
|