Commit Graph

1623 Commits

Author SHA1 Message Date
Paul Lorenz 2bf9808df6 Add target field to config types. Fixes #3744 2026-05-27 13:17:06 -04:00
Paul Lorenz ba809e4d26 Keep controller mesh fully connected, as much as possible. Fixes #3684 2026-05-27 10:21:34 -04:00
Paul Lorenz 975a23e5f6 Add a recover mechanism for when a controller cluster can't form a quorum. Fixes #3849
- adds 'ziti ops cluster recover <controller-config>', an offline CLI
  that opens a stopped controller's data directory, forces the raft
  configuration to a single local node via raft.RecoverCluster, and
  aligns the FSM-tracked member list in ctrl-ha.db so stale peers don't
  leak through IsPeerMember or CtrlAddresses on restart
- removes the previous in-process recovery path: the cluster.recover
  config flag and the corresponding RaftConfig.Recover field are gone,
  along with the os.Exit branch in Controller.Init that consumed them
- adds BoltDbFsm.OverwriteServers and GetCachedServers so offline
  tooling can update and inspect the FSM-side server list without a
  live raft instance; OverwriteServers runs before raft.RecoverCluster
  so the snapshot it produces captures the corrected configuration
- updates Broker.AcceptClusterEvent to call DeleteRemovedPeers on every
  ClusterLeadershipGained, making the controllers entity table
  self-healing for any membership change a non-leader missed (offline
  recovery, or a 'cluster remove' applied while another node was leader)
- wires the new subcommand into both V1 and V2 CLI roots so it's
  reachable regardless of ZITI_CLI_LAYOUT
- switches filesystem path joins in the raft package and the recover
  command from path.Join to filepath.Join
- tests bootstrap a two-node configuration, run recoverDataDir, then
  verify the post-recovery snapshot, the FSM-cached server list, and
  Fsm.GetCurrentState (after starting a real raft instance) all report
  the survivor only
2026-05-27 09:23:01 -04:00
Paul Lorenz 91edc68409 Set fsm.startIndex on FSM init. Fixes #3860
- adds the missing self.startIndex assignment in BoltDbFsm.Init so
  GetStartRaftIndex() returns the persisted raft index instead of 0,
  which was leaving the RDM's RaftIndexProvider seeded at 0 on every
  restart and reporting a stale index until the next command applied
- adds a regression test that opens an FSM, persists a raft index,
  reopens it, and asserts GetStartIndex reflects the persisted value
- notes the fix in CHANGELOG.md under the ziti/v2 issue list
2026-05-11 19:12:16 -04:00
Paul Lorenz c73ea941dd Tidy duplicate permission types. Remove vestigial info message. Update changelog 2026-05-08 11:34:20 -04:00
Paul Lorenz 7c82e2d2c1 Filter current api session certs by current api session id. Fixes #3855 2026-05-07 14:28:43 -04:00
Paul Lorenz 67d34ef829 Fix permissions check on list controllers in management API. Fixes #3838 2026-05-07 14:28:43 -04:00
Paul Lorenz 8a3ad21365 Fix incorrect permissions check on create db snapshot with path. Fixes #3837 2026-05-07 14:28:43 -04:00
Andrew Martinez 949de99ee4 fixes #3809 support CSR submission during OIDC authentication (#3840)
* fixes #3809 support CSR submission during OIDC authentication

- accepts an optional CSR during OIDC login (all auth methods) and
  signs it into a session-bound certificate with a SPIFFE ID derived
  from the identity and API session
- returns the signed certificate PEM as a top-level "session_cert"
  field in the token endpoint JSON response (CodeExchange, RefreshToken,
  TokenExchange)
- adds cert-binding verification on RefreshToken and TokenExchange:
  if z_cfs is present the peer cert fingerprint must match (strict),
  otherwise falls back to SPIFFE ID verification
- supports cert rotation via csr_pem form parameter on refresh and
  token exchange; replaces the session cert fingerprint while
  preserving the authenticating cert fingerprint
- adds AuthCertFingerprints (z_acfs) claim to track permanent auth
  cert fingerprints separately from rotatable session cert fingerprints
- only the leaf certificate fingerprint is added to z_cfs and z_acfs,
  intermediates are never included
