Skip to content

Commit

Permalink
Parameterizing Painless script literals (#9770)
Browse files Browse the repository at this point in the history
* Parameterizing some script literals

* Fixing script property name

* Fixing syntax error

* Reverting nginx change

* Reverting auditd pipeline change (for now)

* Work around painless limitation

* Working around Painless issue for nginx module ingest pipeline

* Parameterizing one more script in redis module ingest pipeline

* Adding back lang field to explicitly set script language to Painless

* Reformatting nginx access log

* Fixing indent
  • Loading branch information
ycombinator authored Dec 28, 2018
1 parent 3559e58 commit 2c6030d
Show file tree
Hide file tree
Showing 3 changed files with 222 additions and 160 deletions.
8 changes: 6 additions & 2 deletions filebeat/module/auditd/log/ingest/pipeline.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,19 @@
},
{
"convert": {
"field" : "auditd.log.sequence",
"field": "auditd.log.sequence",
"type": "integer",
"ignore_missing": true
}
},
{
"script": {
"lang": "painless",
"inline": " String trimQuotes(def v) {\n if (v.startsWith(\"'\") || v.startsWith('\"')) {\n v = v.substring(1, v.length());\n }\n if (v.endsWith(\"'\") || v.endsWith('\"')) {\n v = v.substring(0, v.length()-1);\n } \n return v;\n }\n \n boolean isHexAscii(String v) {\n def len = v.length();\n if (len == 0 || len % 2 != 0) {\n return false; \n }\n \n for (int i = 0 ; i < len ; i++) {\n if (Character.digit(v.charAt(i), 16) == -1) {\n return false;\n }\n }\n\n return true;\n }\n \n String convertHexToString(String hex) {\n\t StringBuilder sb = new StringBuilder();\n\n for (int i=0; i < hex.length() - 1; i+=2) {\n String output = hex.substring(i, (i + 2));\n int decimal = Integer.parseInt(output, 16);\n sb.append((char)decimal);\n }\n\n return sb.toString();\n }\n \n def possibleHexKeys = ['exe', 'cmd'];\n \n def audit = ctx.auditd.get(\"log\");\n Iterator entries = audit.entrySet().iterator();\n while (entries.hasNext()) {\n def e = entries.next();\n def k = e.getKey();\n def v = e.getValue(); \n\n // Remove entries whose value is ?\n if (v == \"?\" || v == \"(null)\" || v == \"\") {\n entries.remove();\n continue;\n }\n \n // Convert hex values to ASCII.\n if (possibleHexKeys.contains(k) && isHexAscii(v)) {\n v = convertHexToString(v);\n audit.put(k, v);\n }\n \n // Trim quotes.\n if (v instanceof String) {\n v = trimQuotes(v);\n audit.put(k, v);\n }\n \n // Convert arch.\n if (k == \"arch\" && v == \"c000003e\") {\n audit.put(k, \"x86_64\");\n }\n }"
"source": " String trimQuotes(def singleQuote, def doubleQuote, def v) {\n if (v.startsWith(singleQuote) || v.startsWith(doubleQuote)) {\n v = v.substring(1, v.length());\n }\n if (v.endsWith(singleQuote) || v.endsWith(doubleQuote)) {\n v = v.substring(0, v.length()-1);\n } \n return v;\n }\n \n boolean isHexAscii(String v) {\n def len = v.length();\n if (len == 0 || len % 2 != 0) {\n return false; \n }\n \n for (int i = 0 ; i < len ; i++) {\n if (Character.digit(v.charAt(i), 16) == -1) {\n return false;\n }\n }\n\n return true;\n }\n \n String convertHexToString(String hex) {\n\t StringBuilder sb = new StringBuilder();\n\n for (int i=0; i < hex.length() - 1; i+=2) {\n String output = hex.substring(i, (i + 2));\n int decimal = Integer.parseInt(output, 16);\n sb.append((char)decimal);\n }\n\n return sb.toString();\n }\n \n def possibleHexKeys = ['exe', 'cmd'];\n \n def audit = ctx.auditd.get(\"log\");\n Iterator entries = audit.entrySet().iterator();\n while (entries.hasNext()) {\n def e = entries.next();\n def k = e.getKey();\n def v = e.getValue(); \n\n // Remove entries whose value is ?\n if (v == \"?\" || v == \"(null)\" || v == \"\") {\n entries.remove();\n continue;\n }\n \n // Convert hex values to ASCII.\n if (possibleHexKeys.contains(k) && isHexAscii(v)) {\n v = convertHexToString(v);\n audit.put(k, v);\n }\n \n // Trim quotes.\n if (v instanceof String) {\n v = trimQuotes(params.single_quote, params.double_quote, v);\n audit.put(k, v);\n }\n \n // Convert arch.\n if (k == \"arch\" && v == \"c000003e\") {\n audit.put(k, \"x86_64\");\n }\n }",
"params": {
"single_quote": "'",
"double_quote": "\""
}
}
},
{
Expand Down
247 changes: 137 additions & 110 deletions filebeat/module/nginx/access/ingest/default.json
Original file line number Diff line number Diff line change
@@ -1,112 +1,139 @@
{
"description": "Pipeline for parsing Nginx access logs. Requires the geoip and user_agent plugins.",
"processors": [{
"grok": {
"field": "message",
"patterns":[
"\"?%{IP_LIST:network.forwarded_ip} - %{DATA:user.name} \\[%{HTTPDATE:nginx.access.time}\\] \"%{GREEDYDATA:nginx.access.info}\" %{NUMBER:http.response.status_code:long} %{NUMBER:nginx.access.body_sent.bytes:long} \"%{DATA:http.request.referrer}\" \"%{DATA:nginx.access.agent}\""
],
"pattern_definitions": {
"IP_LIST": "%{IP}(\"?,?\\s*%{IP})*"
},
"ignore_missing": true
}
}, {
"grok": {
"field": "nginx.access.info",
"patterns": [
"%{WORD:http.request.method} %{DATA:url.original} HTTP/%{NUMBER:http.version}",
""
],
"ignore_missing": true
}
}, {
"remove": {
"field": "nginx.access.info"
}
}, {
"split": {
"field": "network.forwarded_ip",
"separator": "\"?,?\\s+"
}
}, {
"set": {
"field": "source.ip",
"value": ""
}
}, {
"script": {
"lang": "painless",
"inline": "boolean isPrivate(def ip) { try { StringTokenizer tok = new StringTokenizer(ip, '.'); int firstByte = Integer.parseInt(tok.nextToken()); int secondByte = Integer.parseInt(tok.nextToken()); if (firstByte == 10) { return true; } if (firstByte == 192 && secondByte == 168) { return true; } if (firstByte == 172 && secondByte >= 16 && secondByte <= 31) { return true; } if (firstByte == 127) { return true; } return false; } catch (Exception e) { return false; } } def found = false; for (def item : ctx.network.forwarded_ip) { if (!isPrivate(item)) { ctx.source.ip = item; found = true; break; } } if (!found) { ctx.source.ip = ctx.network.forwarded_ip[0]; }"
}
}, {
"remove":{
"field": "message"
}
}, {
"rename": {
"field": "@timestamp",
"target_field": "read_timestamp"
}
}, {
"date": {
"field": "nginx.access.time",
"target_field": "@timestamp",
"formats": ["dd/MMM/YYYY:H:m:s Z"]
}
}, {
"remove": {
"field": "nginx.access.time"
}

}, { "user_agent": { "field": "nginx.access.agent" }
}, {
"rename": {
"field": "nginx.access.agent",
"target_field": "user_agent.original"
}
}, {
"rename": {
"field": "user_agent.os",
"target_field": "user_agent.os.full_name",
"ignore_missing": true
}
}, {
"rename": {
"field": "user_agent.os_name",
"target_field": "user_agent.os.name",
"ignore_missing": true
}
}, {
"rename": {
"field": "user_agent.os_major",
"target_field": "user_agent.os.major",
"ignore_missing": true
}
}, {
"rename": {
"field": "user_agent.os_minor",
"target_field": "user_agent.os.minor",
"ignore_missing": true
}
}, {
"rename": {
"field": "user_agent.os_patch",
"target_field": "user_agent.os.patch",
"ignore_missing": true
}

},{
"geoip": {
"field": "source.ip",
"target_field": "source.geo",
"ignore_missing": true
}
}],
"on_failure" : [{
"set" : {
"field" : "error.message",
"value" : "{{ _ingest.on_failure_message }}"
}
}]
"description": "Pipeline for parsing Nginx access logs. Requires the geoip and user_agent plugins.",
"processors": [
{
"grok": {
"field": "message",
"patterns": [
"\"?%{IP_LIST:network.forwarded_ip} - %{DATA:user.name} \\[%{HTTPDATE:nginx.access.time}\\] \"%{GREEDYDATA:nginx.access.info}\" %{NUMBER:http.response.status_code:long} %{NUMBER:nginx.access.body_sent.bytes:long} \"%{DATA:http.request.referrer}\" \"%{DATA:nginx.access.agent}\""
],
"pattern_definitions": {
"IP_LIST": "%{IP}(\"?,?\\s*%{IP})*"
},
"ignore_missing": true
}
},
{
"grok": {
"field": "nginx.access.info",
"patterns": [
"%{WORD:http.request.method} %{DATA:url.original} HTTP/%{NUMBER:http.version}",
""
],
"ignore_missing": true
}
},
{
"remove": {
"field": "nginx.access.info"
}
},
{
"split": {
"field": "network.forwarded_ip",
"separator": "\"?,?\\s+"
}
},
{
"set": {
"field": "source.ip",
"value": ""
}
},
{
"script": {
"lang": "painless",
"source": "boolean isPrivate(def dot, def ip) { try { StringTokenizer tok = new StringTokenizer(ip, dot); int firstByte = Integer.parseInt(tok.nextToken()); int secondByte = Integer.parseInt(tok.nextToken()); if (firstByte == 10) { return true; } if (firstByte == 192 && secondByte == 168) { return true; } if (firstByte == 172 && secondByte >= 16 && secondByte <= 31) { return true; } if (firstByte == 127) { return true; } return false; } catch (Exception e) { return false; } } def found = false; for (def item : ctx.network.forwarded_ip) { if (!isPrivate(params.dot, item)) { ctx.source.ip = item; found = true; break; } } if (!found) { ctx.source.ip = ctx.network.forwarded_ip[0]; }",
"params": {
"dot": "."
}
}
},
{
"remove": {
"field": "message"
}
},
{
"rename": {
"field": "@timestamp",
"target_field": "read_timestamp"
}
},
{
"date": {
"field": "nginx.access.time",
"target_field": "@timestamp",
"formats": [
"dd/MMM/YYYY:H:m:s Z"
]
}
},
{
"remove": {
"field": "nginx.access.time"
}
},
{
"user_agent": {
"field": "nginx.access.agent"
}
},
{
"rename": {
"field": "nginx.access.agent",
"target_field": "user_agent.original"
}
},
{
"rename": {
"field": "user_agent.os",
"target_field": "user_agent.os.full_name",
"ignore_missing": true
}
},
{
"rename": {
"field": "user_agent.os_name",
"target_field": "user_agent.os.name",
"ignore_missing": true
}
},
{
"rename": {
"field": "user_agent.os_major",
"target_field": "user_agent.os.major",
"ignore_missing": true
}
},
{
"rename": {
"field": "user_agent.os_minor",
"target_field": "user_agent.os.minor",
"ignore_missing": true
}
},
{
"rename": {
"field": "user_agent.os_patch",
"target_field": "user_agent.os.patch",
"ignore_missing": true
}
},
{
"geoip": {
"field": "source.ip",
"target_field": "source.geo",
"ignore_missing": true
}
}
],
"on_failure": [
{
"set": {
"field": "error.message",
"value": "{{ _ingest.on_failure_message }}"
}
}
]
}
Loading

0 comments on commit 2c6030d

Please sign in to comment.