Define policies centrally. Enforce them beside every service. Sync the identity data you already have. Trace every decision back to the rule that produced it.
Two paths, deliberately separate. The hot path — every authorization check — runs entirely in your infrastructure and never leaves the pod. Everything that crosses to ZStrike Cloud — policy sync, entity sync, logging — is asynchronous, out of the request path. ZStrike hosts the control plane: policy authoring, versions, and the audit store.
One local check. No network hop. The control plane is not in the request path.
LOCALHOST · NO NETWORK HOP · LAST-SYNCED STATE
RESILIENCE BY DESIGN. The sidecar decides from local state, so a cloud outage does not become your application outage.
Access rules are Cedar policies — short, reviewable, versioned. Write them by hand, or describe the intent in plain English and let AI draft the rule, checked against your description before it saves. Every change is a version; any version rolls back in one click.
// care-team-only · v14 permit ( principal in CarePortal::CareTeam, action == Action::"chart.view", resource ) when { resource.careTeam == principal.careTeam };
// simulator — same engine, your schema + entities request { "principal": "CarePortal::Nurse::\"k.moreno\"", "action": "CarePortal::Action::\"chart.view\"", "resource": "CarePortal::Chart::\"pt-88213\"", "context": { "shift": "night" } } // decision — with the policies that produced it response { "decision": "DENY", "determining_policies": ["care-team-only@v14"], "errors": [] }
Run any request against your real schema and entities before it ships. The response names the determining policies — the deny you didn’t expect surfaces here, with the rule that caused it, not in an incident.
Enforcement is a single check per request — SDKs for TypeScript/JavaScript, Java, Ruby, Rust, Go, and Elixir, and the protocol is plain gRPC/REST, so any other language can call the sidecar without waiting for an SDK. Deployment is one container added to the pod spec; the sidecar keeps deciding on last-synced policy if the control plane is unreachable.
Decision metrics and traces integrate with OpenTelemetry, so denials show up where your engineers already look.
SDKS
· GRPC + REST · SIDECAR · OPENTELEMETRY
// service.ts — the whole integration
const decision = await zstrike.check({
principal: 'User::"j.willis"',
action: 'Action::"chart.edit"',
resource: 'Chart::"pt-71002"',
});
if (!decision.allowed) throw new Forbidden(decision.reason); # your service's pod — add one container
containers:
- name: your-service
image: registry.example.com/care-portal:1.42.0
- name: zstrike-pdp
image: zstrike/pdp-sidecar:<version>
ports:
- containerPort: 50051 # gRPC · localhost only Principals, groups, and attributes sync from Entra ID, Okta, or any identity provider over SCIM 2.0 or REST — alongside databases and APIs. Every sidecar keeps a local copy, so decisions don't wait on a directory lookup.
ENTRA ID · OKTA · ANY IDP · REST · SCIM 2.0 BETA
Granted or denied, every decision lands in the audit trail with its full context — who asked, what they tried, which resource — and the exact policies, by name and version, that produced the answer. “Why could she open that chart?” is one query, not an investigation. And when access is denied, engineers see which rule said no — not a mystery 403.
Because policies are versioned, the trail holds up over time: a decision from last quarter traces to the policy text that was live at that moment, not today’s edit.
WHO · WHAT · WHY ON EVERY RECORD
ZStrike was founded by engineers who ran access control at scale — and watched every company rebuild the same brittle permission code from scratch. We believe who-can-do-what is infrastructure, not application logic: one governed platform, tested, enforced, and logged.
A 30-minute briefing with our engineering team — your use cases, live.