DNS feed schemas
Catalog
| Logical feed | Customer topic | Records |
|---|---|---|
dns.logs.ops | cnx.customer.<customer_id>.dns.logs.ops | Approval, validation, deployment, ownership, and alias events |
dns.logs.platform | cnx.customer.<customer_id>.dns.logs.platform | Selected Knot signing and zone-distribution events |
dns.queries.detail | cnx.customer.<customer_id>.dns.queries.detail | Sampled classified DNS responses |
dns.queries.summary | cnx.customer.<customer_id>.dns.queries.summary | Unsampled classified response counts |
Subscriptions select feeds individually. The exact granted topics are in
connection.yml. See Delivery and compatibility for
retention, transport losses, replay, and schema evolution.
Common fields
| Field | Type | Meaning |
|---|---|---|
timestamp | string | UTC RFC 3339 time with nine fractional digits: source journal time for logs, dnstap response time for detail, or counting-window start for summaries |
server | string | Host producing the source event |
customer_id | string | Canonical customer identifier |
zone | string | Absolute zone name with a trailing dot; may be absent from repository-level operations |
The JSON timestamp is the event time. Nine fractional digits express resolution; clock accuracy and cross-host alignment are described in Time provenance.
For SIEM field mapping and correlation, see Ingesting DNS telemetry.
Delivery and compatibility
| Feed | Behavior |
|---|---|
dns.logs.ops | Confirmed-delivery cursor with deterministic event_id; replay may duplicate records. Deduplicate by event_id. |
dns.logs.platform | Best-effort delivery of selected platform events; transport backpressure can drop records. |
dns.queries.detail | Best-effort delivery with producer sampling and a default customer delivery sample of up to 100 records per second across the fleet. Full producer-selected fleet delivery is available on request, up to 10,000 records per second. |
dns.queries.summary | Unsampled classified counts in 60-second windows; best-effort transport can still lose summary records. |
DNS serving continues independently of Kafka and customer consumption. CNX's central logging platform is the durable authority for DNS operations and platform logs. Absence from the SIEM feed does not prove that a source event did not occur. An unsampled summary describes the events counted by its producer, not a guarantee that every summary reaches the SIEM.
DNS records have no inline schema-version field. The topic identifies the
feed, and action identifies the log event type where present. Optional
fields may be added within the contract. Renaming or removing a documented
field, changing its type, or changing an action's meaning requires a
versioned contract and a customer migration plan.
Operations log: dns.logs.ops
Every record contains the common fields except that zone is conditional,
plus:
| Field | Type | Meaning |
|---|---|---|
event_id | string | Deterministic 32-character hexadecimal replay-deduplication identifier |
actor | string | dns-ops or dns-aliases |
actor_type | string | system |
action | string | Event type from the catalog below |
log_level | string | Source severity, normally info, warning, or error |
message | string | Source event text for analyst display |
Conditional correlation fields:
| Field | Type | Meaning |
|---|---|---|
production_sha | string | Approved main revision being processed; its presence alone does not prove successful validation or deployment |
previous_production_sha | string | Previously accepted revision; omitted when there is none |
approved_by | array of strings | Normalized committer email identities from accepted first-parent merge history |
observed_sha | string | Repository head rejected by the authorization gate |
serial | integer | Confirmed zone serial after a successful update |
actor identifies the executing or observing system component. Human
approval is represented separately in approved_by. Individual commit
authors and merge-request submitters remain in the customer's Git history.
Action catalog
| Action | Level | Conditional fields | Meaning |
|---|---|---|---|
repo-config-enforcement-failed | error | none | Required repository protection or merge settings could not be enforced; processing stops for the cycle |
violation | error | observed_sha | Repository history failed the production-authorization gate |
change-approved | info | zone, production_sha, previous_production_sha, approved_by | An authorized revision changed the zone and processing began |
change-validated | info | zone, production_sha | Zone syntax and policy validation passed |
change-rejected | error | zone, production_sha | Validation failed; prior accepted state remains authoritative |
ownership-ksk-missing | warning | zone, production_sha | Required customer KSK was missing; ownership processing was skipped |
ownership-verify-ns | info | zone, production_sha | Ownership verified through NS delegation |
ownership-verify-txt | info | zone, production_sha | Ownership verified through the CNX TXT challenge |
ownership-token-generate | info | zone, production_sha | New verification token generated; the token is not emitted |
zone-provision | info | zone, production_sha | Zone added to Knot configuration |
zone-record-add-scheduled | info | zone, production_sha | Record shown in message scheduled for addition |
zone-record-remove-scheduled | info | zone, production_sha | Record shown in message scheduled for removal |
zone-change-applied | info | zone, production_sha, serial | Knot committed the change and the resulting serial was confirmed |
zone-change-failed | error | zone, production_sha | Deployment attempt failed |
alias-register | info | zone, production_sha | Configured alias entered processing |
alias-publish | info | zone, production_sha, serial | Alias answers changed and the new serial was confirmed |
alias-deregister | info | zone, production_sha | Alias removed from the registry after removal from accepted state |
alias-retract | warning | zone, production_sha | Answers retracted after the configured period without a DNSSEC-validated target answer |
Optional fields depend on the source event. Use action and structured
fields for correlation and alert rules; message is display text.
Deployment example
{
"timestamp": "2026-10-02T09:15:04.123456000Z",
"server": "dns-master.example.com",
"event_id": "7b52883921ee5bce81ffad6b1de3208a",
"actor": "dns-ops",
"actor_type": "system",
"action": "zone-change-applied",
"log_level": "info",
"customer_id": "123",
"zone": "example.com.",
"production_sha": "a1b2c3d4e5f60123456789abcdef0123456789abc",
"serial": 2026100201,
"message": "change committed successfully; zone serial 2026100201"
}
The normal change trace is change-approved, change-validated, scheduled
record operations, and zone-change-applied. Rejected validation and failed
deployment have separate actions. Scheduled record operations describe
intention; the applied event confirms the transaction result. Platform events
correlate by zone and serial because Knot has no Git-revision context.
Platform log: dns.logs.platform
Every record contains timestamp, server, actor, actor_type, action,
log_level, zone, customer_id, and message. actor is dns-master
or dns-slave; actor_type is system. The message preserves Knot log text.
| Action | Optional structured fields |
|---|---|
dnssec-signing-zone | none |
dnssec-signing-started | none |
dnssec-signing-complete | serial, rrsigs_added |
dnssec-incremental-signing-complete | serial, rrsigs_added |
dnssec-next-signing | next_signing_at |
dnssec-key-active | key_tag, algorithm, key_role, key_state |
zone-file-updated | previous_serial, serial |
zone-notify-outgoing | remote, serial |
zone-notify-incoming | remote, serial |
zone-transfer-incremental-outgoing | remote; started events may include previous_serial, serial; finished events may include duration_seconds, message_count, bytes |
zone-transfer-incremental-incoming | remote; started events may include previous_serial, serial; finished events may include remote_serial |
zone-transfer-full-outgoing | remote |
zone-transfer-full-incoming | remote |
zone-refresh | remote, remote_serial, expires_in_seconds |
Only recognized Knot message shapes are published. If an optional value cannot be extracted, the event is retained with that field omitted.
{
"timestamp": "2026-10-02T09:15:04.123450000Z",
"server": "dns-master.example.com",
"actor": "dns-master",
"actor_type": "system",
"action": "dnssec-signing-complete",
"log_level": "info",
"zone": "example.com.",
"customer_id": "123",
"serial": 2026100201,
"rrsigs_added": 7,
"message": "DNSSEC, successfully signed, serial 2026100201, new RRSIGs 7"
}Query detail: dns.queries.detail
Classified dnstap response events use the following fields:
| Field | Type | Meaning |
|---|---|---|
timestamp | string | DNS response time |
server | string | Authoritative server that answered |
query_transport | string | v4 or v6, after recovery of the original client address |
zone | string | Best matching served zone |
customer_id | string | Customer identifier for that zone |
qname | string or null | Absolute queried name |
qtype | string or null | Query type |
rcode | string | Response code |
src_v4, src_v6 | string or null | Recovered client address; normally exactly one is populated |
ecs_v4, ecs_v6 | string or null | EDNS Client Subnet value when supplied |
answer | array of strings | Text representation of each answer-section RDATA item |
answer_v4, answer_v6 | array of strings | A and AAAA answer values for indexing |
Query detail has two sampling stages:
| Stage | Scope | Selection |
|---|---|---|
| Producer | Each sink | At most 1,000 detail events per one-second window; uniform reservoir sampling above that threshold |
| Customer delivery | Your subscription, across all fleet sinks | By default, a further sample of up to 100 records per second |
Before publishing to your customer topic, CNX selects records from the fleet's query-detail stream according to your subscription's sampling level. The default limit applies across the fleet, rather than separately to each sink.
Request full fleet delivery from CNX if your consumer and SIEM can sustain up to 10,000 records per second. This removes the additional customer delivery sampling and provides the full producer-selected stream for your customer account. Per-sink producer sampling still applies, so full fleet delivery is not a complete record of every DNS query. Delivery remains best effort; use query summaries for counts.
The additional customer sampling applies only to dns.queries.detail.
Operations logs, platform logs, and query summaries have no customer sampling
filter. Their event selection and transport behavior remain as documented
for each feed.
{
"timestamp": "2026-10-02T09:16:00.123456789Z",
"server": "dns-edge.example.com",
"query_transport": "v4",
"zone": "example.com.",
"customer_id": "123",
"qname": "www.example.com.",
"qtype": "A",
"rcode": "NOERROR",
"src_v4": "192.0.2.10",
"src_v6": null,
"ecs_v4": null,
"ecs_v6": null,
"answer": ["192.0.2.80"],
"answer_v4": ["192.0.2.80"],
"answer_v6": []
}Query summary: dns.queries.summary
| Field | Type | Meaning |
|---|---|---|
timestamp | string | Counting-window start |
server | string | Authoritative server counted |
zone | string | Served zone |
customer_id | string | Customer identifier |
rcode | string | Response code |
window_seconds | integer | Counting-window length, currently 60 |
count | integer | Classified responses for this server, zone, and response code |
Counts include all classified responses observed by the producer, independent of detail sampling. Sum across servers for a customer-wide zone total over the same window. Summary transport remains best effort.
{
"timestamp": "2026-10-02T09:16:00.000000000Z",
"server": "dns-edge.example.com",
"zone": "example.com.",
"customer_id": "123",
"rcode": "NOERROR",
"window_seconds": 60,
"count": 84000
}Live-zone correlation
CNX publishes these synthetic TXT records in the deployed zone:
_cnx-customer-id.example.com. TXT "123"
_cnx-meta.example.com. TXT "sha=<zone-directory-hash>"
_cnx-production-sha.example.com. TXT "<production_sha>"
_cnx-production-sha identifies the accepted Git revision represented by the
live zone. _cnx-meta identifies the source-directory hash used for drift
detection. The serial in zone-change-applied identifies the first committed
zone version containing the corresponding synthetic records.