- invalid CSR returns 400 Bad Request in OIDC error format
- propagates updated CustomClaims (including CertFingerprints) from
  access token to renewed refresh token so rotated fingerprints are
  enforced on subsequent refreshes
- adds CertGenerated field to ApiSessionEvent
- advertises OIDC_AUTH_WITH_CSR controller capability when OIDC is
  enabled
- adds unit tests for verifyCertBinding (fingerprint, SPIFFE ID,
  edge cases) and CsrPem field parsing
- adds integration tests for initial CSR auth (updb, cert, ext-jwt),
  cert-binding on refresh/exchange, CSR rotation with cert auth,
  SPIFFE fallback and z_cfs transition, and CSR property forging
  resistance

* address pr concerns

* add z_cfs len tests on junk chain certs

* strip csr subject info, replace w/ santized values

* fix csr rotation rejection/paths during token exchange/refresh
2026-05-07 13:56:48 -04:00
Andrew Martinez 767ff11cfc fixes #3846 OIDC tokens from non-cert auth no longer bind incidental TLS certs (#3848)
- gates OIDC `z_cfs` claim on cert-based primary auth so non-cert sessions don't bind TLS-presented certs
- reorders router api session validation: fingerprint match first, then SPIFFE-on-first-party as fallback
- accepts first-party SPIFFE-Identity match as an acceptance signal (previously fell through to fingerprint check)
2026-05-06 21:41:19 -04:00
dovholuknf 7a6da85fdd add generic 'binding: spa', fix quickstart --home, lint cleanup 2026-05-03 11:08:40 -04:00
Paul Lorenz 82ac2e8060 Rework connect event handling to ensure serialized-per-router handling 2026-04-24 13:22:02 -04:00
Paul Lorenz c44350b3a7 Support ziti agent inspect so ziti processes can be inspected via IPC. Fixes #3824. Fixes #2049
- adds `ziti agent inspect <value>...` CLI that sends an InspectRequest directly to a ziti process over its agent IPC channel and pretty-prints JSON values in the response
- accepts app id 0 on controller and router agent channels so a single inspect command works against any process type
- adds Controller.agentOpInspect, backed by a new InspectionsManager.InspectLocal that runs inspect processing on the local controller only, without fanning out to routers or peer controllers
- extracts the router inspect handler into a new router/inspect package and stores a single shared instance on Router, reused by both the control channel and the agent IPC channel
- adds RouterEnv.GetInspectHandler and RouterEnv.GetXgressListeners so the control channel bind pulls the shared handler from env
- removes the now-redundant InspectRouterEnv interface from handler_ctrl/bind.go
- adds tunnel HandleAgentAsyncOp with support for stackdump and sdk inspect keys
2026-04-24 12:12:02 -04:00
Andrew Martinez 8297a817b7 fixes #3734 enforce client certificate proof-of-possession for OIDC sessions (#3805)
* fixes #3734 enforce client certificate proof-of-possession for OIDC sessions

- adds verifyCertProofOfPossession() in resolveOidcSession() to require
  TLS client cert matching a z_cfs fingerprint or SPIFFE ID when the
  OIDC token was issued with cert bindings
- adds z_cae (CertAllowExpired) claim from auth policy, propagated
  through token issuance and refresh
- adds TrustCache.VerifyClientCert() with tiered pool matching
  (first-party roots, trust anchors, third-party) and TTL cache
- adds WrapIdentityWithCertValidation() on the router to verify client
  certs at the TLS level against RDM PublicKeys
- adds IsFirstPartyCert() on the router to gate SPIFFE ID matching by
  checking whether the cert chains to the controller root CA
- adds VerifySpiffeId() in common/spiffehlp with SpiffeMatchApiSession,
  SpiffeMatchIdentity, and SpiffeMatchNone return types
- adds SPIFFE IDs to OTT and token enrollment certs (/identity/<id>)
- enforces cert expiry by match type: API session certs must be valid,
  fingerprint-matched certs respect z_cae, legacy sessions skip checks
- shallow-copies leaf certs before overriding time fields in all cert
  verification paths to avoid races on shared x509.Certificate pointers
- fixes controllerRootCache setting inited=true before the ctrl channel
  is available, which permanently cached the failure
