pub struct Gateway {Show 39 fields
pub version: u32,
pub listeners: Vec<Listener>,
pub routes: Vec<Route>,
pub services: Vec<Service>,
pub upstreams: Vec<Upstream>,
pub consumers: Vec<Consumer>,
pub policies: Vec<Policy>,
pub global_policies: Vec<String>,
pub authorization: Option<Authz>,
pub default_security_headers: Option<SecurityHeaders>,
pub waf: Option<GlobalWaf>,
pub trusted_proxies: Vec<String>,
pub max_concurrent_requests: Option<u32>,
pub load_shed_dry_run: bool,
pub jwt_providers: Vec<JwtProvider>,
pub admin: Option<AdminConfig>,
pub allow_empty_routes: bool,
pub hmac_auth: Option<HmacAuth>,
pub webhooks: Vec<Webhook>,
pub analytics: Option<AnalyticsConfig>,
pub analytics_stream: Option<AnalyticsStreamConfig>,
pub geoip: Option<GeoipConfig>,
pub admission_queue: Option<AdmissionQueue>,
pub mtls_consumer_mapping: Option<MtlsConsumerMapping>,
pub mtls_forward_headers: Option<MtlsForwardHeaders>,
pub license: Option<LicenseConfig>,
pub oidc_providers: Vec<OidcProvider>,
pub redis_rate_limiter: Option<RedisRateLimiterConfig>,
pub redis_quotas: Option<RedisQuotaConfig>,
pub redis_cache: Option<RedisCacheConfig>,
pub config_convergence: Option<ConfigConvergenceConfig>,
pub plugins: Vec<PluginConfig>,
pub plugin_registry: Option<PluginRegistryConfig>,
pub filter_chain: Option<FilterChainConfig>,
pub ai: Option<AiConfig>,
pub fleet: Option<FleetConfig>,
pub lifecycle: Option<LifecycleConfig>,
pub mesh: Option<MeshConfig>,
pub ssrf_filter: Option<SsrfFilterConfig>,
}Expand description
Root of a dwara configuration: one gateway process, N listeners, and one compiled config generation.
Fields§
§version: u32CFG-03 (#239): config schema version. Defaults to 1 when
absent (the initial schema). The dwara lint command warns
when the version is older than the current schema version; the
dwara migrate command upgrades the config to the current
version.
listeners: Vec<Listener>Entry points the gateway binds.
routes: Vec<Route>Match rules routing requests to services.
services: Vec<Service>Logical APIs being exposed.
upstreams: Vec<Upstream>Load-balancing pools.
consumers: Vec<Consumer>API caller identities.
policies: Vec<Policy>Named reusable rule bundles.
global_policies: Vec<String>Gateway-level (global) policy attachment (#123): names of policies
from the policies list that apply to EVERY request the gateway
serves — the LEAST specific link of the frozen precedence chain
consumer > route > service > listener > global. Named
global_policies (not policies, which is the policy REGISTRY at
this level) so the two roles cannot be confused. All applicable
levels’ rules AND together (see the rate-limiter module docs), so a
global policy is an additional constraint on every request, not a
default that more specific levels replace. Global policies also
apply to UNROUTED traffic: a request whose path matches no route
is rate-limited by them before the 404 is answered (the reserved
paths /healthz, /readyz, and /metrics stay exempt).
Gateway-level (global) authorization rules (#123): the least
specific link of the authorization precedence chain
consumer > route > service > listener > global (see Authz for
the rule semantics and the authz module for the merge: a deny at
ANY level wins; otherwise the most specific level with rules
governs). Applies to every request that resolved a route
(authorization runs after route resolution per the documented
request-path order). Same validation rules as route-level
authorization; see Authz.
default_security_headers: Option<SecurityHeaders>Gateway-level default security headers baseline (SEC-09, #213):
applied to EVERY route that does not carry its own
security_headers block and has not set
security_headers_opt_out: true. Fail-secure defaults: a
route with no security_headers block inherits this posture
rather than shipping without HSTS/nosniff. A route that needs
to disable a header from the default sets its own
security_headers block (which fully replaces the default
for that route), or sets security_headers_opt_out: true to
opt out entirely. See SecurityHeaders.
waf: Option<GlobalWaf>SEC-08 (#212): Global WAF policy with CRS-compatible rules.
When enabled, the rules are evaluated on every request
(regardless of route-level WAF config). The anomaly score is
accumulated across all matching rules; the request is blocked
when the score exceeds the threshold. See GlobalWaf.
trusted_proxies: Vec<String>IP addresses / CIDR ranges of proxies whose X-Forwarded-For claims
are trusted (gateway-level; the direct connection peer must be in
this list for an inbound XFF chain to be preserved and extended).
Each entry must be an IP address (e.g. 10.1.2.3) or a CIDR
(e.g. 10.0.0.0/8); anything else fails validation. Empty (the
default) trusts nobody: every proxied request carries an XFF of
exactly the direct peer, and inbound XFF values are discarded.
max_concurrent_requests: Option<u32>Gateway-level concurrency cap (DW-015): the maximum number of
requests admitted concurrently across the WHOLE gateway. Absent
(the default) is unlimited; 0 is invalid (validation rejects it —
omit the field for unlimited). Over-cap requests are rejected
immediately with 503 “gateway saturated” (no queueing). A slot is
reserved at request admission and released when the response body
completes (or the connection drops). The reserved paths
/healthz and /readyz bypass the cap so liveness/readiness
probes still answer under saturation.
load_shed_dry_run: boolMonitor mode (DW-041) for the gateway concurrency cap’s load
shedding: when the cap is saturated and a request would be shed,
the would-shed is LOGGED and counted
(dwara_policy_dry_run_total{phase="load_shed"} + a
dwara::policy warn event) and the request is ADMITTED over the
cap instead — deliberately exceeding max_concurrent_requests so
an operator can observe what a cap would shed (and at which
priorities) before enforcing it. Only meaningful with a cap set;
validation rejects it on an uncapped gateway (it would be a
no-op flag that reads as coverage).
jwt_providers: Vec<JwtProvider>JWT verification providers (DW-019): trusted token issuers whose
keys are fetched from a JWKS endpoint. Each provider independently
verifies Authorization: Bearer tokens (alg allowlist, iss/aud,
exp with leeway) and maps the token to a consumer — via the
provider’s explicit consumer binding, or by matching a
consumer’s jwt credential issuer against the token’s iss
claim. Empty (the default): the gateway does not interpret Bearer
tokens and forwards Authorization upstream untouched.
admin: Option<AdminConfig>Admin API listener (DW-022, decision 6): mTLS-ONLY management
endpoint. Absent (the default): no admin listener is started at
all — the gateway is admin-silent until an operator configures
one. When present, tls must carry all three files (server
cert, key, and the CA that client certificates must chain to);
a missing client_ca_file is rejected by validation — plaintext
admin is not a supported production shape. The dev fallback
(DWARA_ADMIN_DEV=1, dwara-bin) allows loopback-only plaintext
and is loudly dev-only. The admin listener’s bind set is fixed
at startup; changes take effect on restart.
allow_empty_routes: boolDeliberate opt-in to running a gateway with ZERO routes (#129, maintainer decision). Default false: validation rejects a route-less config. An empty route set is schema-valid (every collection defaults empty), and a truncated or torn config write (truncate-then-save, common in naive editors) is schema-valid too — publishing it would drop ALL routing mid-run (every request 404s while the file “looks fine”). The guard applies to cold start AND hot reload alike; a rejected reload keeps the running generation serving. Set this to true only for deliberate route-less shapes (e.g. a gateway whose sole job is the admin API): with the flag set, unrouted requests answer 404 after listener/global policy checks, per the documented request-path order.
hmac_auth: Option<HmacAuth>HMAC request-signing verification policy (DW-036): the
gateway-wide clock-skew window applied to the
X-Dwara-Timestamp header of every signed request. Absent
(the default) = DEFAULT_HMAC_CLOCK_SKEW_SECS (±5 minutes).
See the security::authn module docs for the full
signing contract (canonical string, headers, replay window).
webhooks: Vec<Webhook>Alert/event webhook targets (DW-044): every gateway event whose
kind appears in a target’s events list is POSTed to that
target’s url as one JSON envelope (id, kind, timestamp,
gateway instance, payload). Delivery runs on a background task,
never on the request path; emission is a bounded non-blocking
hand-off (a full queue drops the event and counts the drop), so
webhook failures can never stall the dataplane. Header values
may be inline or ${...} secret references (DW-045) — inline
values are redacted in every config echo. See the events
module docs for the envelope, the retry/budget shape, and the
egress posture. Empty (the default): no webhooks, and events
are still counted (emitted/dropped) but delivered nowhere.
analytics: Option<AnalyticsConfig>The embedded analytics store (DW-043). Absent (the default):
no analytics database, request records go nowhere beyond the
Prometheus families and the sampled access log, and the admin
API’s analytics endpoints answer 404. When present, the
gateway opens a SEPARATE SQLite file (never the state store’s
database) at path, feeds every completed request’s access
record to it on a fire-and-forget channel (a full channel
DROPS and counts — analytics can never slow the dataplane),
rolls raw records up through 1m/5m/1h/1d additive tables with
per-granularity retention, and serves the dashboard/Top-N/
structured-query endpoints from the admin listener. See the
analytics module docs for the write path and the bounded-disk
story. Part of startup wiring (the database opens once); the
DIMENSIONS list is read live from the current generation so a
reload can add or rename dimensions without a restart.
analytics_stream: Option<AnalyticsStreamConfig>Real-time access-record stream (DW-121, the opt-in firehose out):
every completed request’s access record — not rollups, not the
discrete DW-044 ops events — streamed to an external sink in
flushed batches. Complements, never replaces, the embedded
analytics store: the two are configured independently and a
deployment can run either, both, or neither. Absent (the
default): no stream. The pipeline is fire-and-forget end to end
(a bounded channel that drops and counts — it can never slow or
block the dataplane). See the events::stream module docs for
the wire format, the batching contract, and the failure
isolation story. Startup wiring arms the pipeline (the channel
capacity is fixed at boot); the sink set — including the
enabled/disabled state — is live per config generation.
geoip: Option<GeoipConfig>The GeoIP database (DW-050): MaxMind-format .mmdb file backing
authorization.geoip country/ASN predicates. Absent: geo rules
are rejected by validation (an unevaluable gate is an authoring
error, not a silent pass).
admission_queue: Option<AdmissionQueue>Bounded admission queues (DW-053): when the gateway concurrency
cap (max_concurrent_requests) is saturated, requests WAIT for a
permit up to queue_timeout_ms instead of being immediately
shed. This produces a graceful degradation curve (latency rises
before shedding begins) rather than the cliff of immediate
shedding. Absent (the default): the DW-016 behavior stands —
over-cap requests are shed immediately with 503. Requires
max_concurrent_requests (validation rejects an enabled queue
on an uncapped gateway, the same rule as load_shed_dry_run).
mtls_consumer_mapping: Option<MtlsConsumerMapping>mTLS client-certificate consumer mapping (DW-035): maps a
VERIFIED client certificate (its SHA-256 fingerprint or subject
CN) to a consumer name, so a client presenting a valid mTLS
certificate is authenticated WITHOUT an API key, JWT, or other
header credential — the certificate IS the credential. The
certificate must still chain to a listener’s client_ca_file
(verified at the TLS layer); this mapping only resolves an
ALREADY-VERIFIED certificate to a consumer. Distinct from the
per-consumer mtls credential (which binds a cert to ONE
consumer’s credential list): this is a gateway-level table that
can map certificates independent of the consumer credential
registry. Absent (the default): mTLS certificates are matched
only through consumers’ mtls credentials (the DW-019 path).
mtls_forward_headers: Option<MtlsForwardHeaders>Identity-forwarding headers (DW-035): when mTLS client auth is
used, the gateway forwards client certificate metadata to the
upstream as X-Client-Cert-* headers. These headers are
GATEWAY-SET: any inbound headers with these names are STRIPPED
from the client request before the gateway adds its own
(spoofing prevention — the “without headers spoofing” part of
the done-when). Absent (the default): no X-Client-Cert-*
headers are forwarded.
license: Option<LicenseConfig>Enterprise license configuration (DW-032). Absent (the default):
the gateway runs in OSS mode — all features available are
OSS-only and no license verification occurs. When present, the
gateway verifies the license file at startup (if compiled with
the ent cargo feature) and gates enterprise features behind
the license’s feature claims. The public key is NOT configured
here — it comes from the DWARA_LICENSE_PUBLIC_KEY env var (or
the compiled-in development key when unset), never
user-configurable, so an operator cannot substitute their own
key to forge a license. When the ent feature is NOT compiled
in, the block is accepted but inert (the gate is always
LicenseGate::none()).
oidc_providers: Vec<OidcProvider>OIDC providers (DW-034): trusted OpenID Connect issuers whose
Bearer tokens are validated by token introspection (RFC 7662)
rather than local JWT signature verification. Each provider
independently introspects Authorization: Bearer tokens that did
not verify against any JWT provider (DW-019) and maps the
introspection result to a consumer via the provider’s explicit
consumer binding. The gateway also supports the
authorization-code + PKCE flow (acting as an OIDC relying party),
token exchange (RFC 8693), and token revocation (RFC 7009). Empty
(the default): the gateway does not introspect Bearer tokens and
OIDC is inert. See the security::oidc module docs for the full
flow, caching, and fail-open/fail-closed posture.
redis_rate_limiter: Option<RedisRateLimiterConfig>Distributed Redis rate limiter (DW-031). Absent (the default):
the local in-memory GCRA limiter is used (one limit per
process). When present, the ent cargo feature is compiled in,
AND a valid license with the redis_rate_limiter feature claim
is loaded, the gateway uses a Redis-backed GCRA limiter so two
or more instances share one rate limit. The same GCRA algorithm
runs, but the bucket state lives in Redis and is updated
atomically via a Lua script in a single round-trip. When the
ent feature is NOT compiled in, or the license lacks the
claim, the block is accepted but inert (the local limiter is
used and a warning is logged). When Redis is unreachable,
fail_open (default true) lets requests through; false
rejects with 429.
redis_quotas: Option<RedisQuotaConfig>Distributed Redis-backed consumer request quotas (DW-155, ent
feature). Absent (the default): the local SQLite-backed quota
checker is used (one counter per instance, so a fleet of N
instances enforces N x the configured cap). When present, the
ent cargo feature is compiled in, AND a valid license with the
redis_quotas feature claim is loaded, the gateway uses a
Redis-backed quota checker so two or more instances share one
counter per (consumer, budget, window) — a fleet of N instances
enforces the CONFIGURED cap. The same daily/monthly budget
semantics run, but the counters live in Redis and are updated
atomically via a Lua script in a single round-trip. When the
ent feature is NOT compiled in, or the license lacks the
claim, the block is accepted but inert (the local SQLite checker
is used and a warning is logged). When Redis is unreachable,
fail_open (default true) lets requests through; false
rejects with 429.
redis_cache: Option<RedisCacheConfig>Distributed Redis-backed response cache (SCALE-04, #183, ent
feature). Absent (the default): the local in-memory moka cache
is used (one cache per instance, so a fleet of N instances has
N x cold caches). When present, the ent cargo feature is
compiled in, AND a valid license with the redis_cache feature
claim is loaded, the gateway uses a Redis-backed response cache
so two or more instances share one cache — fleet-wide hit
ratios. A local moka tier can front Redis (two-tier with Pub/Sub
invalidation) or be disabled for a pure Redis cache. When the
ent feature is NOT compiled in, or the license lacks the
claim, the block is accepted but inert (the local moka cache is
used and a one-line notice is logged at startup).
config_convergence: Option<ConfigConvergenceConfig>Config convergence (DW-054, enterprise feature). Absent (the
default): each gateway instance serves only its local config
generation and never watches remote instances. When present,
the ent cargo feature is compiled in, AND a valid license
with the config_convergence feature claim is loaded, the
gateway publishes its config generation to a shared backend
(Redis in v1; etcd/Consul are deferred behind the
ConfigConvergenceBackend trait) and polls for generations
published by other instances, converging to the highest
generation within the poll interval. A drift report is emitted
at drift_check_interval_ms when instances diverge. When the
ent feature is NOT compiled in, or the license lacks the
claim, the block is accepted but inert (the local file watcher
runs alone) and a one-line notice is logged at startup.
plugins: Vec<PluginConfig>Proxy-wasm plugin definitions (DW-055). Each plugin is a .wasm
module loaded and compiled with every config generation
(checksum-keyed hot-swap) and run on the request pipeline
phases it declares. Routes reference plugins by name via their
plugins field; the dataplane dispatches them through the
unified plugin chain (DW-157). A plugin whose .wasm cannot be
read or compiled is marked crashed at load time (logged) and
routes referencing it answer 500 fail-closed.
plugin_registry: Option<PluginRegistryConfig>SCALE-12 (#192): remote/signed plugin registry configuration.
When present, plugin source.url references are resolved
against the registry’s base URL and signatures are verified
against the registry’s pinned public keys. See
PluginRegistryConfig.
filter_chain: Option<FilterChainConfig>SCALE-12 (#191): global filter-chain ordering and dry-run
configuration. Per-route filter_chain overrides take
precedence. See FilterChainConfig.
ai: Option<AiConfig>The AI provider-adapter pack (DW-075): the provider pool and the
model alias table behind every ai route action. Absent (the
default): no AI surface — an ai route action is rejected by
validation. When present, clients send OpenAI chat-completions
shaped requests to an ai route and the gateway translates to
the target provider’s wire format (OpenAI, Anthropic, Gemini),
normalizing responses (and streaming deltas) back to the OpenAI
shape. See ai::AiConfig and the ai domain docs.
fleet: Option<FleetConfig>Fleet operations (DW-098, enterprise feature). Absent (the
default): no fleet skew policy is enforced — the controller
accepts edges regardless of version. When present, the ent
cargo feature is compiled in, AND a valid license with the
fleet_operations feature claim is loaded, the controller
checks each connecting edge’s version against the skew policy
and the admin API exposes GET /fleet/skew (per-edge skew
status) and GET /fleet/status (fleet-wide convergence +
version distribution). When the ent feature is NOT compiled
in, or the license lacks the claim, the block is accepted but
inert (the controller accepts all edges).
lifecycle: Option<LifecycleConfig>API lifecycle management (DW-110): the developer portal
(auto-generated from OpenAPI specs), environment profiles
(dev/staging/prod config overlays), and the API journey
recorder (request flow visualization for debugging). Absent
(the default): no lifecycle surface. The portal serving, profile
overlay application, and journey recording are scaffolded: the
block is accepted in every build and is inert until the runtime
wiring lands (validation
warns). See LifecycleConfig.
mesh: Option<MeshConfig>Service mesh mode (DW-107, enterprise feature). Absent (the
default): the gateway runs as a regular reverse proxy. When
present, the mesh cargo feature is compiled in, AND a valid
license with the service_mesh feature claim is loaded, the
gateway runs as a sidecar in each pod: an init container
configures iptables/TPROXY redirects so all traffic to and from
the local application flows through the sidecar, which
terminates mTLS (inbound) and wraps mTLS (outbound) using
SPIFFE/SPIRE X.509 SVIDs fetched from the SPIRE Workload API.
When the mesh feature is NOT compiled in, or the license
lacks the claim, the block is accepted but inert (validation
warns, no sidecar listeners or SPIFFE client are wired). Ent-
only: validation warns when mesh is configured without the
ent feature. See mesh::MeshConfig and the mesh domain
module docs.
ssrf_filter: Option<SsrfFilterConfig>SSRF egress filter (SEC-13): when enabled, outbound connections
from webhook deliveries and OPA callouts are checked against a
deny set of private/loopback/link-local/metadata IP ranges.
An optional allowlist exempts specific CIDRs. Default disabled
(the v1 posture trusts operator-configured endpoints). See
ssrf::SsrfFilterConfig and ssrf::SsrfFilter.
Implementations§
Source§impl Gateway
impl Gateway
Sourcepub fn redacted(&self) -> Gateway
pub fn redacted(&self) -> Gateway
A display-safe copy of this config (DW-045): every INLINE
api_key value is replaced by the
credentials::redact_inline_secret placeholder
(${redacted:sha256:<prefix>}); ${...} references pass through
unchanged (an env-var name or file path is not secret bytes —
the config file itself carries it). This is the TYPED redaction
behind every surface that echoes configuration (admin
GET /config); it is deliberately a transform, not a custom
serializer, so it cannot drift from the schema — a future
secret-bearing field fails visibly (its value reaches the dump
unredacted) instead of silently escaping an allowlist regex.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for Gateway
impl<'de> Deserialize<'de> for Gateway
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl JsonSchema for Gateway
impl JsonSchema for Gateway
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn inline_schema() -> bool
fn inline_schema() -> bool
$ref keyword. Read moreimpl StructuralPartialEq for Gateway
Auto Trait Implementations§
impl Freeze for Gateway
impl RefUnwindSafe for Gateway
impl Send for Gateway
impl Sync for Gateway
impl Unpin for Gateway
impl UnwindSafe for Gateway
Blanket Implementations§
§impl<T> AnyExt for T
impl<T> AnyExt for T
§fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
T behind reference§fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
T behind mutable reference§fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
T behind Rc pointer§fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
T behind Arc pointer§fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>where
T: Any,
fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>where
T: Any,
T behind Box pointer§fn downcast_move<T>(this: Self) -> Option<T>
fn downcast_move<T>(this: Self) -> Option<T>
Self to T,
useful only in generic context as a workaround for specializationSource§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
fn coerce_rc_to(self: Rc<X>) -> Rc<T>
fn coerce_box_to(self: Box<X>) -> Box<T>
fn coerce_ref_to(&self) -> &T
fn coerce_mut_to(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more