github openziti/ziti v1.8.0-pre3

pre-release7 hours ago

Release 1.8.0

What's New

  • controllers can now optionally bind APIs using a OpenZiti identity
  • ziti edge login now supports the --network-identity flag to authenticate and establish connections through the Ziti overlay network
  • ziti edge login now supports using a bearer token with --token for authentication. The token is expected to be
    provided as just the JWT, not with the "Bearer " prefix
  • identity configuration can now be loaded from files or environment variables for flexible deployment scenarios
  • OIDC/JWT Token-based Enrollment
  • Clustering Performance Improvements

Binding Controller APIs With Identity

Controller APIs can now be bound to an OpenZiti overlay network identity, allowing secure communication through
the Ziti network. This is useful for scenarios where you want to expose controller APIs only through the overlay
network rather than on a standard network interface.

Configuration Structure

A standard bindPoint configuration looks like this:

    bindPoints:
      - interface: 127.0.0.1:18441
        address: 127.0.0.1:18441

To bind controller APIs to an OpenZiti identity, add an additional identity block to your bindPoints. The
identity configuration specifies where to load the Ziti identity file and which service to bind it to:

    bindPoints:
      - interface: 127.0.0.1:18441
        address: 127.0.0.1:18441
      - identity:
          file: "c:/temp/ctrl.testing/ctrl.identity.json"
          service: "mgmt"

Supported Configuration Options

  • file: Path to a Ziti identity JSON file containing the controller's identity and enrollment certificate
  • env: Name of an environment variable containing a base64-encoded Ziti identity (alternative to file)
  • service: The name of the Ziti service to bind the controller API to

Using Environment Variables

For deployments where storing identity files on disk is not preferred, you can reference a base64-encoded
identity file from an environment variable. The environment variable should contain the base64-encoded contents
of the identity JSON file.

For example, if an environment variable named ZITI_CTRL_IDENTITY contains a base64-encoded identity file:

    bindPoints:
      - interface: 127.0.0.1:18441
        address: 127.0.0.1:18441
      - identity:
          env: ZITI_CTRL_IDENTITY
          service: "mgmt"

IPv6 Support

Both IPv4 and IPv6 addresses are supported for standard bind points. IPv6 addresses should be specified in bracket
notation with a port number:

    bindPoints:
      - interface: "[::1]:18441"
        address: "[::1]:18441"
      - identity:
          file: "/path/to/identity.json"
          service: "mgmt"

CLI Enhancements for Identity-Based Connections

The ziti edge login command and REST client utilities have been enhanced to support identity-based connections
through the Ziti overlay network.

New --network-identity Flag for ziti edge login

The ziti edge login command now includes a --network-identity flag that allows you to authenticate to a Ziti
controller through the overlay network using a Ziti identity:

ziti edge login https://ziti.mgmt.apis.local:1280 \
  --username myuser \
  --password mypass \
  --network-identity /path/to/identity.json

This is useful when the controller is only accessible through the Ziti overlay network or when you want to ensure
all communication to the controller flows through the overlay for security purposes.

Identity Resolution Order

When establishing connections, identities are resolved in the following order:

  1. Command-line flag: The --network-identity flag takes precedence
  2. Environment variable: If ZITI_CLI_NETWORK_ID is set and contains a base64-encoded identity, it is used
  3. Cached identity file: If a network identity was saved from a previous login in the Ziti config directory, it may be used

This layered approach allows for flexibility in deployment scenarios:

  • Development: Use command-line flags for quick testing
  • Automation: Use environment variables in CI/CD pipelines
  • Production: Cache identities securely for repeated access

Dialing Modes When Authenticating

The CLI supports two dialing modes:

Intercept-based Dialing (Default)
By default, URLs are expected to leverage intercepts. Create a service with an appropriate intercept config and use
the intercept address when dialing. This is the standard mode for most use cases. For example, given a service with
the intercept ziti.mgmt.apis.local

ziti edge login https://ziti.mgmt.apis.local:1280 \
  --username myuser \
  --password mypass \
  --network-identity /path/to/identity.json

Identity-aware Dialing (Addressable Terminators)
To support addressable terminators-based dialing, specify a user in the URL. This activates dial-by-identity
functionality. The URL format should be identity-to-dial@service-name-to-dial. For example:

ziti edge login https://my-identity@my-service:1280 \
  --username myuser \
  --password mypass \
  --network-identity /path/to/identity.json

In this mode, the transport extracts the identity from the URL and uses it to establish a direct connection to
the specified service via the addressable terminator.

Binding Controller APIs With Identity

It's now possible to bind controller APIs to an OpenZiti overlay network identity. To bind a given controller
API to an OpenZiti identity, add a section to the desired bindPoint section. For example a common bindPoint
configuration might look like:

    bindPoints:
      - interface: 127.0.0.1:18441
        address: 127.0.0.1:18441

