Skip to main content

Agent identity & governance control plane: policy-gated, credential-brokered, cryptographically audited tool execution for autonomous agents.

Project description

openagent-control

The zero-config security, governance, and telemetry proxy for the autonomous AI workforce.

What it is

Autonomous agents typically run on static service accounts and hardcoded API keys. That forces a choice between over-privileged agents and brittle workflows, and leaves no cryptographically trustworthy record of what an agent actually did.

openagent-control sits between an agent and the tools it calls — today, MCP (tools/list / tools/call) — and enforces three things on every call:

  1. Identity — the agent is a workload with its own identity, not a shared secret.
  2. Policy — every tool call is evaluated against explicit policy (Open Policy Agent / Rego) before it reaches the target system; a scoped, short-lived credential is issued only on allow.
  3. Audit — every decision produces an Ed25519-signed, hash-chained receipt, so a compliance reviewer can prove after the fact what was authorized and executed.

See docs/design.md for the full design, docs/adr/ for the reasoning behind each decision — including what's a real implementation today versus a deliberate v1 stub — docs/roadmap.md for where the codebase stands against the phased enterprise rollout plan, and docs/user-journeys.md for how an agent developer, platform engineer, registry operator, or compliance reviewer actually uses it, and docs/deployment.md for installing and running it.

Status

Early foundation, not production-ready. In particular:

  • Identity defaults to a stub. OAC_IDENTITY_MODE=header (the default) trusts an X-Spiffe-ID header rather than performing real SPIFFE/SPIRE attestation — only safe behind a network boundary that has already authenticated the caller. OAC_IDENTITY_MODE=jwt-svid cryptographically validates a SPIFFE JWT-SVID bearer token (the shape SPIRE issues) but still needs an actual SPIRE deployment to be a full production path — see ADR-0005. OAC_IDENTITY_MODE=oidc-jwks validates a real access token from Okta or Microsoft Entra ID against its published JWKS — see ADR-0010.
  • Token exchange defaults to a stub, with real Okta-compatible (RFC 8693) and Microsoft Entra (OBO) adapters available via OAC_TOKEN_EXCHANGE_MODE — see ADR-0004.
  • The ledger's signing key defaults to in-process (regenerated on restart) unless you inject your own ReceiptSigner; there's no KMS/HSM adapter yet. Chain state itself, however, is durable and replica-safe once OAC_DATABASE_URL is set — see ADR-0003 and ADR-0009.
  • No Human-in-the-Loop approval flow, no sidecar/native-SDK deployment pattern, no cross-organization (DID/VC) identity yet — tracked in ADR-0001 and ADR-0007.

Architecture

Hexagonal (ports & adapters) — see ADR-0006.

src/openagent_control/
├── domain/          # pure models + Protocol ports — no I/O, no framework imports
├── application/       # GovernedExecutionService — the transport-agnostic use case
├── adapters/            # concrete implementations of each port (OPA, ledger, identity, db, ...)
└── gateway/               # FastAPI app: routes + dependency wiring, no policy/crypto logic
Port Default adapter Also available (settings-selected)
PolicyEngine Open Policy Agent (Rego), policies/mcp_authz.rego
IdentityProvider header-trusting stub JWT-SVID validation, OIDC/JWKS (Okta, Entra ID)
AgentRegistry file (registry/agents.yaml, git-reviewed) Postgres (oac.agents), optionally Redis-cached
Ledger in-process Ed25519 hash-chained receipts Postgres-backed, replica-safe chain (oac.execution_receipts)
TokenExchange stub RFC 8693 (Okta-compatible), Microsoft Entra OBO — optionally Redis-cached to each token's own expiry
MCPUpstream MCP Streamable HTTP via the official MCP SDK (ADR-0011) plain JSON-RPC over HTTP, for non-MCP internal endpoints
AuditExporter stdout/log

Install

pip install openagent-control                  # gateway + OPA
pip install 'openagent-control[persistence]'   # + Postgres / Redis support

openagent-control init ./oac                   # starter registry + policy
export OAC_REGISTRY_PATH=./oac/agents.yaml
openagent-control doctor                       # checks every dependency
openagent-control serve

Or with containers — docker compose up (gateway + OPA), --profile persistence for Postgres/Redis, --profile demo for the walkthrough stack. Full guide: docs/deployment.md.

With no registry configured the gateway starts and denies every agent — a fresh install trusts nothing until you register something.

Development

make install      # poetry install --all-extras
make quality      # black --check, ruff, mypy
make test         # pytest with coverage (95% gate)
make check        # quality + test
make up           # docker compose: gateway + OPA
make up-demo      # + demo IdP and governed MCP server
make doctor       # verify config and dependencies
make test-packaging  # build a wheel, install it clean, run it from elsewhere

