v0.1.0-alpha

agentaccesscontrol

the agent gateway for Kubernetes


discovery auth routing credentials rate-limits mcp

$ kubectl apply -f agentpolicy.yaml

The Problem

  • AI agents are calling other agents, external APIs, and LLMs — but there's no standard way to secure these interactions
  • Every team hand-wires auth, rate limiting, and credential injection — scattered across code, envvars, and sidecars
  • No visibility into who can call what, which agents talk to each other, or how outbound API keys are managed
  • Agents get deployed with hardcoded secrets, no access control, and no rate limits — a security incident waiting to happen

What Agent Access Control Is

A Kubernetes operator that separates agent development from platform security — two personas, two CRDs, zero overlap
AI Engineers push code and add a label. Platform Engineers own GitOps and define security policies. Neither touches the other's domain.
The operator auto-discovers agents and generates HTTPRoutes, AuthPolicies, RateLimitPolicies, and sidecar ConfigMaps
Integrates with Kuadrant (Authorino + Limitador), Gateway API, and HashiCorp Vault — no vendor lock-in

Two CRDs, Two Personas

AgentCard auto-generated

  • Created by the operator — no human writes this
  • Discovered from agent endpoints at runtime
  • Skills, protocols (A2A, REST, MCP)
  • Labels inherited from pod for policy matching
  • Generates an HTTPRoute automatically

AgentPolicy platform engineer

  • The only CRD a human writes
  • Selects discovered agents via matchLabels
  • Inbound: allowed agents & users
  • Outbound: credential rules per host
  • Rate limiting, MCP tool references

Agent Discovery

AgentCards are discovered, not written. The AI Engineer adds a label. GitOps deploys. The operator discovers.


AI Engineer adds label         GitOps deploys pod                 AgentCard CR
kagenti=true, commits          Discovery controller watches       created automatically
────────────────────────       ──────────────────────────         ──────────────────────

A2A agent                 →    GET /.well-known/agent.json   →  protocols: [a2a]
                                 (name, skills, protocols)         skills: [...]

MCP agent                 →    POST /tools/list              →  protocols: [mcp]
                                 (available tools)                 skills: [from tools]

REST agent                →    GET /openapi.json             →  protocols: [rest]
                                 (endpoints, schemas)              skills: [from paths]
  

The AI Engineer never writes a CRD or runs kubectl. They commit, GitOps deploys, the operator discovers.

How It Works


AI ENGINEER                 PLATFORM (GitOps + Operator)      PLATFORM ENGINEER
───────────                 ────────────────────────────      ─────────────────

1. Push image, add           GitOps (ArgoCD/Flux)
   kagenti label to          syncs manifests to cluster
   Deployment, commit                |
                             Discovery controller              2. Define AgentPolicy
                             fetches agent metadata                per tier, commit
                             creates AgentCard CR                  to git
                                     |                                  |
                             AgentCard controller               GitOps syncs policy
                             generates HTTPRoute                        |
                                     |                                  |
                             AgentPolicy controller  <──────────────────┘
                             matches cards by labels
                             generates AuthPolicy, RateLimitPolicy, ConfigMap
                                     |
3. Agent receives traffic    Gateway routes via HTTPRoute
   (no action needed)        Authorino + Limitador + Sidecar enforce everything
  

What Discovery Produces

The AI Engineer commits a labeled Deployment. GitOps deploys it. The discovery controller creates this CR — no human writes it.


# Auto-generated from /.well-known/agent.json
apiVersion: kagenti.com/v1alpha1
kind: AgentCard
metadata:
  name: weather-agent
  labels:
    tier: standard          # from pod labels
    domain: weather         # from pod labels
spec:
  description: "Agent providing weather forecasts and alerts"
  protocols:
    - a2a
    - rest
  skills:                   # extracted from agent card
    - name: get-forecast
      description: "Returns weather forecast for a location"
    - name: weather-alerts
      description: "Returns active weather alerts for a region"
  servicePort: 8080
  

Platform Engineer: Apply a Policy

The only CRD a human writes. The Platform Engineer defines security rules that select discovered agents by label.


apiVersion: kagenti.com/v1alpha1
kind: AgentPolicy
metadata:
  name: standard-tier
spec:
  agentSelector:
    matchLabels:
      tier: standard
  ingress:
    allowedAgents: [orchestrator, planner]
    allowedUsers: ["*"]
  external:
    defaultMode: deny
    rules:
      - host: api.openweathermap.org
        mode: vault
        vaultPath: secret/data/openweathermap
      - host: weather.gov
        mode: passthrough
  rateLimit:
    requestsPerMinute: 60
  

Four Credential Modes

