You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Part of:#2696 · Needs first:#2697 (click-through to the Log Explorer and the value/count table) Related:#1725 (parsers and rules for this integration, owned by the detection team)
Goal
Ship a built-in Bitdefender GravityZone dashboard that shows, at a glance, how much Bitdefender GravityZone is sending, whether it is still sending, and what kinds of events they are. The heart of it is the list of Bitdefender GravityZone logs grouped by event types (widget W7): click one and the Log Explorer opens on exactly those logs.
Where the data comes from
Integration (catalog name)
BITDEFENDER
Data type
antivirus-bitdefender-gz
How the logs arrive
UTMStack registers itself in GravityZone's Event Push Service (service type 'cef'), and GravityZone then posts batches of CEF events over HTTPS to the plugin on port 8000; each event whose BitdefenderGZCompanyId matches a configured company ID becomes one log.
The name of the UTMStack config group (one GravityZone connection with its API key and company IDs). Proof: plugins/bitdefender/server/message.go CreateMessage sets DataSource: cnf.GroupName for the group whose company ID appears in the event; the parser never writes dataSource. So W6 is 'Logs by GravityZone connection'; the endpoint is in target.host.
Grouped by
log.eventType (event types)
Why log.eventType: The CEF header grok writes the CEF 'Name' slot to log.eventType on every event. GravityZone fills it with a readable, fixed English name per event module ('AntiMalware', 'Behavioral scanning', 'Firewall', 'Web Control'), so it is low cardinality and needs no translation. The same information exists as a short code in log.BitdefenderGZModule (av, avc, fw, uc), which the KPI filters use because the codes are listed in the plugin's push subscription.
Standard layout from the parent issue; rows W2, W3 and W9 onward are specific to this integration.
#
Title
Shown as
Query
Why
W1
Total logs
number
logs: count
All GravityZone events in the selected time range.
W2
Threat detections
number
logs: count; filter log.BitdefenderGZModule is one of [av, avc, antiexploit, ransomware-mitigation, network-sandboxing, exchange-malware, network-monitor]
Events from the threat modules: antimalware, Advanced Threat Control, anti-exploit, ransomware mitigation, Sandbox Analyzer, Exchange malware and Network Attack Defense.
W3
Threats not removed
number
logs: count; filter actionResult = failed
GravityZone left the threat in place: action 'still present', 'ignored', 'no action' or 'reportOnly', which the parser marks actionResult 'failed'.
W4
Alerts
number
alerts: count
Alerts raised from GravityZone logs.
W5
Log volume over time
area chart
logs: count over time
Shows gaps in the push feed and bursts of events.
W6
Logs by GravityZone connection
bar chart
logs: top 10 values of dataSource
dataSource is the UTMStack config group of the GravityZone connection, so this shows which connection is busiest or silent.
W7
Top event types
value and count table
logs: top 25 values of log.eventType; filter log.eventType exists
The main list: GravityZone event types by count; click one to open those logs.
W8
Event types over time (top 5)
line chart
logs: count over time, one line per value of log.eventType (top 5); filter log.eventType exists
When each of the five most common event types happened.
W9
Top malware
bar chart
logs: top 10 values of target.malware; filter target.malware exists
Most frequent malware names.
W10
Top endpoints
bar chart
logs: top 10 values of target.host; filter target.host exists
Endpoints with the most events.
W11
Top users
bar chart
logs: top 10 values of target.user; filter target.user exists
Users logged on when detections happened.
W12a
Actions taken
bar chart
logs: top 10 values of action; filter action exists
What GravityZone did (blocked, deleted, quarantined, still present, site blocked and so on).
W12b
Top file paths
bar chart
logs: top 10 values of target.path; filter target.path exists
Files and programs detected most often (antimalware, behavior, anti-exploit events).
W13
Alerts by rule
bar chart
alerts: top 10 values of name
Which GravityZone detection rules fire most.
W14
Alerts by severity
bar chart
alerts: top 50 values of severity
Split of GravityZone alerts into low, medium and high.
target.user: User on the endpoint (CEF suser). Examples: jdoe, stefan@graylog.com. Source: rescue grok for suser= -> log.suserFull -> rename to target.user.
action: What GravityZone did (CEF act, or BitdefenderGZMainAction for incidents). Examples: blocked, deleted, quarantined, still present, uc_site_blocked. Source: rescue grok for act= -> log.actFull; rename [log.actFull, log.BitdefenderGZMainAction] -> action.
actionResult: 'success' when the threat was stopped, 'failed' when it was left in place. Examples: success, failed. Source: add 'success' where action in [blocked, block, aph_blocked, portscan_blocked, deleted, disinfected, quarantined, restored]; add 'failed' where action in ['still present', ignored, 'no action', reportOnly].
target.path: Path of the detected file or process. Examples: C:\\Users\\jdoe\\Downloads\\b93ef2d1-160c-4bd9-9cbb-cb59ca59939e.tmp. Source: rescue grok for filePath= -> log.filePathFull -> rename to target.path.
The plugin forwards an event only when it contains 'BitdefenderGZCompanyId=' for one of the configured company IDs (plugins/bitdefender/server/message.go); anything else is dropped before parsing and never counted.
HyperDetect ('hd') events are not in the plugin's push subscription and Product Modules Status ('modules') is set to false (plugins/bitdefender/config/template.go), so those events never arrive even though the parser handles them. Install, registration and uninstall events are off too.
The standard severity column holds the CEF severity number as text ('3', '9', '10'), not low, medium or high, so there is no severity widget.
actionResult only covers some actions: 'success' for blocked, block, aph_blocked, portscan_blocked, deleted, disinfected, quarantined and restored; 'failed' for 'still present', ignored, 'no action' and reportOnly. Other values such as 'Blocked' (behavioral scanning), 'uc_site_blocked', 'data_protection_blocked' and 'kill' get none; W12a shows the raw action instead.
W2 counts events of the threat modules av, avc, antiexploit, ransomware-mitigation, network-sandboxing, exchange-malware and network-monitor (module codes from the plugin's subscription; names from Bitdefender's event types page).
Values with spaces are rescued only for act, filePath, sproc, fname, suser, request, BitdefenderGZDetectionName, BitdefenderGZMalwareName and BitdefenderGZAttackTypes. Other keys are cut at the first space; for example dvchost 'Computer 1' becomes 'Computer' in target.host.
CEF escapes are not decoded, so backslashes in paths stay doubled (for example 'C:\Users\jdoe\...').
dataSource is the config group, so W6 shows one bar per GravityZone connection, not per endpoint.
deviceTime is set from the detection time (BitdefenderGZDetectionTime, start or end), but the time charts use @timestamp, which is when the plugin received the push.
No field used here depends on the engine's underscore rule (GravityZone CEF keys have no underscores); the replay gave the same result with both rules. Checked with a step-by-step replay of this filter over 20 events, including GravityZone push samples published in Sekoia's documentation.
Parser problems found while designing this
These are not dashboard work, but they limit what the dashboard can show. They belong to #1725; raise them there rather than working around them in the dashboard.
severity gets the raw CEF number (rename log.severity -> severity) instead of low, medium or high, so any view that compares severity across products mixes numbers and words. Fix: keep the number in log.cefSeverity and map it (for example 0-3 low, 4-6 medium, 7-10 high).
actionResult matching is case-sensitive and incomplete: 'Blocked' from behavioral scanning, 'uc_site_blocked', 'data_protection_blocked' and 'kill' get no actionResult.
Keys outside the rescue list are cut at the first space (dvchost 'Computer 1' becomes 'Computer').
log.BitdefenderGZMalwareName keeps a cut copy from the kv step ('EICAR-Test-File') next to the full target.malware, because it is not in the final delete list.
Plugin, not parser: the company IDs are split on ',' without trimming (config/module.go), but the setup guide says 'comma-separated'; an ID typed after ', ' never matches and all its events are dropped.
Plugin, not parser: the push subscription leaves out 'hd' (HyperDetect), so HyperDetect detections never reach UTMStack.
How to build it
Before you start: parser field names are changing while the parsers are updated for the engine's new underscore handling (see "Field names are about to move" in #2696). Check every field in this issue against the v12 parser at that moment and against real logs, and build against what you find.
Add definitions/dashboards/integration-bitdefender.yaml. Keep it in the top folder: the test that checks shipped dashboards (TestEveryShippedDashboardDefinitionIsValid) only reads the top folder.
Start from the file below; it follows the table above and passes the same checks as the backend (domain.Spec.Validate).
definitions/dashboards/integration-bitdefender.yaml is merged to release/v12.0.0 and go test ./modules/dashboards/... passes in backend/.
With Bitdefender GravityZone logs flowing on a v12 test server, every widget shows data. A widget that stays empty while logs arrive means a wrong field or value: fix it, don't ship it.
Clicking a row, bar or line point opens the Log Explorer on the same logs, and the Log Explorer count matches the widget.
A time range with no logs shows empty states, not errors.
A screenshot of the finished dashboard is attached to this issue.
Part of: #2696 · Needs first: #2697 (click-through to the Log Explorer and the value/count table)
Related: #1725 (parsers and rules for this integration, owned by the detection team)
Goal
Ship a built-in Bitdefender GravityZone dashboard that shows, at a glance, how much Bitdefender GravityZone is sending, whether it is still sending, and what kinds of events they are. The heart of it is the list of Bitdefender GravityZone logs grouped by event types (widget W7): click one and the Log Explorer opens on exactly those logs.
Where the data comes from
BITDEFENDERantivirus-bitdefender-gzdefinitions/filters/antivirus/bitdefender_gz.yamldataSourceholdslog.eventType(event types)Why
log.eventType: The CEF header grok writes the CEF 'Name' slot to log.eventType on every event. GravityZone fills it with a readable, fixed English name per event module ('AntiMalware', 'Behavioral scanning', 'Firewall', 'Web Control'), so it is low cardinality and needs no translation. The same information exists as a short code in log.BitdefenderGZModule (av, avc, fw, uc), which the KPI filters use because the codes are listed in the plugin's push subscription.Typical values:
AntiMalware (module av),Behavioral scanning (module avc, Advanced Threat Control),Exploit Mitigation (module antiexploit),Ransomware Detection (module ransomware-mitigation),Web Control (module uc),Firewall (module fw),New Incident (module new-incident)Widgets
Standard layout from the parent issue; rows W2, W3 and W9 onward are specific to this integration.
log.BitdefenderGZModuleis one of [av, avc, antiexploit, ransomware-mitigation, network-sandboxing, exchange-malware, network-monitor]actionResult= faileddataSourcelog.eventType; filterlog.eventTypeexistslog.eventType(top 5); filterlog.eventTypeexiststarget.malware; filtertarget.malwareexiststarget.host; filtertarget.hostexiststarget.user; filtertarget.userexistsaction; filteractionexiststarget.path; filtertarget.pathexistsnameseverity@timestamp,dataSource,log.eventType,target.host,target.malware,action,target.user,target.pathFields used and where they come from
log.eventType: Event name from the CEF header. Examples:AntiMalware,Behavioral scanning,Antiphishing,Task Status. Source: CEF header grok on log.restData (fieldName log.eventType) + trim suffix '|'.log.BitdefenderGZModule: GravityZone event module code. Examples:av,avc,antiexploit,ransomware-mitigation,network-sandboxing. Source: kv step on log.restData (key BitdefenderGZModule, not renamed); codes match plugins/bitdefender/config/template.go subscribeToEventTypes.target.malware: Full malware name. Examples:EICAR-Test-File (not a virus),Trojan.GenericKD.1234. Source: rescue grok for BitdefenderGZMalwareName= (keeps spaces) -> log.BitdefenderGZMalwareNameFull -> rename to target.malware.target.host: Endpoint name (CEF dvchost). Examples:Desktop-JDO,Graylog-Win11. Source: kv (dvchost) -> rename log.dvchost -> target.host.target.user: User on the endpoint (CEF suser). Examples:jdoe,stefan@graylog.com. Source: rescue grok for suser= -> log.suserFull -> rename to target.user.action: What GravityZone did (CEF act, or BitdefenderGZMainAction for incidents). Examples:blocked,deleted,quarantined,still present,uc_site_blocked. Source: rescue grok for act= -> log.actFull; rename [log.actFull, log.BitdefenderGZMainAction] -> action.actionResult: 'success' when the threat was stopped, 'failed' when it was left in place. Examples:success,failed. Source: add 'success' where action in [blocked, block, aph_blocked, portscan_blocked, deleted, disinfected, quarantined, restored]; add 'failed' where action in ['still present', ignored, 'no action', reportOnly].target.path: Path of the detected file or process. Examples:C:\\Users\\jdoe\\Downloads\\b93ef2d1-160c-4bd9-9cbb-cb59ca59939e.tmp. Source: rescue grok for filePath= -> log.filePathFull -> rename to target.path.severity: CEF header severity number, as text. Examples:3,9,10. Source: CEF header grok (log.severity) + trim, then rename log.severity -> severity.Watch out for
Parser problems found while designing this
These are not dashboard work, but they limit what the dashboard can show. They belong to #1725; raise them there rather than working around them in the dashboard.
How to build it
Before you start: parser field names are changing while the parsers are updated for the engine's new underscore handling (see "Field names are about to move" in #2696). Check every field in this issue against the v12 parser at that moment and against real logs, and build against what you find.
definitions/dashboards/integration-bitdefender.yaml. Keep it in the top folder: the test that checks shipped dashboards (TestEveryShippedDashboardDefinitionIsValid) only reads the top folder.domain.Spec.Validate).categoryquery shown with chart typetable. It already renders; v12 dashboards: groundwork for integration dashboards (click-through to the Log Explorer, value/count table, Agents dashboard fix) #2697 makes its rows clickable and its headers readable.Starting dashboard file
Done when
definitions/dashboards/integration-bitdefender.yamlis merged torelease/v12.0.0andgo test ./modules/dashboards/...passes inbackend/.