2026-04-23 12:00:46 -04:00
Andrew Martinez 82e9870cd6 fixes #3806 expose OpenZiti endpoints in OIDC discovery document (#3808)
* fixes #3806 expose OpenZiti endpoints in OIDC discovery document

- adds vendor-specific "openziti_endpoints" field to the
  /.well-known/openid-configuration response
- overrides Discovery() on the OIDC server to wrap the standard config
  with OpenZiti login and MFA endpoint URLs
- advertises password, cert, ext-jwt, totp, totp enrollment, and
  auth query endpoints as absolute URLs derived from the issuer
- adds integration test verifying all openziti_endpoints fields
- adds dual-server integration test confirming endpoint URLs reflect
  the correct issuer when edge-oidc is hosted on multiple bind points

* changelog
2026-04-22 10:54:53 -04:00
Paul Lorenz 0042f6a345 Merge pull request #3810 from openziti/db-explorer-import-pr
Import the storage and ziti-db-explorer repos into the ziti repo
2026-04-21 09:54:19 -04:00
Paul Lorenz 9ac9a4f17a Filter service policies by type="Dial"/type="Bind" in queries. Fixes #3818
- registers the service policy type symbol as a string, so queries match the
  API's "Dial" and "Bind" names rather than the internal int32 ids
- adds a symbol mapper that converts the stored int32 to its PolicyType name
  at query eval time
- updates the posture-checks lookup in EdgeServiceManager, the only direct
  caller that went through GetSymbol, to read the mapped string form
- adds a store test covering type = "Dial" and type = "Bind" filtering
- notes the breaking removal of the undocumented type = 1/type = 2 form in
  the 2.0 deprecation cleanup list
2026-04-20 15:25:37 -04:00
Paul Lorenz 040016993e Fix codespell errors 2026-04-16 09:43:49 -04:00
Paul Lorenz 4df6ae564d Update package paths for newly imported storage and ziti-db-explorer packages 2026-04-16 09:18:55 -04:00
Paul Lorenz 9efd930fbd Merge storage project into controller/storage 2026-04-15 16:17:42 -04:00
Paul Lorenz 596e018e25 Merge pull request #3792 from openziti/specific-router-error-types
Add specific circuit failure error codes. Fixes #3717, #3543, #3364, #2888, #2859, #1580
2026-04-14 17:26:31 -04:00
Andrew Martinez 69885639d3 fixes #3788 return proper OIDC error codes and HTTP status codes (#3790)
- migrates from op.NewProvider() to LegacyServer/RegisterLegacyServer,
  routing all OIDC endpoint errors through op.WriteError which maps
  server_error to HTTP 500 and supports custom status codes via
  op.StatusError
- returns oidc.ErrInvalidClient() from AuthorizeClientIDSecret for
  unknown clients and bad secrets (HTTP 400 with invalid_client)
- returns oidc.ErrInvalidGrant() from parseRefreshToken,
  parseAccessToken, createAccessToken, and renewRefreshToken for
  client-supplied token errors (HTTP 400 with invalid_grant)
- fixes copy-paste bug in parseAccessToken that reported "invalid
  refresh_token" for access token errors
- plain Go errors from server-side failures (identity read, JSON
  marshal, token signing, Raft dispatch) now correctly surface as
  HTTP 500 via WriteError's DefaultToServerError handling
- adds integration tests covering error codes for token endpoint,
  login endpoint, userinfo endpoint, and end_session endpoint
2026-04-14 16:44:06 -04:00
Paul Lorenz 90f32affda Address review comments 2026-04-14 16:09:19 -04:00
Andrew Martinez 6515e3615c fixes #3680 add revocation management API, CLI, and enforcement (#3789)
* fixes #3680 add revocation management API, CLI, and enforcement

- adds Management API endpoints for revocations (POST, GET, LIST) with
  type-aware validation (JTI/API_SESSION require UUID, IDENTITY requires
  existing identity)
- adds CLI commands: ziti edge create revocation identity|api-session|jti
- adds revocation checks to resolveOidcSession in security_ctx.go so the
  REST API returns 401 for revoked OIDC tokens. Previously only
  ValidateAccessToken (router ctrl channel path) checked revocations,
  so revoked tokens still received 200 OK from the management and client
  HTTP APIs
