Skip to main content

Configuration reference

nf-data-connector is configured via a YAML file (default: config.yaml, override with -config <path>) and environment variables for secrets.

Related docs:

Top-level structure

controller: # Ziti controller connection
events: # Event stream subscriptions
enrichment: # Resource-name resolution cache
subscribers: # Output targets (enable what you need)
triggers: # Optional rule-based alerting
logging: # Log level and format

controller: Controller connection

Connects to one or more controller nodes. Supports HA clusters.

controller:
# Single controller:
host: "ctrl.example.com:1280"

# HA cluster (takes precedence over host). When set, the connector tries
# each host in order and rotates on failure:
# hosts:
# - "ctrl-1.example.com:1280"
# - "ctrl-2.example.com:1280"
# - "ctrl-3.example.com:1280"

auth_method: "password" # "password" or "cert"
username: "" # prefer env var ZITI_USERNAME
password: "" # prefer env var ZITI_PASSWORD

# Certificate-based auth (when auth_method: cert):
cert_file: "" # path to client cert (PEM)
key_file: "" # path to client key (PEM)

# TLS:
ca_file: "" # path to custom CA bundle (PEM)
fetch_ca: true # auto-fetch CA from /edge/client/v1/.well-known/est/cacerts
skip_verify: false # disable TLS verification (dev/test only)
FieldTypeDefaultDescription
hoststring:Single controller host:port (no https:// prefix)
hostslist:HA cluster list; takes precedence over host
auth_methodstringpasswordpassword or cert
usernamestring:Password auth username (use env var)
passwordstring:Password auth password (use env var)
cert_filestring:Client cert for cert auth
key_filestring:Client key for cert auth
ca_filestring:Custom CA bundle (PEM)
fetch_cabooltrueFetch CA from controller's well-known EST endpoint
skip_verifyboolfalseSkip TLS verification — dev only

HA behavior: If multiple hosts are configured, authentication and CA fetching try each host in order. On disconnect or connection failure, the connector rotates to the next host. All components (websocket, enrichment API) follow the active host.

events: Event subscriptions

events:
subscriptions:
- type: usage
version: 3
- type: circuit
- type: link
- type: router
- type: terminator
- type: session
- type: apiSession
- type: sdk
- type: service
- type: connect
- type: metrics
sourceFilter: ".*"
metricFilter: ".*"
- type: entityCount
- type: entityChange
include:
- identities
- services
- routers

namespace_filter: [] # optional: only forward events in this list

Each subscription can have the following fields:

FieldUsed byDescription
typeallEvent namespace. See the Event Types table below.
versionusageSchema version (use 3 for current flat format)
sourceFiltermetricsRegex matching the event source
metricFiltermetricsRegex matching the metric name
includeentityChangeArray of entity types to report on

Event types

Each type maps to a distinct event namespace on the controller's WebSocket stream.

TypeDescription
apiSessionAPI session created/deleted/refreshed
authenticationLogin success/failure
circuitFabric circuit lifecycle (created/deleted/failed/pathUpdated)
clusterHA cluster peer events
connectConnections to controllers/routers
entityChangeCRUD events for OpenZiti entities
entityCountPeriodic entity count snapshots
linkRouter-link lifecycle
metricsPerformance histograms (e.g., ctrl.latency, link.latency)
routerRouter online/offline
sdkSDK (identity) online/offline
serviceService dial metrics
sessionBind/dial session lifecycle
terminatorTerminator lifecycle
usageBandwidth counters (set version: 3)

Namespace filter

If set, only events whose namespace matches one of the listed values are forwarded. Empty list = forward everything.

enrichment: Resource name resolution

enrichment:
enabled: true
cache_ttl: 24h
cache_max_size: 10000

The enricher resolves OpenZiti resource IDs (services, identities, and edge routers) to human-readable names by querying the management API, caching results in memory.

FieldTypeDefaultDescription
enabledbooltrueEnable name resolution
cache_ttlduration24hHow long to cache lookups
cache_max_sizeint10000Maximum cache entries (FIFO eviction on overflow)

Enriched fields added per event type:

EventResolved Fields
usageservice_name, identity_name, host_name, edge_router_name
circuitservice_name, identity_name, attributes
metrics (ctrl.latency)edge_router_name from source_entity_id
metrics (link.latency)source_edge_router_name, destination_edge_router_name
sdkidentity_name, attributes
routeredge_router_name
apiSessionidentity_name
linksource_edge_router_name, destination_edge_router_name
terminatorservice_name, edge_router_name
service.eventsservice_name

subscribers: Output targets

Each subscriber is enabled with enabled: true in its config block. Multiple subscribers can run in parallel — events are fanned out through an internal pub-sub bus, so a slow or failing subscriber never blocks the others.

SubscriberYAML keyDescription
stdoutstdoutWrite events to stdout as JSON (pretty or single-line)
Raw HTTPraw_httpPOST events to any HTTP endpoint (webhooks, Lambda URLs, Collector's webhookevent)
ElasticsearchelasticsearchBulk-index events into per-namespace datastreams
S3s3Batched JSONL uploads, partitioned by namespace/date
syslogsyslogForward each event as a single syslog message (TCP/UDP)
DatadogdatadogLogs intake and/or v2 metrics series
SplunksplunkHTTP Event Collector with optional indexer acknowledgement
OTel (OTLP)otelNative OTLP logs and metrics over HTTP or gRPC

See each subscriber's page for the full field reference, defaults, and tuning notes. Subscriber-by-subscriber throughput counters (delivered, dropped, QLEN) live in the TUI Throughput view (-tui, then tab to cycle).

Common tuning

Every subscriber accepts buffer_size, and HTTP-backed subscribers (raw_http, elasticsearch, s3, datadog, and splunk) also accept workers. Defaults are tuned for a small-to-medium network; raise them when you see sustained drops or high QLEN in the TUI Throughput view.

FieldApplies toDefaultDescription
buffer_sizeall1000In-memory channel capacity. When full, events bound for this subscriber are dropped (drops are counted per subscriber and visible in the TUI).
workersraw_http, elasticsearch, s3, datadog, splunkvariesNumber of goroutines doing parallel delivery. See each subscriber's page for its default.

Workers parallelize delivery only — events may arrive at the endpoint out of order when workers > 1. Most consumers (Elasticsearch, S3, alert backends) key on timestamp so this is harmless; if your downstream requires strict ordering, keep workers: 1.

Per-subscriber filtering

Every cost-sensitive sink — datadog.logs, splunk, otel.logs, elasticsearch, s3, and raw_http — accepts an optional include and exclude block. The connector evaluates these against the enriched event JSON and drops anything that doesn't pass before the event is batched or compressed, so filtered events never count against your ingest bill.

Use this when an upstream sink charges per event or per indexed field and you want to send only a subset. The two most common cases:

# Only ship circuit events whose event_type is not "created" — drop the
# noisy creates, keep failed / pathUpdated / deleted.
datadog:
logs:
enabled: true
namespace_filter: [fabric.circuits]
include:
- { field: event_type, not_equals: created }

# Ship usage events only for production services (name starts with "prod-").
splunk:
enabled: true
namespace_filter: [fabric.usage]
include:
- { field: service_name, regex: "^prod-" }

Semantics:

  • include is any-of — at least one condition must match. Empty include accepts every event.
  • exclude is none-of — if any condition matches, the event is dropped. Empty exclude drops nothing.
  • Both can be set; the event must pass include AND not match exclude.
  • namespace_filter (if set) runs first, so you can think of include/exclude as a finer-grained refinement of the namespaces you already opted in to.

Each condition is one field-level predicate. Field paths are gjson paths into the enriched event payload (so service_name, event_type, metrics.p99, tags.hostId all work). See Comparators under the triggers section below for the full set; exactly one comparator must be set per condition.

A condition with an invalid regex or no comparator is rejected at startup — the connector fails fast rather than silently letting everything through.

triggers: Rule-based alerting

Optional. Loads a separate rules file and fires webhooks when events match configured conditions. The condition vocabulary is the same as Per-Subscriber Filtering above — field + one comparator — but conditions inside a rule are AND'd (every condition must match) rather than OR'd.

triggers:
rules_file: "/etc/nf-data-connector/rules.yaml"
default_webhook:
url: "https://alerts.example.com/hooks/ziti"
method: "POST"
headers:
Authorization: "Bearer my-token"

Rule file format

A rules file contains a top-level rules array:

# rules.yaml
rules:
- name: circuit-failure
description: "Alert on circuit creation failures"
severity: critical
cooldown: 5m # optional: suppress duplicate alerts
conditions:
- field: namespace
equals: circuit
- field: event_type
equals: failed

- name: high-ctrl-latency
description: "Controller latency p99 over 100ms"
severity: warning
cooldown: 10m
conditions:
- field: namespace
equals: metrics
- field: metric
equals: ctrl.latency
- field: metrics.p99
gt: 100000000 # 100ms in nanoseconds

- name: prod-identity-offline
description: "Production identity disconnected"
severity: critical
webhook: # per-rule override
url: "https://pagerduty.example.com/hooks/ziti"
conditions:
- field: namespace
equals: sdk
- field: event_type
equals: sdk-offline
- field: attributes
in_array: "prod-users"

All conditions in a rule are AND'd — every condition must match. For OR logic, create separate rules.

Comparators

Each rule condition uses one of the following comparators. The same vocabulary is used by per-subscriber include/exclude filters above.

ComparatorDescriptionExample
equalsExact string matchfield: namespace, equals: circuit
not_equalsString negationfield: event_type, not_equals: created
containsSubstring matchfield: service_name, contains: prod
regexRE2 regexfield: identity_name, regex: "^prod-.*"
gt / gte / lt / lteNumeric comparisonfield: metrics.p99, gt: 50000000
existsField presencefield: tags.hostId, exists: true
in_arrayValue in array fieldfield: attributes, in_array: "prod-users"

Fields can be nested (e.g., metrics.p99, tags.hostId) using gjson path syntax.

Alert payload

When a rule fires, the connector POSTs this payload to the configured webhook URL:

{
"rule": "circuit-failure",
"description": "Alert on circuit creation failures",
"severity": "critical",
"fired_at": "2026-04-13T12:34:56Z",
"event": { "...": "the full enriched event..." }
}

logging

Configure the log level and output format:

logging:
level: "info" # debug, info, warn, error
format: "text" # text or json

Environment variables

Secrets should come from environment variables rather than being written into the YAML file. Env vars override YAML values.

VariableOverridesNotes
ZITI_USERNAMEcontroller.usernameOpenZiti controller username
ZITI_PASSWORDcontroller.passwordOpenZiti controller password
ES_USERNAMEsubscribers.elasticsearch.usernameElasticsearch username
ES_PASSWORDsubscribers.elasticsearch.passwordElasticsearch password
DD_API_KEYsubscribers.datadog.api_keyDatadog API key

How those env vars reach the connector depends on how it's installed:

Install methodWhere to set env vars
Debian package (systemd)/etc/nf-data-connector/env, loaded via EnvironmentFile= in a systemd override (see Install on Debian)
Docker-e VAR=value flags, --env-file, or the environment: block in compose (see Install with Docker)
Standalone binaryExported in the shell or in the launchd / Windows-service environment block

AWS credentials for the S3 subscriber: the S3 subscriber uses the standard AWS SDK credential chain — there is no project-specific override. It picks up, in order:

  • AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN env vars
  • ~/.aws/credentials and ~/.aws/config files (respecting AWS_PROFILE)
  • EC2 instance metadata (IMDS)
  • ECS/EKS task role credentials

Command-line flags

Pass these flags when starting nf-data-connector:

FlagDefaultDescription
-config <path>config.yamlPath to config file
-tuioffLaunch the interactive terminal UI instead of stream mode