Skip to content

Agent Identity & Policies

An agent identity turns an autonomous agent into a first-class security principal the gateway can decide, enforce and prove against. The model is actions, not access: instead of handing an agent a key that can do anything its group can do, you grant it specific action types on specific targets — and everything else is denied by default.

Brutor is deliberately not an identity provider. Issuance stays with your IdP (Okta, Entra Agent ID, SPIFFE); Brutor holds the mapping from IdP subject to agent, and the policy attached to it.

Agent identities — Resources → Agents → Identities

Identities are defined under Resources → Agents → Identities; their grants live under Governance → Agent Policies (also editable per resource group).

Editing an agent identity

Field Values Notes
name unique per tenant
owner_user_id / owner_label The accountable human sponsor
idp_server_id + idp_subject The IdP workload seam — e.g. spiffe://acme/ns/agents/billing; unique per IdP server
source manual · idp · discovered How the identity entered the platform
default_deny default true No matching grant → deny
enforcement_mode enforce · dry_run dry_run logs would-block verdicts and lets traffic proceed
status / enabled / expires_at active · suspended Revocation sets suspended + revoked_at

How a caller becomes this agent — two ways, no bespoke headers:

  1. API key binding — an API key with agent_id set: every call with that key acts as the agent.
  2. IdP workload token — the agent presents its own OIDC/SPIFFE bearer token; the gateway verifies signature, issuer and expiry against the tenant IdP’s JWKS and resolves the agent by (idp_server_id, sub).

Resource-group membership is separate from grants: adding the agent to a resource group applies that group’s ACLs, limits, guardrails and approval rules — the same stack a human member gets.

A grant is (action_type, target, effect) plus optional constraints:

Values
action_type llm_call · mcp_tool · a2a_call · skill_exec
target Glob over the model/tool/card/skill name — hubspot:*, db:delete_rows, *
effect allow · deny · approval_required
constraints time_window, max_delegation_depth (A2A depth cap), rate (per-grant rate limit), deny_tool_risk

Tool risk classes (read_only, idempotent, destructive, open_world) are derived from MCP tool annotations — with conservative defaults: a tool with no annotations is treated as destructive + open_world, so deny_tool_risk: ["destructive"] blocks unannotated tools too.

Terminal window
# Create the identity
curl -s -X POST http://localhost:5050/v1/admin/agent-identities \
-H "Authorization: Bearer $ADMIN_JWT" -H "Content-Type: application/json" \
-d '{"name": "billing-bot", "owner_label": "RevOps",
"idp_server_id": "idp-01K0...", "idp_subject": "spiffe://acme/ns/agents/billing"}'
# Grant: read CRM freely, updates need a human, deletes never
curl -s -X POST http://localhost:5050/v1/admin/agent-identities/agent-01K0.../grants \
-H "Authorization: Bearer $ADMIN_JWT" -H "Content-Type: application/json" \
-d '{"action_type": "mcp_tool", "target": "hubspot:*", "effect": "allow"}'
{
"id": "grant-01K0...",
"agent_id": "agent-01K0...",
"action_type": "mcp_tool",
"target": "hubspot:*",
"effect": "allow",
"enabled": true
}

On every governed surface (LLM, MCP tool, A2A, skills), when the caller is an agent principal:

  1. Strictest matching grant wins — among live grants (enabled, unexpired, inside time_window) matching the action + target, deny beats approval_required beats allow.
  2. Default-deny — no matching grant and default_deny: true → deny; with default_deny: false the decision falls through to the resource-group ACL.
  3. Strictest-wins merge with the group ACL — the agent must satisfy its own grants and its resource group’s rules; an explicit deny from either plane wins, and approval_required beats allow.
  4. Constraints only tighten — delegation depth, tool-risk denies and per-grant rate limits apply after the effect is resolved.

A blocked call returns HTTP 403 with agent_not_authorized: <reason>; policy-lookup failures fail closed. The decision, matched grant and reason are stamped on the proxy log (actor_agent_id records the acting agent) — every decision is evidence.

Base: /v1/admin/agent-identities on the Control Plane (:5050).

Method Path Purpose
GET / POST /v1/admin/agent-identities List (filters: status, q) / create
GET / PATCH /v1/admin/agent-identities/{agent_id} Detail / update
POST /v1/admin/agent-identities/{agent_id}/revoke Revoke (disable + suspend)
GET / POST /v1/admin/agent-identities/{agent_id}/grants List / add grants
DELETE /v1/admin/agent-identities/{agent_id}/grants/{grant_id} Remove a grant
GET / POST /v1/admin/agent-identities/{agent_id}/memberships List / add resource-group memberships
DELETE /v1/admin/agent-identities/{agent_id}/memberships/{member_id} Remove membership
  • A2A agents — agent cards (what an agent exposes to peers) vs identity (who it is, what it may do)
  • Tool approvals — where approval_required grants route
  • Resource groups — the group plane the agent decision merges with
  • AI Asset Registry — identities appear as agent_identity assets