- adds api-session revocation check to ValidateAccessToken, which only
  checked JTI and identity revocations
- adds Type field to Revocation model, store, and protobuf message
- adds integration tests covering CRUD, input validation, and token
  enforcement for all three revocation types
- use release edge-api@v0.28.1
2026-04-14 15:53:03 -04:00
Paul Lorenz 538623ceb6 Add specific circuit failure error codes. Fixes #3717, fixes #3543, fixes #3364, fixes #2888, fixes #2859, fixes #1580
- adds ErrorType constants for rejected-by-application, DNS resolution failed,
  port not allowed, invalid link destination, and resources not available
- adds corresponding CircuitFailureCause strings reported in circuit events
- extracts classifyDialError() in route handler to map dial errors to specific
  error codes using typed errors, syscall constants, and string matching
- detects DNS errors via *net.DNSError and string fallback for ER/T hosted
  services where errors are serialized through the SDK message protocol
- detects resource exhaustion via EMFILE, ENFILE, ENOBUFS syscall errors
- introduces InvalidLinkDestinationError typed error in forwarder package
- adds unit tests covering all 16 classification cases
- adds integration tests for rejected-by-application (SDK host),
  DNS resolution failed, connection refused, and port not allowed
  (ER/T host mode) with circuit event verification
- adds CreateEnrollAndStartTunnelerEdgeRouterWithCfgTweaks to test context
2026-04-14 15:52:49 -04:00
Paul Lorenz f951ac2423 Merge pull request #3763 from openziti/add-revocations-to-rdm-full-state
Include revocations in full router data model state. Fixes #3762
2026-04-14 11:22:08 -04:00
Paul Lorenz 6a3292e804 Set empty path when reserving circuit, to avoid panics. Fixes #3777 2026-04-07 09:25:55 -04:00
Paul Lorenz a785ab41fb Fix potential deadlock if panic while lock held 2026-04-06 09:56:43 -04:00
Paul Lorenz 588cb2350c Fix data race on heartbeat lastResponse and peer logger label
- changes lastResponse from plain int64 to atomic.Int64 in both router
  and peer heartbeat callbacks, fixing a data race between the heartbeat
  response handler and the heartbeat check ticker
- fixes peer heartbeat logger channelType from "router" to "peer"
2026-04-03 17:42:18 -04:00
Paul Lorenz 0766e79526 Fix minor config parsing bugs
- uses already-parsed AdvertiseAddress for cert validation instead of
  re-reading from the raw map, which panicked when the key was absent
- replaces errors.Wrapf(err, ...) with fmt.Errorf where err is nil, so
  routerDataModel.listenerBufferSize validation errors are returned
  instead of silently swallowed
- fixes pfxlog.Logger().Warn() call using %w verb, which is not
  interpolated outside fmt.Errorf
2026-04-03 17:42:18 -04:00
Paul Lorenz 1435676f8b Fix mesh peer signing cert from header being overwritten. Fixes #3757
- prefers the signing cert from the hello header when available, falling
  back to the TLS underlay cert
- applies consistently on both dialer and acceptor sides
- removes the dead append on the acceptor side that was immediately
  overwritten
2026-04-03 17:42:18 -04:00
Paul Lorenz afa3121469 Fix TLS rate limiter timeout check reading from wrong scope. Fixes #3756
- checks for the timeout key in the rateLimiter submap instead of the
  parent tls cfgmap, so a user-specified timeout is no longer silently
  overwritten by the default
2026-04-03 15:22:52 -04:00
Paul Lorenz 438c507a63 Fix commandHandler config read from wrong scope. Fixes #3755
- reads commandHandler from the cluster submap instead of the top-level
  cfgmap, matching all surrounding config reads in the cluster block
2026-04-03 15:22:49 -04:00
Paul Lorenz 33e9115182 Fix swapped HasPrefix args in SPIFFE trust domain check. Fixes #3753
- swaps arguments to strings.HasPrefix so it checks whether the trust
  domain starts with "spiffe://" rather than whether "spiffe://" starts
  with the trust domain
