A deterministic policy layer between every caller and every API
ZTeasy doesn't ask a model, a mesh sidecar, or an implicit network boundary to decide what's allowed. Every request — from a human, a service, or an AI agent — is checked against one explicit, auditable policy document before it reaches its target.
Seven questions, answered on every request
The same model applies whether the caller is an interactive user, an internal service, an AI agent, or a human operator managing policy itself.
Who is the user?
A Keycloak-issued JWT (RS256) is required and cryptographically validated at the gateway before anything else happens.
Is the user allowed to do this?
The user's realm role is matched against users2service rules in a single YAML policy document. No match means deny — there is no implicit-allow fallback.
Who is the internal caller?
Every hop between services presents a client certificate signed by ZTeasy's own CA. A service that can't prove its certificate never completes the TLS handshake, let alone the request.
On whose behalf is this call being made?
The gateway mints a signed, 30-second on-behalf-of token (HMAC-SHA256) that travels with the request. Downstream services validate the signature and expiry rather than trusting a forwarded header.
May this service call that service?
Service-to-service traffic (a client credential rather than a human user) is checked against its own service2service rule set — a compromised service account still can't reach APIs it was never granted.
May this AI agent call this tool?
Every MCP tool call is matched against agentMcpToolCalls rules by agent identity and tool name before the backend agent server ever sees it. See AI & MCP policy below.
May this operator see or change policy?
The Admin Console itself is policy-gated — an operator JWT needs the ADMIN role to view or reload the active policy set, audited the same way as every other request.
One YAML file. The sole source of truth.
No database fallback, no implicit defaults hiding in code. Every rule — for users, services, and AI agents — lives in one version-controllable document, validated at load and hot-reloadable with zero downtime.
- Deny always wins — an explicit DENY overrides any ALLOW, regardless of priority.
- Deny by default — a rule with no match is rejected, not permitted.
- Hot reload — push a policy change and reload without restarting the gateway; an invalid file keeps the previous policy active.
- Identity-aware sources — rules can target a role, user, group, or client synced live from your identity provider.
# one rule shape, reused across every category users2service: - id: u2s-user-write-service-a effect: ALLOW source: role:USER target: service-a pathPattern: "/api/v1/service-a/**" methods: "POST" service2service: - id: s2s-a-to-b-restricted effect: DENY source: client:service-a target: service-b pathPattern: "/restricted/**"
An AI agent's permissions, not its intentions, decide what it can do
A model can be persuaded, manipulated, or simply mistaken about whether an action is authorized. ZTeasy doesn't rely on the model to police itself — it enforces policy outside the model, on every tool call.
Every tool call is intercepted
ZTeasy's MCP proxy sits between the agent and its backend tool server, evaluating each tools/call request before it's forwarded — a denial never reaches the tool.
Per-agent, per-tool grants
Agent identity comes from its own OAuth2 client-credentials token, not a shared API key — so one agent's grants never leak into another's.
Denied by default
No matching rule means no access — an agent with a broad credential still can't discover its way into an ungranted tool.
Policy you can see, reload, and audit — not policy you have to trust
Admin Console
A web dashboard for the active policy set, audit trail, synced identities, and the service/agent registry — no redeploy to inspect what's enforced right now.
Audit trail
Every allowed or denied request is written asynchronously with a distributed trace ID, so one call can be followed end-to-end across every hop.
Identity sync
Users, groups, roles, and OIDC clients sync from your identity provider on a schedule, so policy rules can reference live identities instead of guessing at names.
Service registry
REST services and MCP agents are onboarded, auto-discovered, and health-monitored centrally — routing follows the registry, not hardcoded config.
Built to be read, not just trusted
Every trust decision is implemented explicitly in application code — no service mesh, no sidecar hiding the logic. The full source is open on GitHub.
Java 21 + Spring WebFlux
Reactive gateway and downstream services.
Keycloak (OIDC)
Identity provider for users, services, and agents.
PostgreSQL + R2DBC
Async audit trail, identity cache, service registry.
mTLS everywhere
Hot-swappable certificates for every internal hop.
React + TypeScript
The Admin Console, policy-gated like everything else.
Kotlin AI copilot
A policy-auditor agent that reviews your own YAML rules.
YAML policy engine
Version-controlled, hot-reloadable, no DB fallback.
MIT licensed
Read the source, run it yourself, adapt it.
Explore the reference implementation
The full architecture, ADRs, and technical specification are documented alongside the code.