Product

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.

The trust chain

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.

1

Who is the user?

A Keycloak-issued JWT (RS256) is required and cryptographically validated at the gateway before anything else happens.

Identity Provider — Keycloak
2

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.

users2service policy
3

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.

mTLS
4

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.

OBO delegation
5

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.

service2service policy
6

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.

agentMcpToolCalls policy
7

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.

Admin Console
Policy engine

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/**"
AI & MCP

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.

See the AI-agent incidents this addresses →

Visibility & operations

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.

Under the hood

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.