- fixes both the trustDomain and additionalTrustDomains code paths
2026-04-03 15:22:41 -04:00
Paul Lorenz 14cc2695c0 Merge pull request #3748 from openziti/fix-connect-handler-goroutine-leak
Fix connect events handler goroutine leak. Fixes #3746
2026-04-03 15:14:56 -04:00
Paul Lorenz 3f14d3e2cb Merge pull request #3751 from openziti/fix-peer-error-marshalling
Update controller peer error marshalling for app code changes. Fixes #3747
2026-04-03 15:14:39 -04:00
Paul Lorenz f2db0e147d Fix connect events handler goroutine leak. Fixes #3746
- replaces the per-handler goroutine in connectEventsHandler with a shared,
  bounded goroutine pool on AppEnv
- the old design spawned a processEvents goroutine per router connection that
  only exited on application shutdown, leaking a goroutine on every reconnect
- adds ConnectEventsConfig to the controller config with pool tuning options
  (queueSize, minWorkers, maxWorkers, idleTime)
- defaults: queue 16, 0-16 workers, 30s idle timeout
2026-04-02 23:44:43 -04:00
Paul Lorenz c9694ce3aa Update controller peer error marshalling for app code changes. Fixes #3747 2026-04-02 22:46:28 -04:00
Paul Lorenz be641e99b2 Merge pull request #3576 from dmuensterer/fix/oidc-token-refresh-bugs
fix openziti/ziti#3575 OIDC token endpoint code bugs possibly resulting in panics/eof errors
2026-04-01 13:18:06 -04:00
Paul Lorenz 7b4ae12c05 Add CreateCircuitV3 for RDM-authorized circuit creation. Fixes #3721
- adds CreateCircuitV3 message type and handler for routers that have
  already authorized dials locally via RDM, bypassing service session
  tokens in favor of identity ID, service ID, and pre-assigned circuit ID
- renames CreateCircuitRequest/Response to CreateCircuitV2Request/V2Response
  for clarity now that V3 exists
- adds CircuitManager.Reserve to atomically claim circuit IDs before routing,
  preventing collisions on pre-assigned IDs
- extends CreateCircuitParams with GetCircuitId so V3 can supply a
  pre-assigned circuit ID (falls back to UUID generation when empty)
