Complete field reference for custom rule files. For an introduction to rules and
built-in rules, see Rules.
Rule file structure
| Field | Type | Required | Description |
|---|
name | string | yes | unique within the bundle |
description | string | no | help text for managing rules |
facts | list | yes | connection-level filters; at least one with connection_kind |
conditions | list | yes | per-message filters; at least rule_type |
default | action | yes | action when no rule body matches |
trace | bool | no | enable per-rule tracer output (debug only, do not use in production) |
rules | list | yes | one or more rule bodies |
Actions
Valid values for default, success, and fail:
| Action | Terminal | Description |
|---|
allow | no | permit the operation |
deny | yes | reject the operation and close the connection |
error | yes | same as deny, recorded with error metrics |
suspend | no | park the connection — keep alive but drop the backend connection |
log | no | log the raw protocol to the auditor, continue evaluation |
Terminal actions (deny, error) stop all further rule evaluation and return
immediately. Non-terminal actions (allow, log, suspend) accumulate and
evaluation continues.
Facts
Static properties of a connection, set once at connect time. The engine
pre-filters the ruleset using facts — rules whose facts don't match are never
evaluated for that connection.
| Key | Values | Description |
|---|
connection_kind | client, leaf | required on every rule |
remote_ip | IP address | exact string match on source IP |
remote_ip uses string equality only. For CIDR-based IP filtering,
use matchCIDR(Meta.Address, "10.0.0.0/8") in a rule expression.
Entries use OR logic within the same key and AND across different keys.
Conditions
Conditions filter per protocol message and determine whether a rule applies.
Rule type (required)
| Key | Values | Description |
|---|
rule_type | connect, message | which protocol messages this rule handles |
Direction
| Key | Values | Description |
|---|
direction | to_backend, from_backend, both, inherit | traffic direction filter |
inherit (or omitting direction) uses the port's default_rule_direction.
Connect conditions
Available for rule_type: connect and rule_type: message:
| Key | Type | Matches against |
|---|
username | string | Connect.Username |
password | string | Connect.Password |
token | string | Connect.Token |
nkey | string | Connect.Nkey |
jwt | string | Connect.JWT |
name | string | Connect.Name (connection name) |
lang | string | Connect.Lang |
version | string | Connect.Version |
protocol | int | Connect.Protocol version number (0 or 1) |
Account conditions
Available for rule_type: message:
| Key | Type | Matches against |
|---|
account | string | AccountInfo.Account |
is_system_account | bool | AccountInfo.IsSystemAccount |
Message conditions
Available for rule_type: message:
| Key | Type | Matches against |
|---|
subject | string | exact match on Message.Subject |
subject_match | string | NATS wildcard match on Message.Subject |
subject_not_match | string | negative NATS wildcard match |
reply_to | string | exact match on Message.ReplyTo |
has_header | string | true if header key exists |
not_header | string | true if header key does not exist |
Conditions use OR within the same key, AND across different keys.
Rule bodies
| Field | Type | Required | Description |
|---|
expression | string | yes | Expr expression that evaluates to a boolean |
success | action | no | action when expression returns true |
fail | action | no | action when expression returns false |
message | string | no | shown in audit logs on deny/suspend |
Both success and fail can be set on the same rule body.
Evaluation environment
| Field | Type | Expr access | Description |
|---|
Direction | string | Meta.Direction | to_backend or from_backend |
DefaultDirection | string | Meta.DefaultDirection | port's default direction |
Host | string | Meta.Host | gateway hostname |
Address | string | Meta.Address | client network address |
RemoteServer | string | Meta.RemoteServer | remote server name |
RemoteHost | string | Meta.RemoteHost | remote host IP |
Time | string | Meta.Time | RFC3339 timestamp |
ConnectionKind | int | Meta.ConnectionKind | 1=client, 2=leaf (rarely needed — facts already filter on connection_kind) |
ProtoLen | int | Meta.ProtoLen | protocol message length |
Connect
| Field | Type | Expr access | Description |
|---|
Username | string | Connect.Username | basic auth username |
Password | string | Connect.Password | basic auth password |
Token | string | Connect.Token | auth token |
Nkey | string | Connect.Nkey | NKey public key |
JWT | string | Connect.JWT | JWT credential |
Sig | string | Connect.Sig | signature |
Name | string | Connect.Name | client/server name |
Lang | string | Connect.Lang | client language |
Version | string | Connect.Version | client version |
Protocol | int | Connect.Protocol | protocol version |
Account | string | Connect.Account | account name |
Echo | bool | Connect.Echo | echo mode |
Verbose | bool | Connect.Verbose | verbose mode |
Pedantic | bool | Connect.Pedantic | pedantic mode |
TLSRequired | bool | Connect.TLSRequired | TLS required |
Headers | bool | Connect.Headers | headers support |
NoResponders | bool | Connect.NoResponders | no responders |
AccountNew | bool | Connect.AccountNew | new account flag |
ProxySig | string | Connect.ProxySig | proxy signature |
Leaf-only fields:
| Field | Type | Expr access | Description |
|---|
ID | string | Connect.ID | server ID |
ServerName | string | Connect.ServerName | server name |
RemoteAccount | string | Connect.RemoteAccount | remote account |
Cluster | string | Connect.Cluster | cluster name |
Hub | bool | Connect.Hub | is hub |
Domain | string | Connect.Domain | domain |
JetStream | bool | Connect.JetStream | JetStream enabled |
Compression | string | Connect.Compression | compression mode |
DenyPub | []string | Connect.DenyPub | denied publish subjects |
Isolate | bool | Connect.Isolate | isolation flag |
Import | SubjectPermission | Connect.Import.Allow | import permissions |
Export | SubjectPermission | Connect.Export.Allow | export permissions |
Message
| Field | Type | Expr access | Description |
|---|
Subject | string | Message.Subject | message subject |
SID | string | Message.SID | subscription ID |
ReplyTo | string | Message.ReplyTo | reply subject |
Payload | []byte | Message.Payload | message body |
Headers | map[string][]string | Message.Headers | NATS headers |
Queues | []string | Message.Queues | queue groups |
AccountInfo
| Field | Type | Expr access | Description |
|---|
Account | string | AccountInfo.Account | account name |
IsSystemAccount | bool | AccountInfo.IsSystemAccount | system account flag |
Config
Available for built-in rules only. Contains the rule's configuration as set in
the .conf file. nil for custom rules.
Custom functions
Subject functions
| Function | Returns | Description |
|---|
subjectMatch(subject, pattern) | bool | NATS wildcard match (* matches one token, > matches one or more) |
subjectHasWildcards(subject) | bool | true if subject contains * or > |
isLiteralSubject(subject) | bool | true if subject has no wildcards |
JetStream functions
| Function | Returns | Description |
|---|
normalizeJSSubject(subject) | string | strip domain/prefix from JetStream subjects to $JS.API... form |
fromJsRequest() | typed struct | parse JetStream request from message payload; returns the appropriate jsm.go API type (cached per message) |
hasAllowedConsumerFilter(allowed) | bool | true when all consumer filter subjects are within at least one allowed pattern |
hasDeniedConsumerFilter(denied) | bool | true when any consumer filter subject overlaps a denied pattern |
| Function | Returns | Description |
|---|
hasHeader(config, headers) | bool | check headers against config map; keys are header names, values are regex patterns (empty = existence check); OR logic across entries |
Payload functions
| Function | Returns | Description |
|---|
payloadMatches(config, subject, payload) | bool | match payload against regex based on subject pattern |
regexMatch(str, pattern) | bool | Go regex match (cached) |
bytesToString(data) | string | convert payload bytes to string |
Time functions
| Function | Returns | Description |
|---|
matchesTime(schedule, timestamp) | bool | cron schedule match; format: minute hour day month weekday; truncated to minute precision |
Rate limit functions
| Function | Returns | Description |
|---|
connectionMessageRateExceeded(interval, messages) | bool | true when the connection exceeds messages per interval in the rule's direction (token bucket) |
connectionBytesRateExceeded(interval, bytes) | bool | true when the connection exceeds bytes of payload per interval in the rule's direction (token bucket) |
See Rate limit for details.
Network functions
| Function | Returns | Description |
|---|
matchCIDR(address, cidr) | bool | IPv4/IPv6 CIDR match (cached) |
Auth functions
| Function | Returns | Description |
|---|
IsTrustedExternalSigner(token, config) | bool | JWT signature verification; config format: algorithm:base64key |
Utility functions
| Function | Returns | Description |
|---|
infoLog(message, ...params) | bool | log at info level; always returns true |
debug(...params) | bool | debug output to stderr; always returns true |
Evaluation flow
Fact filtering
When a client or leafnode connects, the engine filters the port's ruleset
against the connection's facts. Only matching rules are kept for that
connection's lifetime.
When a bundle is activated, deactivated, or upgraded on a port, all active
connections on that port are re-evaluated. If the changed ruleset contains
connect rules matching a connection's facts, the connection is disconnected to
force a full re-evaluation on reconnect.
Per-message evaluation
For each protocol message, the engine iterates through the filtered ruleset:
- Condition matching — conditions are grouped by key. Within a key, values use
OR logic. Across keys, AND logic. If conditions don't match, the rule is
skipped.
- Rule body evaluation — rule bodies are evaluated in order. Each expression
returns a boolean; the corresponding
success or fail action is applied.
- Short-circuit on deny/error — if any body returns
deny or error,
evaluation stops immediately.
- Rule default — if no rule body produced a result, the rule's
default action
is used.
- No rules matched — if no rules produced any results, the port's unmatched
action applies (defaults to
deny).