Skip to content

AlertTrigger

A Guardian trigger: run a SavedSearch or a DetectionRule on a schedule and, when its rows pass the levers, start a Software Factory workflow. Fields, YAML, HCL and CLI samples, and how apply treats it.

Checked against config-schemas@v1.15.0, terraform-provider-resolve@82cb23c, cli@v4.9.1

A Guardian trigger: run a SavedSearch or a DetectionRule on a schedule and, when its rows pass the levers, start a Software Factory workflow, post to messaging connections or send an email, with the rows as context. No rows, nothing starts. Name exactly one of searchRef or ruleRef. The plan caps how many triggers are enabled at once.

apiVersion vulnetix.com/v1
kind AlertTrigger
Group SIEM
Status Served. The config engine plans and applies it.
Objects per tenant many, keyed by metadata.name
Token and role A vmt_ config management token that lists AlertTrigger in its kinds. The owner or admin role writes; the member role reads only. A console session or an ApiKey is refused with kind_not_allowed, because the kind is written in Guardian with the caller’s own token.
Applied after SavedSearch, DetectionRule, MessagingConnection (deleted before them)
Terraform resource vulnetix_alert_trigger, imported by name (see Terraform and OpenTofu)
CLI vulnetix config apply, CLI v3.165.1 and later.
Pinned schema v1.15.0/AlertTrigger.schema.json
Newest schema latest/AlertTrigger.schema.json
First released in v1.3.0
Print the built-in copy vulnetix config schema AlertTrigger

Minimal

Only the fields the kind requires. From examples/AlertTrigger/minimal.yaml.

YAML

# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/AlertTrigger.schema.json
apiVersion: vulnetix.com/v1
kind: AlertTrigger
metadata:
  name: dns-investigate
spec:
  searchRef: dynamic-dns-lookups
  destination:
    kind: workflow

HCL (resource vulnetix_alert_trigger)

# Only the arguments the kind requires. From config-schemas examples/AlertTrigger/minimal.yaml.

resource "vulnetix_alert_trigger" "dns_investigate" {
  name = "dns-investigate"
  destination = {
    kind = "workflow"
  }
  search_ref = "dynamic-dns-lookups"
}

CLI (applies it)

export VULNETIX_CONFIG_TOKEN=vmt_...   # a config management token
vulnetix config apply -f - --manager gitops:acme/platform --auto-approve <<'EOF'
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/AlertTrigger.schema.json
apiVersion: vulnetix.com/v1
kind: AlertTrigger
metadata:
  name: dns-investigate
spec:
  searchRef: dynamic-dns-lookups
  destination:
    kind: workflow
EOF

Advanced

Every field the kind supports, with a when expression where it takes one. From examples/AlertTrigger/advanced.yaml.

YAML

# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/AlertTrigger.schema.json
apiVersion: vulnetix.com/v1
kind: AlertTrigger
metadata:
  name: dns-investigate
  labels:
    team: secops
  annotations:
    runbook: https://wiki.example.com/secops/dynamic-dns
spec:
  displayName: Dynamic DNS lookups from one host
  searchRef: dynamic-dns-lookups
  everySec: 300
  enabled: true
  levers:
    minRows: 3
    windowSec: 900
    countBy: src_ip
    cooldownSec: 3600
    maxPerHour: 4
    hours: business
    zone: Australia/Melbourne
    rowsCap: 25
    columns: [ts, src_ip, qname]
    ask: always
  destination:
    kind: workflow
    severity: warning
---
apiVersion: vulnetix.com/v1
kind: AlertTrigger
metadata:
  name: root-login-page
spec:
  displayName: AWS root console login
  ruleRef: sigmahq-aws-root-login
  everySec: 60
  levers:
    windowSec: 300
    cooldownSec: 900
    hours: always
  destination:
    kind: messaging
    connections: [secops-slack]
    severity: critical
---
apiVersion: vulnetix.com/v1
kind: AlertTrigger
metadata:
  name: failed-logins-digest
spec:
  displayName: Failed SSO logins outside business hours
  searchRef: failed-sso-logins
  everySec: 3600
  enabled: false
  levers:
    minRows: 20
    windowSec: 3600
    countBy: user_name
    hours: outside_business
    zone: Europe/London
    rowsCap: 50
  destination:
    kind: email
    emails: [secops@example.com, oncall@example.com]
    severity: notice

HCL (resource vulnetix_alert_trigger)

# Every argument the kind supports. From config-schemas examples/AlertTrigger/advanced.yaml.

resource "vulnetix_alert_trigger" "dns_investigate" {
  name = "dns-investigate"
  destination = {
    kind     = "workflow"
    severity = "warning"
  }
  display_name = "Dynamic DNS lookups from one host"
  enabled      = true
  every_sec    = 300
  levers = {
    ask          = "always"
    columns      = ["ts", "src_ip", "qname"]
    cooldown_sec = 3600
    count_by     = "src_ip"
    hours        = "business"
    max_per_hour = 4
    min_rows     = 3
    rows_cap     = 25
    window_sec   = 900
    zone         = "Australia/Melbourne"
  }
  search_ref = "dynamic-dns-lookups"
  labels = {
    team = "secops"
  }
  annotations = {
    runbook = "https://wiki.example.com/secops/dynamic-dns"
  }
}