- fixes IsDialableByIdentity which was incorrectly calling IsBindableByIdentity
- extracts V2 handler into its own file create_circuit_v2.go
- adds CreateCircuitV3RequestType/ResponseType (20222/20223) to edge_ctrl protobuf
- registers V3 handler in controller server
2026-03-27 14:41:28 -04:00
Paul Lorenz bd1f486958 Skip wildcard DNS SANs when building OIDC issuers. Fixes #3696
- skips certificate DNS names starting with "*." in getPossibleIssuers,
  since they produce unusable OIDC URLs (e.g. https://*.example.com/oidc/authorize)
- updates test to verify wildcard DNS SANs are excluded while IP SANs
  from the same cert remain valid issuers
2026-03-23 11:02:10 -04:00
Paul Lorenz 62e29169c2 Coalesce OIDC JWT revocations to reduce controller write pressure. Fixes #3681
- adds DeleteRevocationsBatchCommand so expired-revocation cleanup goes
  through raft as a single log entry per batch
- adds CreateRevocationsBatchCommand for batched revocation creation
  through raft
- moves refresh-token revocations from synchronous inline creation to a
  background batcher that flushes on a configurable interval, removing
  the database and raft as a bottleneck on token refreshes
- skips revocation creation for tokens expiring within a configurable
  threshold (revocationMinTokenLifetime), since they become invalid on
  their own
- validates that revocationMinTokenLifetime is less than 50% of the
  configured refresh token lifetime
- makes the revocation enforcer frequency configurable and restricts it
  to run only on the raft leader
- adds tests for multi-batch delete, batched create with router RDM
  propagation, and skip-threshold behavior
- adds new configuration tunables under edge.oidc: revocationBucketInterval,
  revocationMinTokenLifetime, revocationBucketMaxSize, revocationMaxQueued,
  revocationEnforcerFrequency
2026-03-19 08:35:00 -04:00
Andrew Martinez dbeb5c9f46 fixes openziti/ziti#3673 purge expired revocations, fix revocation bugs (#3679)
- fixes RevokeToken double-write: adds return after JWTID-keyed revocation
    save, preventing fallthrough write with raw JWT string as unreachable key
  - fixes TerminateSession key mismatch: stores revocation by identityId alone,
    matching the Subject-based lookup in ValidateAccessToken
  - fixes RevocationDelete sync action: passes DataState_Delete instead of
    DataState_Create so routers evict the entry from their data model
  - adds RevocationManager.DeleteExpired: batch-deletes expired revocations in
    batches of 500 until none remain
  - adds RevocationEnforcer: periodic policy runner (every 1 minute) that calls
    DeleteExpired and records metrics

before test fixes
2026-03-11 20:33:38 -04:00
Andrew Martinez 82a22e43b9 fixes #3496 allow TOTP enroll mid OIDC (#3656)
* fixes #3496 allow TOTP enroll mid OIDC

- detects unenrolled TOTP mid-OIDC flow and redirects to enroll endpoints
- adds enroll/verify endpoints in oidc_auth/login.go
- centralizes auth query storage rendering in oidc_auth/storage.go
- adds SDK integration tests for enrollment success, re-auth, cancelled
  enrollment, empty/alpha/wrong codes, and missing provider
- removes reduce rp server usage in tests
- refactors some oidc tests to new style where possible
- fixes amr regression in 2.0
- adds test for amr and auth_time
2026-03-11 16:27:31 -04:00
Paul Lorenz 5eb0f7944a Address review comments 2026-03-11 15:48:30 -04:00
Paul Lorenz e1638173cd Fixes for SDK terminator management. Add support for ziti sdk inspection. Fixes #3609
- removes legacy v1 terminator code path; all terminators now use v2 flow
- refactors edgeTerminator.close() to decouple SDK notification from control plane notification
- adds pending SDK close notification queue with retry when channel is busy
- adds post-create inspect mechanism that verifies SDK still holds the bind after terminator creation
- queues second post-create inspect when establishment takes >30s to catch SDK timeout races
- detects and discards stale reordered binds on the same connection by comparing connIds
- re-establishes replacement terminators when a delete/create race is detected
- eliminates IsEntityPresent pre-filter in removeTerminatorsHandler to prevent raft ordering races
- fixes ValidateTerminators to query identities from the correct manager with the correct filter field
- adds postCreate flag to ValidateTerminatorsV2Request so routers skip redundant SDK inspect
- returns retry-later (nil result) from router validation when inspect is temporarily unavailable
- blocks SyncAllSubscribers until completion and guards RouterDataModel replacement with in-progress flag
- fixes InheritLocalData to enable service access tracking for all subscribed identities
- adds Services.Has check in GetServiceAccessPolicies to prevent false policy grants
- validates policy-to-identity associations in ValidateServicePolicies
- adds `ziti agent tunnel dump-sdk` command for SDK context inspection via IPC agent
- adds `ziti fabric inspect sdk` command to query SDK context through routers
- fixes --expected-per-host CLI flag binding in validate terminators command
- changes bind-access-lost retry hint from NotRetriable to RetryStartOver
- moves trace route response and xgress close handling off channel handler goroutine
- fixes listTerminators test helper to URL-encode filter parameter
- improves sdk-hosting-test validation resilience with login and query retries
- adds terminator_create_flow.md documenting the full lifecycle across SDK, router, and controller
- adds detailed logging for data model sync, service access tracking, and subscriber change detection
2026-03-11 13:10:28 -04:00
Paul Lorenz 10de7092c1 Address review comments 2026-03-11 10:28:38 -04:00
Paul Lorenz 9513fc902d Fix changelog errors. Fix config parsing bug 2026-03-10 13:08:22 -04:00
Paul Lorenz a3804f4022 Fallback to legacy headers on dial failure, in case of size constraints. Fixes #3658 2026-03-10 10:21:06 -04:00
Andrew Martinez c367679e79 fixes openziti/ziti#3626 omit overlay bind points from /versions apiB… (#3663)
* fixes openziti/ziti#3626 omit overlay bind points from /versions apiBaseUrls

- adds BindPointTypeUnderlay and BindPointTypeOverlay constants
- implements Type() on UnderlayBindPoint and OverlayBindPoint
- skips non-underlay bind points when building apiBaseUrls in version_router
- skips non-underlay bind points in GetApiAddresses
- adds unit tests for Type() on both bind point implementations
- updates xweb
2026-03-10 09:57:50 -04:00