Skip to main content

Source - the top-level data abstraction

Status: Shipped (SourceRegistry + the Source model are the live path).

A Source is one distinct stream of events entering the platform -- filebeat, syslog, crowdstrike-edr, windows-audit. It is the only entity the API, the CLI and the console CRUD, and everything a stream needs hangs off it: where records come in, whether they are transformed, the table they land in, the detections that run against it.

Without it, onboarding a stream means editing four systems that share no concept of "this is one source" -- receiver match rules, a transform's own input and output topics, loader table routing, and a table definition with no link back to any of them -- and hoping the naming stays consistent. It never did.

Two tiers, not two systems​

Global services are infrastructure, configured once and shared by every source. Their config says how: brokers, connection strings, TLS, buffer sizes, scaling.

ServiceRole
receiverHTTP/gRPC ingestion, match routing, _source injection
loaderlanding records to ClickHouse, schema-aware insert
archiverlanding records to S3 or a file archive

Sources say what. Each one contains its own scoped components rather than being listed inside a service's config:

ComponentRequiredPurpose
identityYes_source label, display name
originYesExactly one of a receiver match rule, a fetcher, or external for your own pipeline. See external-pipelines.md
schemaYesClickHouse table definition (starts as the common header alone). See schema.md
transformNoEnrichment or normalisation stage: a DFE transform app, or engine: external for your own
flowNotransport (bus or direct) and archive; unset takes the deployment default. See source-flow.md
rulesNoSQL detections against this source's table
viewsNoNaming-standard views (sigma, ecs, cim, ocsf) with per-source overrides

A source-scoped component is logical config, not a deployment the operator manages. One transform-vector deployment may run the transforms of twenty sources; the source says this source needs a vector transform with this config, and the deployment layer decides which instance runs it.

Source componentRuns onHow
source.matchthe receiver poolcompiled into a receiver rules row
source.fetcherone fetcher instance per sourcethe stanza, and the org fetcher.org names, are compiled into its overlay
source.transformone transform instance per sourcethe stanza is compiled into its overlay
source.schemadfe-engineDDL generated and applied by the engine
source.rulesthe hunt runnerSQL on a schedule, matches to alerts
source.viewsdfe-enginenaming-standard compatibility views

The _source label​

_source is the single identifier that ties the four systems together. The receiver stamps it into the JSON payload at ingest, and from there every other name is derived rather than configured:

_source = "filebeat"

Kafka topics:
filebeat_land raw records from the receiver
filebeat_load transformed records (only when a transform exists)

ClickHouse:
Table: {db}.filebeat
_source column value: "filebeat"

Because it is stamped before the record reaches the bus, the downstream stages read it directly and carry no routing config of their own.

Naming rules​

  • A Kubernetes DNS-1123 label starting with a letter: [a-z]([a-z0-9-]*[a-z0-9])?
  • Hyphens, never underscores. A source-bound app deploys one instance named for the source, and that name becomes an Argo Application and a set of Kubernetes object names, so the charset has to be a subset of what a label allows.
  • Max 40 characters, the cap the instance name carries. dfe-infra's layer2-apps ApplicationSet bounds the Helm release name of an Application past 53 characters, so a 40-character name deploys on Kubernetes too.
  • Unique across all sources

A hyphenated name has to be quoted in a ClickHouse identifier position, so the DDL generator backtick-quotes every identifier (quote_ident in schema/schema_ddl.py).

DocCovers
source-definition.mdthe source YAML, field by field, and what a write is validated against
source-registry.mdstates, storage backends, CRUD, topics on deploy, the API surface
source-flow.mdthe two transports, what the engine compiles, how a change reaches a pod
source-routing.mdthe exact receiver and loader config a source compiles into
external-pipelines.mdyour own Vector, Fluentd or Logstash as the origin or the transform
source-detections.mdrules, hunts, and Sigma views