ModeHow It WorksUse Case
vault Sidecar fetches secret from HashiCorp Vault, injects into outbound request header API keys, static tokens
exchange RFC 8693 Token Exchange — trades inbound JWT for scoped downstream token OAuth2 APIs (GitHub, cloud)
passthrough Forwards the caller's credentials without transformation Public APIs, internal services
deny Sidecar blocks (defense-in-depth). Primary enforcement via NetworkPolicy Default policy, untrusted hosts

Credential injection happens in the sidecar forward proxy — zero code changes in the agent.

What Gets Generated

From AgentCard

HTTPRoute
Gateway API routing rule for the agent's service
MCPServerRegistration
Registered if agent declares mcp protocol (optional CRD)

From AgentPolicy

AuthPolicy
Kuadrant/Authorino inbound JWT validation
RateLimitPolicy
Kuadrant/Limitador per-agent rate limits
Sidecar ConfigMap
Forward proxy config for outbound credential injection
NetworkPolicy
Deny-all egress + allow DNS + allow gateway (when defaultMode=deny)

One AgentPolicy matching N agents generates N sets of downstream resources.

Policy Tiers in Practice

Standard Tier tier: standard
  • 60 req/min rate limit
  • Vault-based API key injection
  • 2 allowed caller agents
  • Passthrough for public APIs
  • Deny by default
Premium Tier tier: premium
  • 200 req/min rate limit
  • Token Exchange for OAuth2 APIs
  • 3 allowed caller agents
  • MCP tool references
  • Scoped access (repo, pull_request)

# Premium: OAuth2 token exchange for GitHub API
external:
  rules:
    - host: api.github.com
      mode: exchange
      audience: github-api
      scopes: [repo, pull_request]
  

Reconciliation Flow


Labeled pod detected
        |
        v
DiscoveryController
  |- Fetch /.well-known/agent.json (A2A) or /tools/list (MCP)
  |- Create AgentCard CR with metadata + pod labels
        |
        v
AgentCardReconciler
  |- Add finalizer
  |- Build HTTPRoute (host, paths, gateway ref)
  |- Create or Update HTTPRoute
  |- If "mcp" in protocols → create MCPServerRegistration
  |- Update status: Ready condition + generatedHTTPRoute
        |
        v  (watcher triggers)
AgentPolicyReconciler
  |- List AgentCards matching policy.spec.agentSelector.matchLabels
  |- For each matched card:
  |    |- Find card's HTTPRoute
  |    |- If ingress defined  → create/update AuthPolicy
  |    |- If rateLimit defined → create/update RateLimitPolicy
  |    |- If external defined → create/update sidecar ConfigMap
  |- Update status: matchedAgentCards count + generatedResources list
  

Architecture

Discovery Controller
Watches labeled pods, fetches agent metadata, creates AgentCard CRs
AgentCard Controller
Watches AgentCards, generates HTTPRoutes + MCPServerRegistration
AgentPolicy Controller
Watches AgentPolicies + AgentCards, generates AuthPolicy, RateLimitPolicy, ConfigMaps
Sidecar Proxies
Reverse proxy (inbound auth) + Forward proxy (outbound credentials)
Gateway API — HTTPRoute-based agent traffic routing
MCP Gateway — tool federation, routing, per-agent filtering via MCPVirtualServer
Kuadrant — Authorino (auth) + Limitador (rate limits)
HashiCorp Vault — secret storage for API credentials
Kubernetes — controller-runtime, CRDs, owner references

Design Principles

  • Persona separation — AI Engineers commit code, Platform Engineers own GitOps and policies, neither crosses into the other's domain
  • Discovery, not declaration — agents are found at runtime from their endpoints, not hand-written by anyone
  • Zero code changes — security is declared in YAML by the platform team, not wired into agent code
  • Label-based matching — policies select agents dynamically, not by hardcoded names
  • Defense in depth — NetworkPolicy at the network layer, sidecar at the application layer, gateway at the routing layer
  • Graceful degradation — optional CRDs (AuthPolicy, MCPServerRegistration) are skipped if not installed
  • Deny by default — NetworkPolicy blocks egress, sidecar blocks unmatched hosts, no access without explicit policy

Inbound vs Outbound

Inbound (who can call me?)

Reverse Proxy validates incoming requests
  • JWT claims checked by Authorino
  • allowedAgents → agent identity in token
  • allowedUsers → user identity in token
  • Unauthorized callers rejected at the gateway

Outbound (what can I call?)

Forward Proxy injects credentials
  • Per-host rules from external.rules
  • Vault → fetch secret, inject header
  • Exchange → trade JWT for scoped token
  • Deny → block unknown hosts

The Agent Gateway

