Announcing OpenZiti v2.0
Production-grade HA, fine-grained permissions, a fully dark management plane, and foundation for the future
It's been over a year since we announced OpenZiti v1.0, and a lot has happened. The community has grown, the platform has matured, and the demands on zero-trust networking have evolved - particularly as AI workloads have entered the picture. v2.0 reflects where we are now and where we're headed.
So, what's in v2.0?
HA controllers are ready for production
This is the headliner, and it's been a long time coming. High availability for controllers has been in development since before v1.0, and with v2.0 we're declaring it ready for general use.
The HA work brought with it some significant architectural improvements. Authentication now uses JWTs by default instead of legacy API sessions. This means controllers no longer need to store and propagate sessions to routers, which removes a bottleneck from the network and allows load to be more easily distributed across controllers and routers.
To support distributed authentication, routers now maintain a bespoke version of the data model. Beyond enabling HA, this sets us up to remove service polling entirely in a future release, further reducing controller load.
If you're running OpenZiti in production, this is the change that matters most.
New permissions model (beta)
The previous authorization model was binary: you were an admin, or you weren't. v2.0 introduces a proper permissions system with three levels of granularity:
- Global permissions - system-wide access levels like
adminandadmin_readonly - Entity-level permissions - full CRUD access to specific resource types (e.g.,
service,identity,router) - Action-level permissions - fine-grained control using
entity.actionpatterns (e.g.,service.read,identity.update)
Permissions are assigned directly to identities and are additive. Non-admin identities cannot escalate their own privileges - they can't create admin identities, grant permissions, or modify admin accounts.
We're marking this as beta primarily to get feedback on which permissions make sense. The implementation is solid, but the specific permission set may evolve based on what users actually need.
OIDC and JWT-based enrollment
OIDC is now enabled by default and is the preferred authentication path going forward. Legacy API sessions and service sessions are deprecated and will be removed in v3.0.
The more interesting addition: identities can now be provisioned just-in-time through OIDC/JWT token-based enrollment. And identities authenticating via non-certificate methods (password, external JWT) can submit a CSR during OIDC authentication to obtain a session-bound certificate for mTLS communication with edge routers. This means every identity can participate in mTLS channels regardless of how it initially authenticated.
For those of you integrating with enterprise identity providers, this is a significant step forward.
Controllers can bind APIs over the overlay
This one is subtle but powerful. Controller APIs can now be bound to an OpenZiti identity, meaning the management API itself can be served exclusively over the Ziti overlay network. The controller's management interface doesn't need to listen on a standard network interface at all.
Combined with the new --network-identity flag on ziti edge login, you can authenticate to a controller entirely through the overlay. The controller is dark. The management API is dark. Everything flows through the zero-trust fabric.
For high-security deployments, this removes the last listening port from the architecture.
CLI reorganization
The ziti CLI has been reorganized to consolidate commands that were spread across ziti edge and ziti fabric into unified top-level commands. Entity management is now available via ziti create, ziti delete, ziti list, and ziti update. Session management is simplified with top-level ziti login.
The existing ziti edge and ziti fabric command trees are still available, so nothing breaks. But the new structure is cleaner, and it's what we'll document going forward.
One breaking change to be aware of: ziti create ca now creates a Ziti edge Certificate Authority (previously it created a PKI CA). PKI CA creation is still available via ziti pki create ca.
Clustering and performance improvements
Several changes improve performance at scale:
- Multiple model updates can now be in-flight simultaneously, improving clustering throughput
- Authentication-related model updates can be non-blocking and even dropped if the system is too busy, preventing auth storms from destabilizing the cluster
- Refresh-token revocations are batched and best-effort, removing the database/raft bottleneck on token refreshes
- Connect events now use per-router single-worker goroutine pools, fixing a goroutine leak that could accumulate thousands of leaked goroutines under router churn
- Dynamic cost range for smart routing expanded beyond the previous 64K limit
Router compatibility note
Because of the JWT authentication changes, v2.x routers will only work with v2.x controllers. When upgrading, controllers should be upgraded first, then routers individually. v2.x routers remain compatible with older router versions on the same network.
We try hard to avoid breaking changes like this, but the engineering trade-offs were clear. This change was first introduced in the 1.7 release line, which we never marked stable specifically because of this incompatibility. If you're currently on 1.6.x, plan your upgrade path accordingly.
Deprecation cleanup
Since we're already making a breaking change, we took the opportunity to clean up some long-deprecated items:
- Controller-managed links (replaced by router-managed links in v0.30.0)
ziti edge create identity <type>(identity types other than router were removed in v0.30.2)- Terminator create/update/delete events (superseded by entity change events in v0.28.0)
xgress_edge_tunnelv1 (replaced by v2 in v0.30.x)- Integer-form service policy filter types (use
type = "Dial"/type = "Bind"instead)
If you're running a recent 1.x release, none of these should be a surprise. If you're upgrading from something older, upgrade to the latest 1.x first.
Additional highlights
A few more things worth noting:
- Generic SPA hosting - the controller's web layer now supports hosting arbitrary single-page applications via
binding: spa, so you can serve your own UIs alongside ZAC - Multiple DNS upstreams - the tunneler can fan out recursive queries to several upstream resolvers in parallel
- Routers provide richer error context to SDKs for terminator errors, enabling better retry behavior
- New alert event type for surfacing operational issues to network operators (beta)
- Azure Service Bus event sink for streaming controller events, contributed by @ffaraone
- Bundled ZAC upgraded to 4.0
- Build updated to Go 1.25
Community
Thank you to everyone who contributed to this release, including community members @ffaraone (Azure Service Bus event sink), @dmuensterer (OIDC token refresh fixes), @nenkoru (controller isleader health check endpoint), Jan Starkl (UPDB auth fix), and Mamy Ratsimbazafy (port range fix). Open source works because people show up and contribute. We appreciate every one of you.
What's ahead
With HA controllers in production, OIDC as the default auth path, and the new permissions model in beta, OpenZiti v2.0 is a more capable and more production-ready platform than it's ever been.
We're also building on OpenZiti in new directions. Agora is a zero-trust network for agent-to-agent communication, built on OpenZiti. The LLM Gateway and MCP Gateway bring zero-trust networking to AI infrastructure. These are all open source, all Apache 2.0, and all building on the foundation that v2.0 strengthens.
The full release notes are on GitHub. Try it out and let us know how it goes. And a star on the main repo is always appreciated.
Thank you all, especially those in the community who have helped advance OpenZiti to this point.



