grok/kv filter audit logs logstash - logstash

I'm learning how to use the grok plugin. I have a message string like so
"type=CRYPTO_SESSION msg=audit(111111.111:111111): pid=22730 uid=0 auid=123 ses=123 subj=system_u:system_r:sshd_t:a1-a1:a1.a1234 msg='op=xx=xx cipher=xx ksize=111 mac=xx pfs=xxx spid=111 suid=000 rport=000 laddr=11.11.111.111 lport=123 exe=\"/usr/sbin/sshd\" hostname=? addr=11.111.111.11 terminal=? res=success'"
I'd like to extract the fields laddr, addr, and lport. I created a patterns directory with the following structure
patterns
|
-- laddr
|
-- addr
My filter is written like so
filter {
grok {
patterns_dir => ["./patterns"]
match => { "messaage" => "%{LADDR:laddr} %{ADDR:addr}"}
}
}
I was expecting to extract at least laddr and addr. I get matches using https://grokdebug.herokuapp.com/. With these patterns
(?<laddr>\b(laddr=\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b)
(?<addr>\b(addr=\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b)
but the configuration fails to compile. I'm just going off of these docs: https://www.elastic.co/guide/en/logstash/current/plugins-filters-grok.html. I've also tried using a kv filter the issue that I run into when I try to use something like
filter{
kv {
value_split => "="
}
}
I end up with msg field showing up twice. I'd really like to figure out how to get the properties from this string. Any help would be greatly appreciated.

I think its field split :
filter {
kv {
field_split => "&?"
}
}
Did you try this, are you getting any error messages?

Related

logstash converting ruby code to logstash filters

I was wondering what will be the best way to implement the following task in logstash :
I have the following field that contains multiple paths divided by ':' :
my_field : "/var/log/my_custom_file.txt:/var/log/otherfile.log/:/root/aaa.jar
I want to add a new field called "first_file" that will contain only the file_name(without suffix) of the first path :
first_file : my_custom_file
I implemented it with the following ruby code ;
code => 'event.set("first_file",event.get("[my_field]").split(":")[0].split("/")[-1].split(".")[0])'
How can I use logstash filters (add_field,split,grok) to do the same task ? I feel like using ruby code should be my last option.
You could do it using just grok, but I think it would be clearer to use mutate to pull out the first value
mutate { split => { "my_field" => ":" } }
mutate { replace => "{ "my_field" => "[my_field][0]" } }
grok { match => { "my_field" => "/(?<my_field>[^/]+)\.%{WORD}$" } overwrite => [ "my_field" ] }
rather than
grok { match => { "my_field" => "/(?<my_field>[^/]+)\.%{WORD}:" } overwrite => [ "my_field" ] }
The (?<my_field>[^/]+) is a custom pattern (documented here) which creates a field called [my_field] from a sequence of one or more (+) characters which are not /
Yes with a basic grok you could match every field in the value.
This kind of filter must work (put it in your logstash configuration file), this one extract the "basename" of the file (filename without extension and path) :
filter{
grok {
match => { "my_field" => "%{GREEDYDATA}/%{WORD:filename}.%{WORD}:%{GREEDYDATA}/%{WORD:filename2}.%{WORD}:%{GREEDYDATA}/%{WORD:filename3}.%{WORD}" }
}
}
You could be more strict in grok with use of PATH in place of GREYDATA, I let you determine your best approach that works in your context.
You could debug the grok pattern with the online tool grokdebug.

Logstash issue with KV filter

I am trying to index a document in ElasticSearch through logstash. An example from the file I am trying to index is as follows
GET firstname=john&lastname=smith 400
My objective is to create an index that looks something like the following
HTTPMethod: GET
firstname : john
lastname: smith
query_time : 400
I did the following so far
filter {
grok{
match => {"message" => "%{WORD:HttpMethod} %{GREEDYDATA:KVText} %{NUMBER:time:int}"}
}
kv {
source => "KVText"
value_split => "&"
remove_field => [ "KVText" ]
}
}
However, when I execute the logstash conf file I see the following
"query_time": 400,
"message": "GET firstname=john&lastname=smith 400\r",
"HttpMethod": "GET",
"firstname=john": "lastname=smith"
I am not getting the index as a key1=value1 format as discrete values. e.g. firstname=john lastname=smith
Also, whenever I make a change to my log file the logstash process doesn't pick the change for indexing in real time. I have to rename the file and restart logstash. I do understand it has something to do with the since_db path in my logstash.conf.
Any pointers are truly appreciated.
Thanks
Nick
You are configuring the kv filter the wrong way.
The value_split param tells the filter what char to use for splitting one key/value pair (you should put "=") while the field_split config tells what char to use to split pairs from the string. Try using:
kv {
source => "KVText"
value_split => "="
field_split => "&"
remove_field => [ "KVText" ]
}

grok filtering pattern issue

I try to match the loglevel of a log file with a grok filter, but still getting a _grokparsefailure. The problem is maybe with the space between [ and the log level.
example of log: 2017-04-21 10:12:03,004 [ INFO] Message
my filter:
filter {
grok {
match => {
"log.level" => "\[ %{LOGLEVEL:loglevel}\]"
}
}
}
I also tried some other solutions without success:
"\[ *%{LOGLEVEL:loglevel}\]"
"\[%{SPACE}%{LOGLEVEL:loglevel}\]"
Thanks in advance for your help
The issue is with the option match in your filter: this option is a hash that tells the filter which field to look at and which field to look at.
Your regex is fine (you can check with http://grokconstructor.appspot.com/do/match), the issue is with the field name; it should be message.
So in your case, your filter should look like this:
grok {
match => {
"message" => "\[ %{LOGLEVEL:loglevel}\]"
}
}
The point is the default field is message and you need to match all the string
filter {
grok {
match => {
"message" => "%{TIMESTAMP_ISO8601:logDate} \[ %{LOGLEVEL:loglevel}\]%{GREEDYDATA:messages}"
}
}
}

Logstash _grokparsefailure

Would someone be able to add some clarity please? My grok pattern works fine when I test it against grokdebug and grokconstructor, but then I put it in Logastash it fails from the beginning. Any guidance would be greatly appreciated. Below is my filter and example log entry.
{"casename":"null","username":"null","startdate":"2015-05-26T01:09:23Z","enddate":"2015-05-26T01:09:23Z","time":"0.0156249","methodname":"null","url":"http://null.domain.com/null.php/null/jobs/_search?q=jobid:\"0\"&size=100&from=0","errortype":"null","errorinfo":"null","postdata":"null","methodtype":"null","servername":"null","gaggleid":"a51b90d6-1f82-46a7-adb9-9648def879c5","date":"2015-05-26T01:09:23Z","firstname":"null","lastname":"null"}
filter {
if [type] == 'EventLog' {
grok {
match => { 'message' => ' \{"casename":"%{WORD:casename}","username":"%{WORD:username}","startdate":"%{TIMESTAMP_ISO8601:startdate}","enddate":"%{TIMESTAMP_ISO8601:enddate}","time":"%{NUMBER:time}","methodname":"%{WORD:methodname}","url":"%{GREEDYDATA:url}","errortype":"%{WORD:errortype}","errorinfo":"%{WORD:errorinfo}","postdata":"%{GREEDYDATA:postdata}","methodtype":"%{WORD:methodtype}","servername":"%{HOST:servername}","gaggleid":"%{GREEDYDATA:gaggleid}","date":"%{TIMESTAMP_ISO8601:date}","firstname":"%{WORD:firstname}","lastname":"%{WORD:lastname}"\} '
}
}
}
}
"Fails from the beginning", indeed! See this?
'message' => ' \{"casename"
^^^
There's no initial (or trailing) space in your input, but you have them in your pattern. Remove them, and it works fine in logstash.
BTW, have you seen the json codec or filter?

Can I use gsub to recursively replace all fieldnames with another field?

After changing my mapping in ElasticSearch to more definitively type the data I am inputting into the system, I have unwittingly made my new variables a nested object. Upon thinking about it more, I actually like the idea of those fields being nested objects because that way I can explicitly know if that src_port statistic is from netflow or from the ASA logs, as an example.
I'd like to use a mutate (gsub, perhaps?) to cause all of my fieldnames for a given type to be renamed to newtype.fieldname. I see that there is gsub which uses a regexp, and rename which takes the literal field name, but I would like to prevent having 30 distinct gsub/rename statements when I will be replacing all of the fields in that type with the "newtype" prefix.
Is there a way to do this?
Here is an example for your reference.
input {
stdin{
type => 'netflow'
}
}
filter {
mutate {
add_field => {"%{type}.message" => "%{message}"}
remove_field => ["message"]
}
}
output {
stdout{
codec => rubydebug
}
}
In this example I have change the message field name to type.message, then delete the origin message field. I think you can use this sample to do what you want.
Hope this can help you.
I have updated my answer!
Use the ruby plugin to do what you want!
Please notice that elasticsearch uses #timestamp field to do index, so I recommend do not change the field name.
input {
stdin{
type => 'netflow'
}
}
filter {
ruby {
code => "
data = event.clone.to_hash;
type = event['type']
data.each do |k,v|
if k != '#timestamp'
newFieldName = type +'.'+ k
event[newFieldName] = v
event.remove(k)
end
end
"
}
}
output {
stdout{
codec => rubydebug
}
}

Resources