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.
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 withvulnetix config plan: it shows each object as create, update, delete or no change, with aplanHashthat 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,consoleorgitops:<repo>).--prunedeletes only objects its own manager owns. See The manager and the config engine. - Order. Applied after
SavedSearch,DetectionRuleandMessagingConnection, so a document that refers to one bymetadata.namecan 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: Failedand amessage, and nothing is recorded for it. The others stay applied and the apply answers 207. Plan again to see what is left. A singlePUTfrom the Terraform provider answers 502external_failedinstead. - Status. A failed second-phase write reports phase
Failedwith amessage. 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.