Skip to content

pvoo/agent-api-firewall

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Agent API Firewall

Policy-driven API gateway for AI agents, powered by Wallarm API Firewall.

Why this project

This project keeps upstream API keys on the host and gives agents controlled access through:

  • Agent-specific routes: /<agent>/<api>/*
  • Agent tokens (X-Agent-Token by default)
  • OpenAPI policy profiles (allowlist, default deny)

Result: one reusable firewall that supports different agent permissions without hardcoding provider logic.

Architecture

Agent (no upstream keys)
  -> Agent API Firewall (Caddy + Wallarm)
    -> External APIs

Request flow:

  1. Route lookup by /<agent>/<api>/*
  2. Agent token validation
  3. Policy enforcement (if spec configured)
  4. Upstream auth/header injection
  5. Forward to provider

Quick start

git clone https://github.com/pvoo/agent-api-firewall.git
cd agent-api-firewall
cp .env.example .env

Populate .env:

  • Upstream credentials (INTERCOM_TOKEN, OPENAI_API_KEY, ...)
  • Agent tokens (AGENT_SUPPORT_TOKEN, AGENT_SALES_TOKEN, ...)

Render and run:

./render
docker compose up -d

Optional (shared host env + local config outside this repo):

FIREWALL_CONFIG_FILE=/path/to/local/config.yaml ./render
FIREWALL_ENV_FILE=/path/to/shared/.env docker compose up -d

Run live tests:

./test

Configuration model

config.yaml defines:

  • listen: proxy listen address (default: :8282)
  • network: Docker network name (default: vault)
  • auth.header: request header used for agent tokens
  • wallarm: firewall image and runtime tuning
  • agents: token + API policy access per agent
  • apis: upstream credentials/headers/query auth
  • apis.<api>.policies: named policy profiles (spec optional)
  • apis.<api>.policies.<policy>.response_validation: BLOCK, LOG_ONLY (default), or DISABLE
  • apis.<api>.policies.<policy>.team_scope: backward-compat team filter shorthand for Intercom-style specs
  • apis.<api>.policies.<policy>.enum_overrides: generic enum constraint overrides for any spec schema

Renderer/runtime env options:

  • FIREWALL_CONFIG_FILE: use a custom config file path (default: config.yaml)
  • FIREWALL_ENV_FILE: env file path injected into router service compose (default: .env)

Minimal example:

listen: ":8282"
network: vault
auth:
  header: "X-Agent-Token"
wallarm:
  image: wallarm/api-firewall:v0.9.5
  server_read_buffer_size: 65536

agents:
  support:
    token: "${AGENT_SUPPORT_TOKEN}"
    access:
      - api: intercom
        policy: support
  sales:
    token: "${AGENT_SALES_TOKEN}"
    access:
      - api: intercom
        policy: support

apis:
  intercom:
    upstream: https://api.intercom.io
    auth: "Bearer ${INTERCOM_TOKEN}"
    headers:
      Intercom-Version: "2.14"
    policies:
      support:
        spec: specs/intercom-support.yaml
        response_validation: LOG_ONLY
        team_scope:
          field: team_assignee_id
          allowed_ids: [6979737, 7257201, 8589981]
          allowed_names: [Support, Tickets, Test]

Routes and usage

If sales has access to intercom, call:

curl "http://localhost:8282/sales/intercom/me" \
  -H "X-Agent-Token: $AGENT_SALES_TOKEN"

No upstream key is sent by the agent. Caddy injects it from host env.

Testing

./test validates:

  • Unknown routes return 404
  • Missing/wrong token returns 401
  • Correct token reaches authorized route
  • Spec-backed policies block unknown endpoints (403)
  • Cross-agent token isolation

./test uses a probe header (X-Agent-Firewall-Probe: 1) for deterministic auth checks without relying on upstream API behavior.

team_scope notes:

  • field: filter field required by the policy (for Intercom, usually team_assignee_id)
  • allowed_ids: integer allowlist used to render policy enum constraints
  • allowed_names (optional): human labels for docs/UI; defaults to stringified IDs

enum_overrides -- generic alternative to team_scope that works with any spec:

enum_overrides:
  AllowedTeamId:                          # schema name under components.schemas
    values: [6979737, 7257201]            # required, sets .enum
    names: [Support, Tickets]             # optional, sets .x-enumNames
  TeamFilterEquals.properties.field:      # dots = path traversal in spec
    values: [team_assignee_id]

Processing order: team_scope expands first, then enum_overrides (overrides win on conflicts).

response_validation: controls how the Wallarm firewall handles API responses.

  • LOG_ONLY (default): log but pass through non-conforming responses
  • BLOCK: reject responses that don't match the spec
  • DISABLE: skip response validation entirely

Included policy packs

  • specs/intercom-support.yaml:
    • Support-safe Intercom subset
    • Team-scoped search constraints (rendered from config.yaml team_scope)
    • No bulk export/download/contact mutation
  • specs/openai-safe.yaml:
    • Models, chat completions, embeddings, responses
    • Sensitive endpoints blocked by omission

Project layout

.
├── config.yaml
├── .env.example
├── render
├── test
├── specs/
│   ├── intercom-support.yaml
│   └── openai-safe.yaml
├── Caddyfile              # generated
└── docker-compose.yml     # generated

Security notes

  • Default bind is localhost-only (127.0.0.1)
  • Keep .env private and out of version control
  • Prefer spec-backed policies for all sensitive APIs
  • See SECURITY.md for hardening guidance

License

MIT

About

OpenAPI-based request firewall for AI agents - thin wrapper on Wallarm API Firewall. Auth injection + endpoint allowlisting.

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages