Skip to content

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.

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

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 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.
  • 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.
  • 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 name is its display name and is not unique, so metadata.name lives in ConfigManagedObject. 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: true publishes on every apply that changes the feed. publish: false revokes 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.when is stored in DetectionRuleFeed.selector and evaluated at every publish; see where each when runs. It needs saas migration 20261226010000_detection_rule_feed_selector. Until it runs, plan refuses a document with a selector and names the migration.
  • A SNORT_YARA feed 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.

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