To bind any declared APIs to a given OpenZiti identity add an identity block:

    bindPoints:
      - interface: 127.0.0.1:18441
        address: 127.0.0.1:18441
      - identity:
          file: "c:/temp/ctrl.testing/clint.ctrl.json"
          service: "mgmt"

It's possible to refer to an environment variable for the identity file if desired. Add an environment variable with
the contents of the environment variable the identity file base64 encoded. For example if an environment is defined
with the name ZITI_ID_EXAMPLE and contains a base64 encoded identity file, the following bindPoint block can be used:

    bindPoints:
      - interface: 127.0.0.1:18441
        address: 127.0.0.1:18441
      - identity:
          env: ZITI_ID_EXAMPLE
          service: "mgmt"

OIDC/JWT Token-based Enrollment

OpenZiti now supports provisioning identities just-in-time through OIDC/JWT token enrollment. External identity
providers can be configured to allow identities to enroll using JWT tokens, with support for the resulting
identities to use certificate or token authentication.

External JWT Signer Configuration

External JWT signers are configured via the Edge Management API to define enrollment behavior with the following new
enrollment-specific properties:

  • enrollToCertEnabled - When enabled, identities can exchange a JWT token and a certificate signing request (CSR)
    for a client certificate during enrollment. The certificate can then be used for standard certificate-based
    authentication.

  • enrollToTokenEnabled - When enabled, identities can use a JWT token to enroll. The current token or future tokens
    may be used for authentication.

  • enrollNameClaimsSelector - Specifies which JWT claim contains the identity name. Accepts a JSON pointer
    (e.g., /preferred_username) or a simple property name (e.g., preferred_username, automatically converted to
    /preferred_username). Defaults to /sub if not specified. The extracted value becomes the identity name in Ziti.

  • enrollAttributeClaimsSelector - Specifies which JWT claims to extract as identity attributes during enrollment.
    Accepts a JSON pointer (e.g., /roles) or a simple property name (e.g., roles). Extracted attributes are
    applied to the newly enrolled identity for use in authorization policies.

  • enrollAuthPolicyId - Specifies the authentication policy to apply to newly enrolled identities. This determines
    what authentication methods are available for the identity post-enrollment.

Additionally the existing property named claimsProperty that specifies external id to match identities to:

  • now supports a JSON pointer (e.g., /id) or a simple property name (e.g., id)
  • is used to populate the externalId field of the identity

Enrollment Paths

Certificate Enrollment (enrollToCertEnabled)

When certificate enrollment is enabled, unauthenticated users can:

  1. Obtain a list of available IdPs from the public Edge Client API GET /external-jwt-signers endpoint, where
    enrollToCertEnabled is set to true
  2. Obtain a JWT from the configured OIDC provider
  3. Generate a certificate signing request (CSR)
  4. Submit an enrollment request with the JWT and CSR
  5. Have their identity created in Ziti with attributes extracted from JWT claims
  6. Receive a signed client certificate for certificate-based authentication

Token Enrollment (enrollToTokenEnabled)

When token enrollment is enabled, unauthenticated users can:

  1. Obtain a list of available IdPs from the public Edge Client API GET /external-jwt-signers endpoint, where
    enrollToTokenEnabled is set to true
  2. Obtain a JWT from the configured OIDC provider
  3. Submit an enrollment request with the JWT
  4. Have their identity created in Ziti with attributes extracted from JWT claims
  5. Receive a Ziti API token for token-based authentication

Edge Management API

The Edge Management API provides full CRUD operations for configuring external JWT signers:

  • POST /external-jwt-signers - Create a new external JWT signer with all configuration options
  • GET /external-jwt-signers - List all configured external JWT signers
  • GET /external-jwt-signers/{id} - Retrieve a specific signer configuration
  • PUT /external-jwt-signers/{id} - Update all fields of a signer
  • PATCH /external-jwt-signers/{id} - Partially update a signer
  • DELETE /external-jwt-signers/{id} - Delete a signer

Edge Client API

The Edge Client API exposes a reduced set of external JWT signer information for unauthenticated enrollment requests:

  • GET /external-jwt-signers - List available JWT signers with enrollment capabilities

The client API response includes the following fields for each signer:

  • name - Signer name
  • externalAuthUrl - URL where users obtain JWT tokens
  • clientId - OIDC client ID
  • scopes - Requested OIDC scopes
  • openIdConfigurationUrl - OIDC discovery endpoint
  • audience - Expected token audience
  • targetToken - Token type to use (ACCESS or ID)
  • enrollToCertEnabled - Flag indicating certificate enrollment is available
  • enrollToTokenEnabled - Flag indicating token enrollment is available

CLI Commands

Create an external JWT signer with enrollment options:

ziti edge controller create ext-jwt-signer <name> <issuer> \
  --jwks-endpoint <url> \
  --audience <audience> \
  --enroll-to-cert \
  --enroll-to-token=false \
  --enroll-name-claims-selector preferred_username \
  --enroll-attr-claims-selector roles \
  --enroll-auth-policy <policy-id-or-name>

