-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Filebeat] Iptables / ubiquiti module #10176
Conversation
Pinging @elastic/secops |
c968354
to
4bec0c3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some questions
"iptables.tcp_window": 8192, | ||
"iptables.ttl": 115, | ||
"log.offset": 0, | ||
"message": "Jan 8 03:37:09 example-host kernel: iptables DROP_INPUT: IN=eth0 OUT= MAC=90:10:35:5a:1e:3a:90:10:9e:ec:2c:71:08:00 SRC=203.0.113.36 DST=172.16.54.114 LEN=52 TOS=0x00 PREC=0x00 TTL=115 ID=15743 DF PROTO=TCP SPT=17805 DPT=445 WINDOW=8192 RES=0x00 SYN URGP=0 ", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shall I keep or remove the original message
field?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@webmat How is this handled in the other modules?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In some modules where there's an actual user-readable message, I grokked the structured headers and sometimes message content, and left only the user-readable message in message
. I think that's helpful for those situations.
These firewall logs are entirely structured content, however. So I think you can remove them for now.
There's two corollaries to this:
- We've discussed in SecOps always populating
message
with an event summary, but I will leave it up to @adriansr on whether to do that or not in this PR. I think it could be tackled later, though. - I saw some activity around a beat-wide option to keep/discard the original messages (in
event.original
, notmessage
). I think @kvch is the best person to tell you about this. For this reason, I don't think this module should handle preservation of the original explicitly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided on log.original
, as the message could've been partially parsed by the syslog input
4bec0c3
to
55dfcb0
Compare
x-pack/filebeat/module/iptables/_meta/kibana/6/dashboard/Filebeat-Suricata-Alert-Overview.json
Outdated
Show resolved
Hide resolved
"iptables.tcp_window": 8192, | ||
"iptables.ttl": 115, | ||
"log.offset": 0, | ||
"message": "Jan 8 03:37:09 example-host kernel: iptables DROP_INPUT: IN=eth0 OUT= MAC=90:10:35:5a:1e:3a:90:10:9e:ec:2c:71:08:00 SRC=203.0.113.36 DST=172.16.54.114 LEN=52 TOS=0x00 PREC=0x00 TTL=115 ID=15743 DF PROTO=TCP SPT=17805 DPT=445 WINDOW=8192 RES=0x00 SYN URGP=0 ", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In some modules where there's an actual user-readable message, I grokked the structured headers and sometimes message content, and left only the user-readable message in message
. I think that's helpful for those situations.
These firewall logs are entirely structured content, however. So I think you can remove them for now.
There's two corollaries to this:
- We've discussed in SecOps always populating
message
with an event summary, but I will leave it up to @adriansr on whether to do that or not in this PR. I think it could be tackled later, though. - I saw some activity around a beat-wide option to keep/discard the original messages (in
event.original
, notmessage
). I think @kvch is the best person to tell you about this. For this reason, I don't think this module should handle preservation of the original explicitly.
I realized this was a WIP, so I didn't mean to post the comments about Suricata LOL |
"field": "source.port", | ||
"type": "integer", | ||
"ignore_missing": true | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you cast directly in the grok patterns with the %{SYNTAX:SEMANTIC:TYPE}
syntax instead of using convert?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I didn't know about casting support in Grok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job as usual.
Note to other reviewers: I didn't look too closely at the script processors in the pipeline.
42ec570
to
026d904
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did a full read through. Noticed minor details, one question.
Amazing work!
"IPTABLES_IPV6": "SRC=%{IPV6:source.ip} DST=%{IPV6:destination.ip} LEN=%{UNSIGNED_INT:iptables.length:int} TC=%{UNSIGNED_INT:iptables.tos} HOPLIMIT=%{UNSIGNED_INT:iptables.ttl:int} FLOWLBL=%{UNSIGNED_INT:iptables.flow_label:int} %{IPTABLES_IP_PAYLOAD}", | ||
"IPTABLES": "%{IPTABLES_ETHERNET} (:?%{IPTABLES_IP}|%{IPTABLES_IPV6})", | ||
"UBIQUITI_FIELD": "[^-\\]]*", | ||
"UBIQUITI_RULESET_NAME": "[^\\]]*", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should UBIQUITI_FIELD and UBIQUITI_RULESET_NAME be 1+
characters, instead of 0+
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, my head is spinning from so much grokking 😆
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather make the regex as tolerant as possible. I'm worried for example about a case where the rule set name could be empty (it's user supplied). Is there a scenario where 0+ causes a problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, just wanted to make sure that was desired. If you're worried there may be situations where it's empty, then * is fine :-)
} | ||
] | ||
}, | ||
"source": "for (action in params.mappings) { def src = ctx[action.source.object]; if (src != null) { Map map = action.map; String key = src[action.source.key]; String mapping = map[key]; if (mapping != null) { Map dst = ctx[action.destination.object]; if (dst == null) { dst = new HashMap(); ctx[action.destination.object] = dst;} dst[action.destination.key] = mapping; } } }" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain what this does, please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given a source and destination fields in the form "object.key",
it looks up the value of the source field in the given map, and if it exists, it will set the destination field to the mapped value.
for example, it sets network.type to ipv6 if iptables.ether_type is 86:dd, or sets network.transport to ipv6-icmp if its original value was icmpv6.
Is there a better way to do it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see it now. Thanks for explaining.
Only thing I see with this is that right now you're limited to a depth of 2 fields (e.g. network.transport
) for source and destination field names. But I'm not sure it's worth modifying for this detail, as we don't need to support deeper nesting for now.
Check out how much I could pack in a screenful in 10192, though. Have you considered just using the basic processors and formatting them more aggressively? ;-)
I still see a need for some custom code for the mapping of values, so just something to think about. No action needed.
By the way, I've been wanting something similar to this in Ingest Node in general. Since right now is a bit late to make requests for 7.0 (understatement of the day), I'm making a note of your code. We could potentially extract it out to a reusable pipeline, pack a bunch of mappings in a temp variable, and call this shared "mapping pipeline". I've noted down this idea in issue elastic/ecs#181
@@ -32,7 +32,8 @@ | |||
"IPTABLES_IP_FRAGFLAG": "((?<= )(CE|DF|MF))*", | |||
"IPTABLES_IP_START": "SRC=%{IPV4:source.ip} DST=%{IPV4:destination.ip} LEN=%{UNSIGNED_INT:iptables.length:int} TOS=0x%{BASE16NUM:iptables.tos} PREC=0x%{BASE16NUM:iptables.precedence_bits} TTL=%{UNSIGNED_INT:iptables.ttl:int} ID=%{UNSIGNED_INT:iptables.id:int}(?: %{IPTABLES_IP_FRAGFLAG:iptables.fragment_flags})?(?: FRAG: %{UNSIGNED_INT:iptables.fragment_offset:int})?", | |||
"IPTABLES_IP": "%{IPTABLES_IP_START} %{IPTABLES_IP_PAYLOAD}", | |||
"IPTABLES_IPV6": "SRC=%{IPV6:source.ip} DST=%{IPV6:destination.ip} LEN=%{UNSIGNED_INT:iptables.length:int} TC=%{UNSIGNED_INT:iptables.tos} HOPLIMIT=%{UNSIGNED_INT:iptables.ttl:int} FLOWLBL=%{UNSIGNED_INT:iptables.flow_label:int} %{IPTABLES_IP_PAYLOAD}", | |||
"IPTABLES_IPV6_START": "SRC=%{IPV6:source.ip} DST=%{IPV6:destination.ip} LEN=%{UNSIGNED_INT:iptables.length:int} TC=%{UNSIGNED_INT:iptables.tos} HOPLIMIT=%{UNSIGNED_INT:iptables.ttl:int} FLOWLBL=%{UNSIGNED_INT:iptables.flow_label:int}", | |||
"IPTABLES_IPV6": "%{IPTABLES_IPV6_START} %{IPTABLES_IP_PAYLOAD}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❤️ Makes the similarity (... %{IPTABLES_IP_PAYLOAD}
) more obvious :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Feel free to keep the mapping code as is. I think part of it could have been done in a more compact way, like in the link I pasted up there.
But on the other hand, we may want to extract this out to a reusable pipeline eventually. So let's keep it in for now, as a test bed for this approach.
This adds a new x-pack module to parse iptables logs from a file. The module understands additional fields added by Ubiquiti firewalls. Example iptables event: ``` "iptables": { "ether_type": 2048, "input_device": "eth0", "output_device": "wan1", "tcp": { "reserved_bits": 0, "flags": "ACK", "window": 128 }, "precedence_bits": 0, "length": 123, "tos": 0, "output_device": "lo", "id": 12345, "ttl": 255 }, ``` For Ubiquiti logs, it parses the Ubiquiti tag before iptables logs. Format: RuleSet-RuleNumber-Action It's a common pattern to format the RuleSet as "InputDevice-OutputDevice". Action can be A for allow and D for Deny. RuleNumber can be a number or "default". For [source-dest-42-D]: ``` "iptables.ubiquiti.input_zone": "source", "iptables.ubiquiti.output_zone": "dest", "iptables.ubiquiti.rule_number": "42", "iptables.ubiquiti.rule_set": "source-dest", "event.outcome": "deny", ``` The following ECS fields are populated: ``` "destination.ip": "10.4.0.5", "destination.mac": "90:10:20:76:8d:20", "destination.port": 443, "ecs.version": "1.0.0-beta2", "event.dataset": "iptables.log", "event.module": "iptables", "event.outcome": "deny", (only when Ubiquiti extension found) "fileset.name": "log", "network.transport": "tcp", "network.type": "ipv4", "source.geo.city_name": "Bellaterra", "source.geo.continent_name": "Europe", "source.geo.country_iso_code": "ES", "source.geo.location.lat": 41.5026, "source.geo.location.lon": 2.0875, "source.geo.region_iso_code": "ES-B", "source.geo.region_name": "Barcelona", "source.ip": "158.109.0.1", "source.mac": "90:10:65:29:b6:2a", "source.port": 38842 ``` Closes elastic#8781 Co-Authored-by: James Spiteri <james.spiteri@elastic.co>
3033e8e
to
938b032
Compare
jenkins, test this |
This adds a new x-pack module to parse iptables logs from a file. The module understands additional fields added by Ubiquiti firewalls. Example iptables event: ``` "iptables": { "ether_type": 2048, "input_device": "eth0", "output_device": "wan1", "tcp": { "reserved_bits": 0, "flags": "ACK", "window": 128 }, "precedence_bits": 0, "length": 123, "tos": 0, "output_device": "lo", "id": 12345, "ttl": 255 }, ``` For Ubiquiti logs, it parses the Ubiquiti tag before iptables logs. Format: RuleSet-RuleNumber-Action It's a common pattern to format the RuleSet as "InputDevice-OutputDevice". Action can be A for allow and D for Deny. RuleNumber can be a number or "default". For [source-dest-42-D]: ``` "iptables.ubiquiti.input_zone": "source", "iptables.ubiquiti.output_zone": "dest", "iptables.ubiquiti.rule_number": "42", "iptables.ubiquiti.rule_set": "source-dest", "event.outcome": "deny", ``` The following ECS fields are populated: ``` "destination.ip": "10.4.0.5", "destination.mac": "90:10:20:76:8d:20", "destination.port": 443, "ecs.version": "1.0.0-beta2", "event.dataset": "iptables.log", "event.module": "iptables", "event.outcome": "deny", (only when Ubiquiti extension found) "fileset.name": "log", "network.transport": "tcp", "network.type": "ipv4", "source.geo.city_name": "Bellaterra", "source.geo.continent_name": "Europe", "source.geo.country_iso_code": "ES", "source.geo.location.lat": 41.5026, "source.geo.location.lon": 2.0875, "source.geo.region_iso_code": "ES-B", "source.geo.region_name": "Barcelona", "source.ip": "158.109.0.1", "source.mac": "90:10:65:29:b6:2a", "source.port": 38842 ``` Closes elastic#8781 Co-Authored-by: James Spiteri <james.spiteri@elastic.co> (cherry picked from commit d7c14df)
…10462) This adds a new x-pack module to parse iptables logs from a file. The module understands additional fields added by Ubiquiti firewalls. Example iptables event: ``` "iptables": { "ether_type": 2048, "input_device": "eth0", "output_device": "wan1", "tcp": { "reserved_bits": 0, "flags": "ACK", "window": 128 }, "precedence_bits": 0, "length": 123, "tos": 0, "output_device": "lo", "id": 12345, "ttl": 255 }, ``` For Ubiquiti logs, it parses the Ubiquiti tag before iptables logs. Format: RuleSet-RuleNumber-Action It's a common pattern to format the RuleSet as "InputDevice-OutputDevice". Action can be A for allow and D for Deny. RuleNumber can be a number or "default". For [source-dest-42-D]: ``` "iptables.ubiquiti.input_zone": "source", "iptables.ubiquiti.output_zone": "dest", "iptables.ubiquiti.rule_number": "42", "iptables.ubiquiti.rule_set": "source-dest", "event.outcome": "deny", ``` The following ECS fields are populated: ``` "destination.ip": "10.4.0.5", "destination.mac": "90:10:20:76:8d:20", "destination.port": 443, "ecs.version": "1.0.0-beta2", "event.dataset": "iptables.log", "event.module": "iptables", "event.outcome": "deny", (only when Ubiquiti extension found) "fileset.name": "log", "network.transport": "tcp", "network.type": "ipv4", "source.geo.city_name": "Bellaterra", "source.geo.continent_name": "Europe", "source.geo.country_iso_code": "ES", "source.geo.location.lat": 41.5026, "source.geo.location.lon": 2.0875, "source.geo.region_iso_code": "ES-B", "source.geo.region_name": "Barcelona", "source.ip": "158.109.0.1", "source.mac": "90:10:65:29:b6:2a", "source.port": 38842 ``` Closes #8781 Co-Authored-by: James Spiteri <james.spiteri@elastic.co> (cherry picked from commit d7c14df)
This adds a new x-pack module to parse iptables logs from a file. The module understands additional fields added by Ubiquiti firewalls.
Example iptables event:
For Ubiquiti logs, it parses the Ubiquiti tag before iptables logs.
Format: RuleSet-RuleNumber-Action
It's a common pattern to format the RuleSet as "InputZone-OutputZone". Action can be A for allow and D for Deny. RuleNumber can be a number or "default".
For [source-dest-42-D]:
The following ECS fields are populated:
Closes #8781