Gateway API + MCP Gateway + this operator = a unified agent gateway handling every call pattern.

Call PatternPathEnforced By
User → Agent Client → Gateway → Agent Authorino (JWT) + Limitador
Agent → Agent (A2A) Agent A → Gateway → Agent B AuthPolicy (allowedAgents)
Agent → MCP Tools Agent → GatewayMCP Gateway → MCP Server MCPVirtualServer (tool filtering)
Agent → External API Agent → Sidecar (vault/exchange) → External Forward proxy + credential injection
Agent → Blocked Host Agent → NetworkPolicy (network) + Sidecar (app) NetworkPolicy primary, sidecar defense-in-depth

Every call — inbound, agent-to-agent, MCP, and outbound — goes through an enforcement point. No direct access.

MCP Gateway Integration

What the MCP Gateway does

  • Aggregates tools from multiple MCP servers into a single /mcp endpoint
  • Router (ext_proc) parses tool name prefix to route to the correct backend
  • MCPVirtualServer filters which tools each agent can access
  • Single gateway, many MCP servers, per-agent tool visibility

What this operator adds

  • Auto-creates MCPServerRegistration when agent declares mcp protocol
  • AgentPolicy mcpTools.virtualServerRef ties tool access to tiers
  • Standard tier: no MCP tools. Premium tier: premium-tools-vs
  • MCP servers are discovered and registered — not hand-configured

# Premium tier agents get MCP tool access
spec:
  mcpTools:
    virtualServerRef: premium-tools-vs   # MCP Gateway filters tools per-agent
  

Egress: Two Layers

Layer 1: NetworkPolicy (network)

  • Deny-all egress by default
  • Allow DNS (port 53 UDP/TCP)
  • Allow traffic to the cluster gateway
  • Enforced at kernel level — cannot be bypassed by the pod
  • Generated by the operator when defaultMode: deny

Layer 2: Sidecar (application)

  • Per-host credential injection (vault, exchange)
  • Hostname-level routing (NetworkPolicy only supports CIDR)
  • Application-level deny for unmatched hosts
  • Defense-in-depth — secondary to NetworkPolicy
  • Configured via generated sidecar ConfigMap

NetworkPolicy blocks at the network. Sidecar injects credentials per host. Both are needed: NetworkPolicy can't do per-host routing, sidecar can be bypassed without NetworkPolicy.

Why a meta-CRD?

Why not let the platform engineer write HTTPRoutes, AuthPolicies, and RateLimitPolicies directly?

Without this operator: per agent, you manually create and maintain 1 HTTPRoute + 1 AuthPolicy + 1 RateLimitPolicy + 1 ConfigMap + 1 NetworkPolicy. For 20 agents = 100 resources.
With this operator: 1 AgentPolicy per tier. New agents inherit the matching policy automatically via labels. The operator generates all downstream resources.
Consistency guarantee: every agent in a tier gets the same auth rules, rate limits, and credential strategy. No drift between manually maintained resources.
The tradeoff: if you need per-agent customization beyond what the CRD exposes, you may need to drop down to the underlying resources directly. This is a valid choice for edge cases.

Complement, Not Compete

Both discover agents — at different stages and for different purposes.

Agent Registry build-time
  • Static discovery: LLM reads source code
  • Identifies dependencies, tools, models, skills
  • Generates BOM (bill of materials)
  • Promotion lifecycle (draft → published)
  • Eval records, supply chain governance
  • Answers: what does this agent depend on?
Agent Access Control runtime
  • Runtime discovery: probes live endpoints
  • Discovers capabilities from running agents
  • Generates auth, routing, rate limits, creds
  • Enforces policy on live traffic
  • Inbound + outbound + MCP tool access
  • Answers: what can this agent do right now?

Registry knows the agent's dependency graph at build time. Access Control enforces what it can actually reach at runtime. Together: full lifecycle governance.

Status

Implemented

  • AgentCard + AgentPolicy CRDs
  • HTTPRoute generation
  • AuthPolicy generation (ServiceAccount identity)
  • RateLimitPolicy generation
  • Sidecar ConfigMap generation
  • NetworkPolicy egress enforcement
  • MCPServerRegistration (optional)
  • Graceful degradation for missing CRDs

Designed / Future

  • Discovery controller (runtime agent probing)
  • Sidecar proxy containers (reverse + forward)
  • Vault credential retrieval
  • RFC 8693 Token Exchange
  • Webhook admission validation
  • Multi-cluster federation
  • Observability and audit

quick start



# Install CRDs
make install

# Run the operator
make run

# Deploy sample agents + policies
kubectl apply -f config/samples/
  

repo → github.com/kagenti/agent-access-control