Update enrollment options on an existing signer:

ziti edge controller update ext-jwt-signer <name|id> \
  --enroll-to-cert \
  --enroll-auth-policy <policy-id-or-name>

List external JWT signers:

ziti edge controller list ext-jwt-signers

Clustering Performance Improvements

In previous releases, model updates were submitted to raft one at at time. This prevented
raft from being efficient by allowing command batching. This release allows multiple
model updates to be in-flight at the same time.

New Configuration Options

  1. Raft Apply Timeout (raft.applyTimeout)

Location: Controller configuration file, under raft section
Type: Duration
Default: 5s
Description: Timeout for applying commands to the Raft distributed log. Commands that exceed this timeout will trigger adaptive rate limiter backoff.

Example:

  raft:
    applyTimeout: 10s
  1. Raft Rate Limiter Configuration (raft.rateLimiter)

A new adaptive rate limiter that controls the submission of commands to the Raft cluster. Unlike the existing command rate limiter, this specifically manages in-flight Raft operations with adaptive window sizing.

Configuration Structure:

  raft:
    rateLimiter:
      enabled: true
      minSize: 5
      maxSize: 250
      timeout: 30s

Sub-options:

  • enabled (boolean)
    • Default: true
    • Description: Enable/disable adaptive rate limiting for Raft command submission
  • minSize (integer)
    • Default: 5
    • Minimum: 1
    • Description: Minimum window size for concurrent in-flight Raft operations
  • maxSize (integer)
    • Default: 250
    • Description: Maximum window size for concurrent in-flight Raft operations. Must be >= minSize
  • timeout (duration)
    • Default: 30s
    • Description: Time after which outstanding work is assumed to have failed if not marked completed
  1. Restart Self on Snapshot (raft.restartSelfOnSnapshot)

Location: Controller configuration file, under raft section
Type: Boolean
Default: false
Description: When true, the controller will automatically restart itself when restoring a snapshot to an initialized system. When false, the controller will exit with code 0, requiring external process management to restart it.

Example:

  raft:
    restartSelfOnSnapshot: true

New Metrics

The adaptive rate limiter exposes three new metrics:

  1. raft.rate_limiter.queue_size (gauge)
    - Current number of operations queued/in-flight
  2. raft.rate_limiter.work_timer (timer)
    - Duration of rate-limited operations
  3. raft.rate_limiter.window_size (gauge)
    - Current adaptive window size

Component Updates and Bug Fixes

  • github.com/openziti/channel/v4: v4.2.41 -> v4.2.42

  • github.com/openziti/edge-api: v0.26.50 -> v0.26.51

  • github.com/openziti/foundation/v2: v2.0.79 -> v2.0.81

  • github.com/openziti/identity: v1.0.118 -> v1.0.119

  • github.com/openziti/sdk-golang: v1.2.10 -> v1.3.0

    • Issue #824 - release notes and hard errors on no TOTP handler breaks partial auth events
  • github.com/openziti/secretstream: v0.1.41 -> v0.1.42

  • github.com/openziti/storage: v0.4.31 -> v0.4.33

    • Issue #122 - StringFuncNode has incorrect nil check, allowing panic
    • Issue #120 - Change post tx commit constraint handling order
    • Issue #119 - Add ContextDecorator API
  • github.com/openziti/transport/v2: v2.0.198 -> v2.0.199

  • github.com/openziti/xweb/v3: v2.3.4 -> v3.0.1

  • github.com/openziti/ziti: v1.7.0 -> v1.8.0

    • Issue #3410 - Consolidate fabric REST API code with edge management and edge client code
    • Issue #3425 - RDM not properly responding to tunneler enabled flag changes
    • Issue #3420 - The terminator id cache uses the same id for all terminators in a host.v2 config, resulting in a single terminator
    • Issue #3419 - When using the router data model, precedence specified on the per-service identity mapping are incorrectly interpreted
    • Issue #3318 - Terminator creation seems to slow exponentially as the number of terminators rises from 10k to 20k to 40k
    • Issue #3407 - The CLI doesn't properly pass JWT authentication information to websocket endpoints
    • Issue #3359 - Ensure router data model subscriptions have reasonable performance and will scale
    • Issue #3381 - the fabric service REST apis are missing the maxIdleTime property
    • Issue #3382 - Legacy service sessions generated pre-1.7.x are incompatible with v1.7.+ and need to be cleared
    • Issue #3339 - get router ctrl.endpoint from ctrls claim in JWT
    • Issue #3378 - login with file stopped working
    • Issue #3346 - Fix confusing attempt logging
    • Issue #3337 - Router reports "no xgress edge forwarder for circuit"
    • Issue #3345 - Clean up connect events tests and remove global XG registry
    • Issue #3264 - Allow routers to generate alert events in cases of service misconfiguration

Don't miss a new ziti release

NewReleases is sending notifications on new releases.