Skip to content

[stormshield] Add ECS event categorization and network mappings - #20031

Merged
taylor-swanson merged 1 commit into
elastic:mainfrom
arenard:stormshield-ecs-categorization
Jul 17, 2026
Merged

taylor-swanson merged 1 commit into
elastic:mainfrom
arenard:stormshield-ecs-categorization

Conversation

@arenard

@arenard arenard commented Jul 8, 2026 •

Copy link
Copy Markdown
Contributor

Proposed commit message

Set event.kind, event.category and event.type for every SNS log family through a table-driven Painless script keyed on logtype, with allowed/denied event.type modifiers derived case-insensitively from the rule action (pass/block; an empty action corresponds to a rule set to Log and adds no modifier). The periodic statistics families (monitor, filterstat, count, routerstat, authstat, ipsecstat) are tagged event.kind: metric so health telemetry can be excluded from detection scopes with a single filter. Unknown families fall back to event.kind: event without asserting a category or type, covered by a dedicated test sample. The script only runs on documents without an error, so the pipeline_error kind set by sub-pipeline failure handlers is preserved.

Add the ECS network mappings tracked in #10114: rcvd to destination.bytes (mirroring the existing sent mapping), network.bytes as the sum of both, srcif/srcifname/dstif/dstifname copied to observer.ingress/observer.egress interface fields, and network.direction computed with private ranges as internal networks. Promote alarm fields (alarmid to event.code, risk to event.risk_score, pri to event.severity on the alarm scale where 1 is major and 4 is minor), HTTP proxy fields (arg to url.original, url.domain from destination.domain), and populate related.hosts. Guard the ASN geoip processors with null checks, matching the geo processors.

Fix the count sub-pipeline, which failed on every count log since the package was created: the script called splitByToken, which does not exist in Painless (runtime error: dynamic method [java.lang.String, splitByToken/2] not found), and collapsed all rules into a single map. Rule counters now form a sorted array under stormshield.metadata.rule_stats, and a counter that does not parse (non-numeric value, out-of-range category or unexpected key shape) is skipped instead of sending the whole document to pipeline_error.

Add pipeline test samples for the alarm, auth, web, vpn, xvpn, count and filter families plus an unknown-family sample, an Alarms (IPS) dashboard keyed on the new categorization fields, and the categorization table in the README.

Design notes

  • All new mappings are copies: no stormshield.* field is renamed, moved or removed, and event.action keeps the verbatim vendor value, so existing dashboards and saved queries are unaffected. This keeps the change a minor version bump.
  • The single log data stream is kept, following the fortinet_fortigate / cisco_asa / sonicwall_firewall precedent for multi-family syslog firewall packages; the categorization script follows the sonicwall_firewall table-driven pattern.
  • event.outcome derivation and deeper per-family enrichment (vpn IKE fields, sandboxing verdicts, the v5 restapi family) are planned as follow-ups.
  • Test samples follow the log format examples from the official Stormshield audit log documentation, with addresses in RFC 1918/5737 ranges; they exercise uppercase (Block), lowercase (pass) and empty action values, and the unknown-family fallback.

Checklist

  • I have reviewed tips for building integrations and this pull request is aligned with them.
  • I have verified that all data streams collect metrics or logs.
  • I have added an entry to my package's changelog.yml file.
  • I have verified that Kibana version constraints are current according to guidelines.
  • I have verified that any added dashboard complies with Kibana's Dashboard good practices

Author's Checklist

  • elastic-package check, test pipeline, test static and test system (udp, tcp, tls) all pass against stack 9.4.3
  • The dashboard imports cleanly into Kibana 9.4.3, every panel is scoped by the dashboard-level data_stream.dataset and stormshield.logtype filters, and every aggregated field is aggregatable and declared in the package field files
  • sample_event.json regenerated through elastic-package test system --generate
  • Fields referenced by the existing Overview dashboard (event.action, log.syslog.severity.name, stormshield.fw, stormshield.logtype, stormshield.in_bytes, stormshield.out_bytes) are untouched

How to test this PR locally

cd packages/stormshield
elastic-package check
elastic-package test pipeline
elastic-package stack up -d
elastic-package test system

Related issues

@cla-checker-service

cla-checker-service Bot commented Jul 8, 2026 •

Copy link
Copy Markdown

💚 CLA has been signed

@github-actions