resource "vulnetix_alert_trigger" "root_login_page" {
  name = "root-login-page"
  destination = {
    connections = ["secops-slack"]
    kind        = "messaging"
    severity    = "critical"
  }
  display_name = "AWS root console login"
  every_sec    = 60
  levers = {
    cooldown_sec = 900
    hours        = "always"
    window_sec   = 300
  }
  rule_ref = "sigmahq-aws-root-login"
}

resource "vulnetix_alert_trigger" "failed_logins_digest" {
  name = "failed-logins-digest"
  destination = {
    emails   = ["secops@example.com", "oncall@example.com"]
    kind     = "email"
    severity = "notice"
  }
  display_name = "Failed SSO logins outside business hours"
  enabled      = false
  every_sec    = 3600
  levers = {
    count_by   = "user_name"
    hours      = "outside_business"
    min_rows   = 20
    rows_cap   = 50
    window_sec = 3600
    zone       = "Europe/London"
  }
  search_ref = "failed-sso-logins"
}

CLI (applies it)

export VULNETIX_CONFIG_TOKEN=vmt_...   # a config management token
vulnetix config apply -f - --manager gitops:acme/platform --auto-approve <<'EOF'
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/AlertTrigger.schema.json
apiVersion: vulnetix.com/v1
kind: AlertTrigger
metadata:
  name: dns-investigate
  labels:
    team: secops
  annotations:
    runbook: https://wiki.example.com/secops/dynamic-dns
spec:
  displayName: Dynamic DNS lookups from one host
  searchRef: dynamic-dns-lookups
  everySec: 300
  enabled: true
  levers:
    minRows: 3
    windowSec: 900
    countBy: src_ip
    cooldownSec: 3600
    maxPerHour: 4
    hours: business
    zone: Australia/Melbourne
    rowsCap: 25
    columns: [ts, src_ip, qname]
    ask: always
  destination:
    kind: workflow
    severity: warning
---
apiVersion: vulnetix.com/v1
kind: AlertTrigger
metadata:
  name: root-login-page
spec:
  displayName: AWS root console login
  ruleRef: sigmahq-aws-root-login
  everySec: 60
  levers:
    windowSec: 300
    cooldownSec: 900
    hours: always
  destination:
    kind: messaging
    connections: [secops-slack]
    severity: critical
---
apiVersion: vulnetix.com/v1
kind: AlertTrigger
metadata:
  name: failed-logins-digest
spec:
  displayName: Failed SSO logins outside business hours
  searchRef: failed-sso-logins
  everySec: 3600
  enabled: false
  levers:
    minRows: 20
    windowSec: 3600
    countBy: user_name
    hours: outside_business
    zone: Europe/London
    rowsCap: 50
  destination:
    kind: email
    emails: [secops@example.com, oncall@example.com]
    severity: notice
EOF

Fields

Paths use dots for nesting and [] for the items of a list. Required means required whenever the parent object is present. A default is what the server uses when the field is left out.

Field Type Required Default Allowed values Description
apiVersion string yes exactly vulnetix.com/v1 The document format version. Every kind in this release is vulnetix.com/v1.
kind string yes exactly AlertTrigger Always AlertTrigger.
metadata object yes no other keys
metadata.name string yes pattern ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$ The object’s name, unique per kind within a tenant. It is the natural key: plan, apply, export and the Terraform provider all address an object by kind and name.
metadata.org string no format uuid The tenant (organization UUID) the document belongs to. When set, plan and apply refuse to run against any other tenant.
metadata.labels object no map of string to string (length 0 to 256); keys match ^[a-z0-9]([a-z0-9._/-]{0,61}[a-z0-9])?$ Free key/value labels. Stored with the object, never interpreted by the server.
metadata.annotations object no map of string to string (length 0 to 4096) Free key/value notes for people and tools, such as a ticket link.
spec object yes no other keys
spec.displayName string no length 1 to 160 The name the console shows. Defaults to metadata.name.
spec.searchRef string no pattern ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$ The metadata.name of the SavedSearch to run.
spec.ruleRef string no pattern ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$ The metadata.name of the DetectionRule to run.
spec.everySec integer no 300 60 to 86400 Seconds between runs.
spec.enabled boolean no true
spec.levers object no no other keys When a run fires, and what it sends.
spec.levers.minRows integer no 1 1 to 100000 Fire when a group has at least this many rows in the window.
spec.levers.windowSec integer no 300 60 to 604800 How far back each run looks, in seconds.
spec.levers.countBy string no pattern ^[a-z_][a-z0-9_]{0,62}$ Count rows per this column. Left out, the whole result is one group.
spec.levers.cooldownSec integer no 3600 0 to 604800 Do not fire the same group again for this long, in seconds.
spec.levers.maxPerHour integer no 4 1 to 60 At most this many fires per hour for the trigger.
spec.levers.hours string no always always, business, outside_business When it may fire. business is 09:00 to 17:00, Monday to Friday, in zone.
spec.levers.zone string no UTC length 1 to 63 The IANA time zone for hours.
spec.levers.rowsCap integer no 25 1 to 100 Rows sent as context, at most.
spec.levers.columns array of string no 0 to 30 items; items unique; each item: pattern ^[a-z_][a-z0-9_]{0,62}$ Columns sent. Left out, every column of the result.
spec.levers.ask string no workflow workflow, always For workflow runs: workflow follows the workflow’s asks; always asks a person before any change.
spec.destination object yes no other keys What a fire starts. workflow: a siem.fired source event for the Software Factory, which every published workflow whose trigger matches it takes. messaging: a post to each connection. email: a message to each address.
spec.destination.kind string yes workflow, messaging, email
spec.destination.connections array of string no 1 to 10 items; items unique; each item: pattern ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$
spec.destination.emails array of string no 1 to 20 items; items unique; each item: format email; length 0 to 254
spec.destination.severity string no warning info, notice, warning, critical

Rules

Conditions the schema enforces beyond each field’s own type. vulnetix config validate and the engine’s plan report a document that breaks one.

On Rule
spec Exactly one of searchRef or ruleRef is set.
spec.destination When kind is messaging: connections is required and emails is not allowed.
spec.destination When kind is email: emails is required and connections is not allowed.
spec.destination When kind is workflow: connections is not allowed and emails is not allowed.

Applying this kind

  • Command. vulnetix config apply -f <file>; the CLI line above says from which release. Plan first with vulnetix config plan: it shows each object as create, update, delete or no change, with a planHash that apply then holds to. Apply writes in one transaction, except for the second phase below.
  • Manager. Each object records the manager that applied it (terraform, console or gitops:<repo>). --prune deletes only objects its own manager owns. See The manager and the config engine.
  • Order. Applied after SavedSearch, DetectionRule and MessagingConnection, so a document that refers to one by metadata.name can be in the same apply. Deleted before them.
  • Second phase. This kind is not written inside the apply transaction. The other kinds apply and commit first, then each AlertTrigger is written on its own, in Guardian. One that fails reports status.phase: Failed and a message, and nothing is recorded for it. The others stay applied and the apply answers 207. Plan again to see what is left. A single PUT from the Terraform provider answers 502 external_failed instead.
  • Status. A failed second-phase write reports phase Failed with a message. The phases the engine reports are explained under status phases.

How apply treats it

Written in Guardian, in the second phase; see SIEM kinds. Everything can change in place, including the source.

Terraform and OpenTofu

The resource is vulnetix_alert_trigger in the vulnetix/resolve provider. Its arguments are the spec in snake case, beside name, labels and annotations from metadata. The Minimal and Advanced HCL are above. The provider’s own reference is vulnetix_alert_trigger.

Import an object that already exists by its name:

# Import an existing AlertTrigger by its name (metadata.name).
terraform import vulnetix_alert_trigger.dns_investigate dns-investigate

Install, authentication and how state is read: Terraform and OpenTofu.

More examples

examples/AlertTrigger/triggers.yaml from Vulnetix/config-schemas:

# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/AlertTrigger.schema.json
apiVersion: vulnetix.com/v1
kind: AlertTrigger
metadata:
  name: dns-investigate
spec:
  searchRef: dynamic-dns-lookups
  everySec: 300
  levers:
    minRows: 3
    windowSec: 900
    countBy: src_ip
    cooldownSec: 3600
    maxPerHour: 4
    hours: business
    zone: Australia/Melbourne
    rowsCap: 25
    columns: [ts, src_ip, qname]
    ask: always
  destination: { kind: workflow }
---
apiVersion: vulnetix.com/v1
kind: AlertTrigger
metadata:
  name: root-login-page
spec:
  ruleRef: sigmahq-aws-root-login
  destination:
    kind: messaging
    connections: [secops-slack]
    severity: critical

Check a file with vulnetix config validate -f <file>. See Validate documents. In an editor, start the file with the schema comment.

Edit this pageSources: config-schemas/schemas/AlertTrigger.schema.json, config-schemas/schemas/common.schema.json, config-schemas/examples/AlertTrigger/minimal.yaml, config-schemas/examples/AlertTrigger/advanced.yaml, config-schemas/examples/AlertTrigger/triggers.yaml, terraform-provider-resolve/examples/resources/vulnetix_alert_trigger/minimal.tf, terraform-provider-resolve/examples/resources/vulnetix_alert_trigger/advanced.tf, vdb-site/docs/platform-iac-engine.md, vdb-site/api/internal/handler/config_engine_kinds.go, vdb-site/api/internal/config/siem_trigger.go, vdb-site/api/internal/config/guardian.go
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.