Requires Python 3.11+ and Poetry. The integration tests additionally need the opa binary (brew install opa); without it they skip rather than substitute a fake policy engine.

Once running (make up), obtain an access token the way a real workload does — an OAuth 2.0 client-credentials grant — then send a governed tool call:

TOKEN=$(curl -s -X POST http://localhost:8090/oauth2/v1/token \
  -u finance-invoice-svc:scenario-only-not-a-real-secret \
  -d grant_type=client_credentials | jq -r .access_token)

curl -X POST http://localhost:8000/mcp/v1 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"read_query","arguments":{"quarter":"Q3"}}}'

The upstream MCP server validates the short-lived credential the gateway brokers for it, so the same request sent directly to localhost:8080 is refused. See examples/enterprise_scenario/.

Persistence & caching (optional)

Unset by default — the gateway runs with the in-process ledger and file registry, zero extra infrastructure. The Postgres/Redis stack is an optional extra (pip install 'openagent-control[persistence]' / poetry install --extras persistence) and is lazy-imported, so the default deployment doesn't pay its ~20MB of resident memory or its install footprint. Set OAC_DATABASE_URL to switch the registry and ledger to Postgres (own oac schema, migrated via Alembic), and OAC_REDIS_URL to cache registry lookups (30s TTL) and brokered tokens (capped at each token's own expiry). See ADR-0009.

make up-persistent               # docker compose --profile persistence: + postgres, redis
make db-upgrade                  # alembic upgrade head against OAC_DATABASE_URL

To point at your own Postgres instance instead: export OAC_DATABASE_URL=postgresql+asyncpg://user:pass@host/db then make db-upgrade.

Examples

  • examples/enterprise_scenario/ — the full stack with nothing stubbed. A LangGraph agent, real OIDC/JWKS identity, real OPA, real RFC 8693 credential brokering, and a real MCP server over real SQLite that validates the brokered credential's signature, audience, and scope. It also demonstrates the property that distinguishes a control plane from a logging proxy: an agent that bypasses the gateway is refused by the upstream, because the token it holds is scoped to the gateway, not to the API. The same assertions run in CI (tests/integration/), so the demo cannot rot.

    brew install opa && poetry install --with examples
    poetry run python -m examples.enterprise_scenario.scenario
    

    Its keycloak/ suite runs the same identity and RFC 8693 adapters against real Keycloak 26.4 — an IdP this repo didn't write, so it can't share our bugs. That check earned its keep on the first run: it caught the identity adapter misreading Keycloak's service-account sub as a human sponsor, which would have 401'd every autonomous agent.

    The same is done for the MCP protocol itself against GitHub's production MCP server (tests/integration/test_github_mcp_conformance.py), which is how we found that the original upstream adapter did not speak MCP at all — see ADR-0011.

  • examples/langgraph_governed_agent/ — a deterministic, zero-API-key demo of a LangGraph agent whose tool calls are allowed, denied, and cryptographically receipted by the gateway:

    poetry install --with examples
    make up
    poetry run python -m examples.langgraph_governed_agent.demo
    
  • examples/oidc_identity_demo/ — the gateway authenticating agents with real Okta/Entra-shaped OIDC access tokens (signature, audience, and orphan-agent checks), fully offline against a mock IdP:

    poetry run python -m examples.oidc_identity_demo.demo
    

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

openagent_control-0.1.0.tar.gz (41.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

openagent_control-0.1.0-py3-none-any.whl (57.5 kB view details)

Uploaded Python 3

File details

Details for the file openagent_control-0.1.0.tar.gz.

File metadata

  • Download URL: openagent_control-0.1.0.tar.gz
  • Upload date:
  • Size: 41.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.3.2 CPython/3.14.5 Darwin/25.5.0

File hashes

Hashes for openagent_control-0.1.0.tar.gz
Algorithm Hash digest
SHA256 28865e29f3bbee708d433f301d84cc33a191b3448b664e76ae6a27ec4e6d8177
MD5 819b0f0bbe0d8d6083818935d68592d4
BLAKE2b-256 48220b3cd4b05358154bc345cc8cb003f67564dc02cbebfb38a4a403322d482b

See more details on using hashes here.

File details

Details for the file openagent_control-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: openagent_control-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 57.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.3.2 CPython/3.14.5 Darwin/25.5.0

File hashes

Hashes for openagent_control-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e241ab81c1a9bf4cb4dae5be1d63d0befbc3b09a476c3ebddc96f4a593d15f51
MD5 42296258519af5d78431e56eb4195542
BLAKE2b-256 fa219e4d22c2c7375bc702e35aa7209a14ae3bb1dffb8d275c101bf6eb76c8be

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page