github-actions Bot commented Jul 8, 2026 •

Copy link
Copy Markdown
Contributor

✅ Elastic Docs Style Checker (Vale)

No issues found on modified lines!


The Vale linter checks documentation changes against the Elastic Docs style guide. To use Vale locally or report issues, refer to Elastic style guide for Vale.

@elastic-vault-github-plugin-prod

Copy link
Copy Markdown
Contributor

🚀 Benchmarks report

To see the full report comment with /test benchmark fullreport

@andrewkroh andrewkroh added documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. Integration:stormshield StormShield SNS needs CLA User must sign the Elastic Contributor License before review. dashboard Relates to a Kibana dashboard bug, enhancement, or modification. labels Jul 8, 2026
@arenard
arenard force-pushed the stormshield-ecs-categorization branch 2 times, most recently from a0275dc to 59232a6 Compare July 8, 2026 15:48
@andrewkroh andrewkroh removed the needs CLA User must sign the Elastic Contributor License before review. label Jul 8, 2026
@arenard
arenard force-pushed the stormshield-ecs-categorization branch 5 times, most recently from 11084e6 to d5a60c4 Compare July 9, 2026 15:33
@arenard arenard changed the title stormshield: add ECS event categorization and network mappings [stormshield] Add ECS event categorization and network mappings Jul 9, 2026
@arenard
arenard force-pushed the stormshield-ecs-categorization branch from d5a60c4 to 069f288 Compare July 10, 2026 11:24
@arenard
arenard marked this pull request as ready for review July 10, 2026 11:24
@arenard
arenard requested a review from a team as a code owner July 10, 2026 11:24
@arenard
arenard force-pushed the stormshield-ecs-categorization branch from 069f288 to a1623ea Compare July 10, 2026 11:29
@arenard
arenard marked this pull request as draft July 10, 2026 11:37
@arenard
arenard marked this pull request as ready for review July 10, 2026 12:10
@andrewkroh andrewkroh added the Team:Integration-Experience Security Integrations Integration Experience [elastic/integration-experience] label Jul 10, 2026
@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

Pinging @elastic/integration-experience (Team:Integration-Experience)

Comment thread packages/stormshield/changelog.yml Resolved
Comment thread packages/stormshield/changelog.yml Resolved
@arenard
arenard force-pushed the stormshield-ecs-categorization branch from a1623ea to 4ce4236 Compare July 10, 2026 21:17
Comment thread packages/stormshield/changelog.yml Resolved
Comment thread packages/stormshield/changelog.yml Resolved
@arenard
arenard force-pushed the stormshield-ecs-categorization branch from 4ce4236 to ccd7280 Compare July 14, 2026 14:13
def logtype = ctx.stormshield?.logtype;
def entry = params.logtypes[logtype];
if (entry == null) {
entry = ['kind': 'event', 'category': ['network'], 'type': ['info']];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity: 🔵 Low confidence: low path: packages/stormshield/data_stream/log/elasticsearch/ingest_pipeline/default.yml:703

The categorization fallback forces event.category: [network] for any unlisted log family, so a non-network family (e.g. the futuretype fixture) is labelled a network event; consider a neutral fallback that omits category instead.

Details

When logtype is absent from the logtypes map, the script assigns kind: event, category: [network], type: [info]. The test-log-families.log futuretype sample confirms this happens today: an unknown family is emitted with event.category: [network]. Because event.category drives detection-rule scoping and the network dashboards, any future/unmapped family (which could be host-, configuration-, or authentication-oriented) is silently pulled into the network bucket. event.kind: event is a safe default; the questionable part is asserting a concrete category the event may not belong to.

Recommendation:

Drop the forced category (and type) from the unknown-family fallback so unmapped families are left uncategorized rather than mislabelled as network:

def logtype = ctx.stormshield?.logtype;
def entry = params.logtypes[logtype];
if (ctx.event == null) {
    ctx.event = [:];
}
if (entry == null) {
    // Unknown family: mark as a generic event but do not assert a category.
    ctx.event.kind = 'event';
} else {
    ctx.event.kind = entry.kind;
    ctx.event.category = new ArrayList(entry.category);
    ctx.event.type = new ArrayList(entry.type);
    if (params.action_logtypes.contains(logtype) && ctx.event.action instanceof String) {
        def mapped = params.action_types[ctx.event.action.toLowerCase()];
        if (mapped != null && !ctx.event.type.contains(mapped)) {
            ctx.event.type.add(mapped);
        }
    }
}

If the network default is intentional for this firewall, no change is needed — the documentation already states it.


🤖 AI-Generated Review | Vera Review Bot | 📚 Knowledge base: integration-skills

⚠️ Automated review — verify suggestions before applying.

@arenard arenard Jul 14, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The network default is intentional and documented in the README's categorization notes. All 26 families the vendor currently documents are explicitly categorized, so the fallback only guards families introduced by future firmware.
On a network appliance, network/info is the least-wrong assumption for those, with stormshield.logtype remaining the precise discriminator for scoping.
Happy to switch to a category-less fallback (event.kind: event only) if it is prefered.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose the argument for making the fallback category-less is that if there is a new family added in the future, it should be:

  • Hopefully obvious that something is amiss since we don't have categorizations on the event
  • "Easier" to make a change to set the correct category, versus having to make a "breaking" change when we change the categorization from network to something else. The concern here is a user starts relying on "network" being present before we catch the incorrect labeling, then we break their workflow.

I think for the second reason, I'm leaning towards leaving unknown events uncategorized.

@arenard arenard Jul 17, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, your forward-compatibility argument settles it. Switched to a category-less fallback: unknown families now get event.kind: event only, with no event.category/event.type asserted. The futuretype test sample and the README note are updated accordingly.

@arenard
arenard force-pushed the stormshield-ecs-categorization branch from ccd7280 to 6a2d7fa Compare July 14, 2026 14:30
@vera-review-bot

Copy link
Copy Markdown
Contributor

No issues across the latest commits 7109bf4, 6a2d7fa.

Review summary

Issues found across earlier commits 3ccf9e6…ccd7280 (27 commits) — 1 low
  • 🔵 The categorization fallback forces event.category: [network] for any unlisted log family, so a non-network family (e.g. the futuretype fixture) is labelled a network event (link) (Unresolved)
Issues found across earlier commits 4ce4236 — 2 medium
  • 🟡 Changelog links a different PR number (link) (Resolved)
  • 🟡 Changelog links a different PR number (link) (Resolved)
Issues found across earlier commits a1623ea — 3 medium
  • 🟡 Authentication events never set event.outcome, so successful and failed logins are indistinguishable by outcome (link) (Unresolved)
  • 🟡 Changelog links a different PR number (link) (Unresolved)
  • 🟡 Changelog links a different PR number (link) (Resolved)

A new commit triggers another review — at most once every 15 minutes. I skip the PR while it's approved or has merge conflicts.

🤖 AI-Generated Review | Vera Review Bot | 📚 Knowledge base: integration-skills

⚠️ Automated review — verify suggestions before applying.

@taylor-swanson taylor-swanson left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall I think the changes look great. I put my two cents about the fallback for category-less down below. Otherwise, just a couple of minor changes to some if statements.

def logtype = ctx.stormshield?.logtype;
def entry = params.logtypes[logtype];
if (entry == null) {
entry = ['kind': 'event', 'category': ['network'], 'type': ['info']];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose the argument for making the fallback category-less is that if there is a new family added in the future, it should be:

  • Hopefully obvious that something is amiss since we don't have categorizations on the event
  • "Easier" to make a change to set the correct category, versus having to make a "breaking" change when we change the categorization from network to something else. The concern here is a user starts relying on "network" being present before we catch the incorrect labeling, then we break their workflow.

I think for the second reason, I'm leaning towards leaving unknown events uncategorized.

@arenard
arenard force-pushed the stormshield-ecs-categorization branch from 6a2d7fa to f2dbfd6 Compare July 17, 2026 15:27
Set event.kind, event.category and event.type for every SNS log family
through a table-driven Painless script keyed on logtype, with allowed/denied
event.type modifiers derived case-insensitively from the rule action. The
periodic statistics families (monitor, filterstat, count, routerstat,
authstat, ipsecstat) are tagged event.kind: metric so health telemetry can
be excluded from detection scopes with a single filter. Unknown families
fall back to event.kind: event without asserting a category or type,
covered by a dedicated test sample. The
script only runs on documents without an error, so the pipeline_error kind
set by sub-pipeline failure handlers is preserved.

Add the ECS network mappings tracked in elastic#10114: rcvd to destination.bytes
(mirroring the existing sent mapping), network.bytes as the sum of both,
srcif/srcifname/dstif/dstifname copied to observer.ingress and
observer.egress interface fields, and network.direction computed with
private ranges as internal networks. Promote alarm fields (alarmid to
event.code, risk to event.risk_score, pri to event.severity on the alarm
scale where 1 is major and 4 is minor), HTTP proxy fields (arg to
url.original, url.domain from destination.domain), and populate
related.hosts. All mappings are copies; no stormshield.* field moves or
changes location. Guard the ASN geoip processors with null checks, matching
the geo processors.

Fix the count sub-pipeline, which failed on every count log since creation:
the script called splitByToken, which does not exist in Painless, and
collapsed all rules into a single map. Rule counters are now a sorted array
under stormshield.metadata.rule_stats. Extend the metadata move list with
the documented alarm, proxy, vpn and auth fields so they land under
stormshield.metadata instead of being left unmapped.

Add pipeline test samples for the alarm, auth, web, vpn, xvpn, count and
filter families, derived from the log format examples in the official
Stormshield documentation with sanitized addresses, including uppercase and
empty action values. Add an Alarms (IPS) dashboard keyed on the new
categorization fields. Document the categorization table in the README.
@arenard
arenard force-pushed the stormshield-ecs-categorization branch from f2dbfd6 to 5098fd8 Compare July 17, 2026 15:38
@elastic-vault-github-plugin-prod

Copy link
Copy Markdown
Contributor

✅ All changelog entries have the correct PR link.

@vera-review-bot

Copy link
Copy Markdown
Contributor

⚠️ @arenard I couldn't complete the review for commits 2807630…5098fd8 (19 commits) after several attempts. A maintainer can re-run it with @vera-review-bot review.

@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

💚 Build Succeeded

History

@taylor-swanson taylor-swanson left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@taylor-swanson
taylor-swanson merged commit 1fcadfa into elastic:main Jul 17, 2026
12 checks passed
@elastic-vault-github-plugin-prod

Copy link
Copy Markdown
Contributor

Package stormshield - 1.6.0 containing this change is available at https://epr.elastic.co/package/stormshield/1.6.0/

christophercutajar pushed a commit to christophercutajar/integrations that referenced this pull request Jul 21, 2026
…tic#20031)

Set event.kind, event.category and event.type for every SNS log family
through a table-driven Painless script keyed on logtype, with allowed/denied
event.type modifiers derived case-insensitively from the rule action. The
periodic statistics families (monitor, filterstat, count, routerstat,
authstat, ipsecstat) are tagged event.kind: metric so health telemetry can
be excluded from detection scopes with a single filter. Unknown families
fall back to event.kind: event without asserting a category or type,
covered by a dedicated test sample. The
script only runs on documents without an error, so the pipeline_error kind
set by sub-pipeline failure handlers is preserved.

Add the ECS network mappings tracked in elastic#10114: rcvd to destination.bytes
(mirroring the existing sent mapping), network.bytes as the sum of both,
srcif/srcifname/dstif/dstifname copied to observer.ingress and
observer.egress interface fields, and network.direction computed with
private ranges as internal networks. Promote alarm fields (alarmid to
event.code, risk to event.risk_score, pri to event.severity on the alarm
scale where 1 is major and 4 is minor), HTTP proxy fields (arg to
url.original, url.domain from destination.domain), and populate
related.hosts. All mappings are copies; no stormshield.* field moves or
changes location. Guard the ASN geoip processors with null checks, matching
the geo processors.

Fix the count sub-pipeline, which failed on every count log since creation:
the script called splitByToken, which does not exist in Painless, and
collapsed all rules into a single map. Rule counters are now a sorted array
under stormshield.metadata.rule_stats. Extend the metadata move list with
the documented alarm, proxy, vpn and auth fields so they land under
stormshield.metadata instead of being left unmapped.

Add pipeline test samples for the alarm, auth, web, vpn, xvpn, count and
filter families, derived from the log format examples in the official
Stormshield documentation with sanitized addresses, including uppercase and
empty action values. Add an Alarms (IPS) dashboard keyed on the new
categorization fields. Document the categorization table in the README.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dashboard Relates to a Kibana dashboard bug, enhancement, or modification. documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. Integration:stormshield StormShield SNS Team:Integration-Experience Security Integrations Integration Experience [elastic/integration-experience]

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants