Configuring pipelines
A pipeline says which events go where: a condition, an optional transformer and a sink. Pipelines are configuration, not code.
Pipelines are owned per tenant. Each tenant is one YAML document — a tenants/<tenantId>.yaml file (local/compose, hot-reloaded) or a labelled ConfigMap (Kubernetes) — and events route only through their own tenant’s pipelines. Tenantless events use the reserved _platform tenant (see tenants/_platform.yaml).
# tenants/acme.yaml
tenantId: acme
enabled: true
quota: # optional per-tenant ingest rate limit (429 + Retry-After over budget)
rateLimitPerSec: 200
burst: 400
pipelines:
- name: security-alerts
enabled: true
condition:
match: all # "all" (AND) or "any" (OR)
rules:
- field: eventType
operator: eq
value: "security.alert"
- field: extra.severity
operator: in
value: "HIGH,CRITICAL"
transformer:
name: audit_loki # optional — omit to pass through unchanged
sink:
name: loki_sink
properties:
url: "http://loki:3100"
api-key: "${secretRef:lokiApiKey}" # resolved from THIS tenant's secret store at delivery
fallback: # optional — used when primary sink fails with a retryable error
name: webhook_sink
properties:
url: "https://hooks.example.com/auditflow"
Available condition operators: eq, neq, eqIgnoreCase, contains, startsWith, endsWith, in, notIn, exists, notExists, regex, gt, gte, lt, lte, cidr, notCidr, wildcard, notWildcard. A rule with match + rules instead of field/operator is a nested group.
Field paths support dot notation (extra.userId) and array indices (items[0].name).
PII Redaction
auditflow:
redaction:
enabled: true
rules:
- field: extra.userId
action: mask # replace with ***
- field: extra.email
action: hash # replace with a keyed hash (needs the key below)
- field: extra.sessionId
action: drop # remove the field entirely
Redaction runs at ingest, before the event is published to the broker — sensitive values never reach it or any downstream sink.
The key of a rule is action (mask, hash or drop); a rule without it masks.
hash needs a secret key. The hash is an HMAC-SHA256 of the value, written as 64 hex characters. A plain, unkeyed hash of an e-mail address, an IP address or a user id can be reversed by hashing candidates; with a key that only AuditFlow holds it cannot.
openssl rand -base64 32 # generate a key (at least 32 characters)
Supply it as the environment variable AUDITFLOW_REDACTION_HASH_KEY, from a secret and never in a values file: with the Helm chart as secrets.data.AUDITFLOW_REDACTION_HASH_KEY, or as a key of the module’s external secret.
- If an enabled rule uses
hashand the key is missing or shorter than 32 characters, the backend does not start. It never falls back to an unkeyed hash. - Every replica must have the same key, or the same value gets different hashes.
- Changing the key changes every hash from then on: values hashed before and after cannot be matched. Keep the key for as long as the hashes must stay comparable.
- Whoever holds the key can test a guess against a hash. Treat it like a credential; it gives pseudonymisation, not anonymisation.
- The key is one per deployment and the same for every tenant, like the redaction rules themselves.