DetectionRuleFeed
A curated feed of virtual patches, countermeasures and catalogue rules, published to a public URL for IDS, IPS, WAF. Fields, YAML, HCL and CLI samples, and how apply treats it.
A curated feed of virtual patches, countermeasures and catalogue rules, published to a public URL for IDS, IPS, WAF, SIEM and YARA engines and the Vulnetix runtime sensor to fetch. A feed has one output format, because its consumers each read one. The plan sets how many feeds of each format a tenant may have, and a feed holds at most 500 rules. Name entries, a selector, or both. The format cannot be changed on the server, so a changed format is applied as delete and create, which moves the feed’s URL.
apiVersion |
vulnetix.com/v1 |
kind |
DetectionRuleFeed |
| Group | Virtual patching |
| Status | Served. The config engine plans and applies it. |
| Objects per tenant | many, keyed by metadata.name |
| Token and role | An owner or admin session, or a vmt_ config management token with the owner or admin role that lists DetectionRuleFeed in its kinds. See Management tokens. |
| CEL fields | spec.selector.when (cve): see CEL rule expressions |
| Terraform resource | vulnetix_detection_rule_feed, imported by name (see Terraform and OpenTofu) |
| CLI | vulnetix config apply, CLI v3.165.1 and later. |
| Pinned schema | v1.15.0/DetectionRuleFeed.schema.json |
| Newest schema | latest/DetectionRuleFeed.schema.json |
| First released in | v1.3.0 |
| Print the built-in copy | vulnetix config schema DetectionRuleFeed |
Minimal
Only the fields the kind requires. From examples/DetectionRuleFeed/minimal.yaml.
YAML
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/DetectionRuleFeed.schema.json
apiVersion: vulnetix.com/v1
kind: DetectionRuleFeed
metadata:
name: edge-waf
spec:
format: AWS_WAF
entries:
- ruleTable: virtual_patch
ruleType: AWS_WAF
rule: 9c2d4e6f-1a3b-4c5d-8e7f-0a1b2c3d4e5f
HCL (resource vulnetix_detection_rule_feed)
# Only the arguments the kind requires. From config-schemas examples/DetectionRuleFeed/minimal.yaml.
resource "vulnetix_detection_rule_feed" "edge_waf" {
name = "edge-waf"
entries = [
{
rule = "9c2d4e6f-1a3b-4c5d-8e7f-0a1b2c3d4e5f"
rule_table = "virtual_patch"
rule_type = "AWS_WAF"
},
]
format = "AWS_WAF"
}
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/DetectionRuleFeed.schema.json
apiVersion: vulnetix.com/v1
kind: DetectionRuleFeed
metadata:
name: edge-waf
spec:
format: AWS_WAF
entries:
- ruleTable: virtual_patch
ruleType: AWS_WAF
rule: 9c2d4e6f-1a3b-4c5d-8e7f-0a1b2c3d4e5f
EOF
Advanced
Every field the kind supports, with a when expression where it takes one. From examples/DetectionRuleFeed/advanced.yaml.
YAML
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/DetectionRuleFeed.schema.json
apiVersion: vulnetix.com/v1
kind: DetectionRuleFeed
metadata:
name: edge-suricata
labels:
team: netsec
engine: suricata
annotations:
consumer: Suricata sensors at the edge pull this feed every 15 minutes.
spec:
displayName: Edge Suricata virtual patches
description: Block-lane Suricata rules for exploited edge appliance CVEs, fetched by the perimeter IPS.
format: SURICATA
schemaVersion: 1
entries:
- ruleTable: virtual_patch
ruleType: SURICATA
rule: 4d5e6f7a-8b9c-4d0e-9f1a-2b3c4d5e6f7a
cve: CVE-2024-3400
- ruleTable: virtual_patch
ruleType: SURICATA
rule: 5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b
cve: CVE-2023-46805
disabled: true
selector:
when: kind == 'SURICATA' && (kev || epss >= 0.5) && cvss >= 7.0 && falsePositiveRisk != 'HIGH' && now - published < duration('8760h')
publish: true
HCL (resource vulnetix_detection_rule_feed)
# Every argument the kind supports. From config-schemas examples/DetectionRuleFeed/advanced.yaml.
resource "vulnetix_detection_rule_feed" "edge_suricata" {
name = "edge-suricata"
description = "Block-lane Suricata rules for exploited edge appliance CVEs, fetched by the perimeter IPS."
display_name = "Edge Suricata virtual patches"
entries = [
{
cve = "CVE-2024-3400"
rule = "4d5e6f7a-8b9c-4d0e-9f1a-2b3c4d5e6f7a"
rule_table = "virtual_patch"
rule_type = "SURICATA"
},
{
cve = "CVE-2023-46805"
disabled = true
rule = "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b"
rule_table = "virtual_patch"
rule_type = "SURICATA"
},
]
format = "SURICATA"
publish = true
schema_version = 1
selector = {
when = "kind == 'SURICATA' && (kev || epss >= 0.5) && cvss >= 7.0 && falsePositiveRisk != 'HIGH' && now - published < duration('8760h')"
}
labels = {
engine = "suricata"
team = "netsec"
}
annotations = {
consumer = "Suricata sensors at the edge pull this feed every 15 minutes."
}
}
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/DetectionRuleFeed.schema.json
apiVersion: vulnetix.com/v1
kind: DetectionRuleFeed
metadata:
name: edge-suricata
labels:
team: netsec
engine: suricata
annotations:
consumer: Suricata sensors at the edge pull this feed every 15 minutes.
spec:
displayName: Edge Suricata virtual patches
description: Block-lane Suricata rules for exploited edge appliance CVEs, fetched by the perimeter IPS.
format: SURICATA
schemaVersion: 1
entries:
- ruleTable: virtual_patch
ruleType: SURICATA
rule: 4d5e6f7a-8b9c-4d0e-9f1a-2b3c4d5e6f7a
cve: CVE-2024-3400
- ruleTable: virtual_patch
ruleType: SURICATA
rule: 5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b
cve: CVE-2023-46805
disabled: true
selector:
when: kind == 'SURICATA' && (kev || epss >= 0.5) && cvss >= 7.0 && falsePositiveRisk != 'HIGH' && now - published < duration('8760h')
publish: true
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 DetectionRuleFeed |
Always DetectionRuleFeed. | |
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 200 | The feed’s name. Defaults to metadata.name. | |
spec.description |
string | no | length 0 to 4096 | ||
spec.format |
string | yes | SNORT_YARA, SNORT, SURICATA, MODSECURITY, NGINX, AWS_WAF, CLOUDFLARE_WAF, REGEX_L7, SIGMA, YARA, STIX, OPENIOC |
The output format, and so which rules the feed accepts. SNORT_YARA publishes snort.rules and rules.yar from the third-party catalogue together. SNORT, SURICATA, MODSECURITY, NGINX, AWS_WAF, CLOUDFLARE_WAF and REGEX_L7 are block-lane virtual patches; SIGMA, YARA, STIX and OPENIOC are detect-lane countermeasures. Every published feed also carries rules.json and a signed manifest for the runtime sensor. | |
spec.schemaVersion |
number | no | 1 |
exactly 1 |
The layout of the published files. |
spec.entries |
array of object | no | 0 to 500 items | Rules named one by one. Each is checked to exist when it is added and again at publish. | |
spec.entries[].ruleTable |
string | yes | snort_rule, yara_rule, virtual_patch, countermeasure |
||
spec.entries[].ruleType |
string | yes | |||
spec.entries[].rule |
string | yes | format uuid |
The rule’s uuid in its table. | |
spec.entries[].cve |
string | no | pattern ^CVE-[0-9]{4}-[0-9]{4,}$ |
The vulnerability the rule was curated for. | |
spec.entries[].disabled |
boolean | no | false |
Publish the rule commented out. Left false, publish turns it on even when its catalogue marks it disabled. | |
spec.selector |
object | no | no other keys | Rules chosen by a condition, as well as any entries. Each time the feed is built for publishing, the condition is evaluated against the generated rules of the feed’s format (virtual patches for a block-lane format, countermeasures for a detect-lane one), once for each vulnerability a rule was written for, and a rule is included when it holds for any of them. The third-party catalogue (SNORT_YARA) carries no vulnerability data, so it takes entries only. A published feed holds at most 500 rules, explicit entries first. | |
spec.selector.when |
string | yes | length 1 to 4096 | A condition over the cve variables (id, cvss, epss, kev, published, kind, confidence, falsePositiveRisk, now), evaluated once per candidate rule. | |
spec.publish |
boolean | no | false |
true: publish on apply, and again whenever the entries change, to the feed’s public URL. false: keep the feed a draft; a published feed is revoked, which deletes its published files. |
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 |
At least one of entries or selector is set. |
spec.entries[] |
Exactly one of these holds: (1) ruleTable must be snort_rule and ruleType must be SNORT; (2) ruleTable must be yara_rule and ruleType must be YARA; (3) ruleTable must be virtual_patch and ruleType must be SNORT, SURICATA, MODSECURITY, NGINX, AWS_WAF, CLOUDFLARE_WAF, REGEX_L7; (4) ruleTable must be countermeasure and ruleType must be SIGMA, YARA, STIX, OPENIOC. |
CEL variables
spec.selector.when is a CEL expression in the cve context, returning bool. It is evaluated by the Vulnetix site API at every publish of the feed, once for each candidate rule and CVE. The pair does not match. When every pair fails, the publish is refused. See where each expression is evaluated. The functions, limits and error codes are on CEL rule expressions.
| Variable | Type | Bound | Description |
|---|---|---|---|
id |
string |
256 chars | CVE identifier. |
cvss |
double |
CVSS base score, 0 to 10. 0 when unscored. | |
epss |
double |
EPSS probability, 0 to 1. | |
kev |
bool |
Listed in a known-exploited catalogue. | |
published |
timestamp |
When the CVE was published. The zero timestamp when unknown. | |
kind |
string |
64 chars | Rule format: SNORT, SURICATA, MODSECURITY, NGINX, AWS_WAF, CLOUDFLARE_WAF, REGEX_L7, SIGMA, YARA, STIX, OPENIOC. |
confidence |
string |
64 chars | Confidence in the rule: HIGH, MEDIUM, LOW, or empty. |
falsePositiveRisk |
string |
64 chars | HIGH, MEDIUM, LOW, or empty. |
now |
timestamp |
The time of evaluation. Callers may fix it; otherwise it is the clock when Eval runs. |
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. - 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. - Status. Applied, Unchanged or Deleted, with no other status fields. The phases the engine reports are explained under status phases.
How apply treats it
- The feed’s own
nameis its display name and is not unique, sometadata.namelives inConfigManagedObject. A feed nobody declared exports under a name derived from its own. - The spec is replaced whole. Entries are a set keyed by rule table, rule type and rule, each checked to exist and to fit the format, as the console’s add does.
publish: truepublishes on every apply that changes the feed.publish: falserevokes a published feed. Publishing writes S3 from inside the apply transaction, after the feed’s rows: a later failure in the same apply rolls the rows back but not the files, and the next publish or revoke of that feed replaces them.- The plan gate and the per-type feed cap are the console’s.
selector.whenis stored inDetectionRuleFeed.selectorand evaluated at every publish; see where eachwhenruns. It needs saas migration20261226010000_detection_rule_feed_selector. Until it runs, plan refuses a document with a selector and names the migration.- A
SNORT_YARAfeed takes entries only: the third-party catalogue has no CVE data, so plan refuses a selector on one.
Terraform and OpenTofu
The resource is vulnetix_detection_rule_feed 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_detection_rule_feed.
Import an object that already exists by its name:
# Import an existing DetectionRuleFeed by its name (metadata.name).
terraform import vulnetix_detection_rule_feed.edge_waf edge-waf
Install, authentication and how state is read: Terraform and OpenTofu.
More examples
examples/DetectionRuleFeed/feeds.yaml from Vulnetix/config-schemas:
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/DetectionRuleFeed.schema.json
apiVersion: vulnetix.com/v1
kind: DetectionRuleFeed
metadata:
name: edge-waf
spec:
displayName: Edge WAF virtual patches
format: AWS_WAF
entries:
- ruleTable: virtual_patch
ruleType: AWS_WAF
rule: 9c2d4e6f-1a3b-4c5d-8e7f-0a1b2c3d4e5f
cve: CVE-2024-3400
publish: true
---
apiVersion: vulnetix.com/v1
kind: DetectionRuleFeed
metadata:
name: kev-sigma
spec:
format: SIGMA
selector:
when: kev && confidence == 'HIGH' && kind == 'SIGMA'
publish: true
---
apiVersion: vulnetix.com/v1
kind: DetectionRuleFeed
metadata:
name: ids-catalogue
spec:
format: SNORT_YARA
entries:
- { ruleTable: snort_rule, ruleType: SNORT, rule: 1f2e3d4c-5b6a-4978-8a9b-0c1d2e3f4a5b }
- { ruleTable: yara_rule, ruleType: YARA, rule: 2a3b4c5d-6e7f-4a8b-9c0d-1e2f3a4b5c6d, disabled: true }
Check a file with vulnetix config validate -f <file>. See Validate documents. In an editor, start the file with the schema comment.