Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
including `http.response.elapsed_time` (ECS). {pull}10188[10188], {pull}10274[10274]
- Rename multiple fields to `http.response.body.bytes`, from modules "apache", "iis",
"kibana", "nginx" and "traefik", including `http.response.content_length` (ECS). {pull}10188[10188]
- Ingesting Elasticsearch audit logs is only supported with Elasticsearch 6.5.0 and above {pull}10352[10352]
- Migrate Elasticsearch audit logs fields to ECS {pull}10352[10352]

*Heartbeat*

Expand Down Expand Up @@ -177,6 +179,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
- Teach elasticsearch/audit fileset to parse out some more fields. {issue}10134[10134] {pull}10137[10137]
- Add convert_timezone to nginx module. {issue}9839[9839] {pull}10148[10148]
- Add support for Percona in the `slowlog` fileset of `mysql` module. {issue}6665[6665] {pull}10227[10227]
- Added support for ingesting structured Elasticsearch audit logs {pull}10352[10352]

*Heartbeat*

Expand Down
35 changes: 23 additions & 12 deletions filebeat/docs/fields.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -3911,6 +3911,17 @@ elasticsearch Module



*`elasticsearch.node.id`*::
+
--
type: keyword

example: DSiWcTyeThWtUXLB9J0BMw

ID of the node

--

*`elasticsearch.node.name`*::
+
--
Expand Down Expand Up @@ -3972,7 +3983,7 @@ The layer from which this event originated: rest, transport or ip_filter

--

*`elasticsearch.audit.origin_type`*::
*`elasticsearch.audit.origin.type`*::
+
--
type: keyword
Expand All @@ -3983,7 +3994,7 @@ Where the request originated: rest (request originated from a REST API request),

--

*`elasticsearch.audit.realm`*::
*`elasticsearch.audit.user.realm`*::
+
--
type: keyword
Expand All @@ -3992,7 +4003,7 @@ The authentication realm

--

*`elasticsearch.audit.roles`*::
*`elasticsearch.audit.user.roles`*::
+
--
type: keyword
Expand Down Expand Up @@ -4025,7 +4036,7 @@ Indices accessed by action

--

*`elasticsearch.audit.request`*::
*`elasticsearch.audit.request.name`*::
+
--
type: keyword
Expand All @@ -4036,39 +4047,39 @@ The type of request that was executed

--

*`elasticsearch.audit.event_type`*::
*`elasticsearch.audit.request_body`*::
+
--
type: alias

alias to: event.type
alias to: http.request.body.content

--

*`elasticsearch.audit.origin_address`*::
*`elasticsearch.audit.event_type`*::
+
--
type: alias

alias to: source.ip
alias to: event.type

--

*`elasticsearch.audit.uri`*::
*`elasticsearch.audit.origin_address`*::
+
--
type: alias

alias to: url.original
alias to: source.ip

--

*`elasticsearch.audit.request_body`*::
*`elasticsearch.audit.uri`*::
+
--
type: alias

alias to: http.request.body.content
alias to: url.original

--

Expand Down
4 changes: 4 additions & 0 deletions filebeat/module/elasticsearch/_meta/fields.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
type: group
description: >
fields:
- name: node.id
description: "ID of the node"
example: "DSiWcTyeThWtUXLB9J0BMw"
type: keyword
- name: node.name
description: "Name of the node"
example: "vWNJsZ3"
Expand Down
16 changes: 8 additions & 8 deletions filebeat/module/elasticsearch/audit/_meta/fields.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
description: "The layer from which this event originated: rest, transport or ip_filter"
example: "rest"
type: keyword
- name: origin_type
- name: origin.type
description: "Where the request originated: rest (request originated from a REST API request), transport (request was received on the transport channel), local_node (the local node issued the request)"
example: "local_node"
type: keyword
- name: realm
- name: user.realm
description: "The authentication realm"
example": "active_directory"
type: keyword
- name: roles
- name: user.roles
description: "Roles to which the principal belongs"
example: [ "kibana_user", "beats_admin" ]
type: keyword
Expand All @@ -26,10 +26,14 @@
description: "Indices accessed by action"
example: [ "foo-2019.01.04", "foo-2019.01.03", "foo-2019.01.06" ]
type: keyword
- name: request
- name: request.name
description: "The type of request that was executed"
example: "ClearScrollRequest"
type: keyword
- name: request_body
type: alias
path: http.request.body.content
migration: true
- name: event_type
type: alias
path: event.type
Expand All @@ -42,10 +46,6 @@
type: alias
path: url.original
migration: true
- name: request_body
type: alias
path: http.request.body.content
migration: true
- name: principal
type: alias
path: user.name
Expand Down
132 changes: 132 additions & 0 deletions filebeat/module/elasticsearch/audit/ingest/pipeline-json.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
{
"description": "Pipeline for parsing elasticsearch audit logs in JSON format",
"processors": [
{
"json": {
"field": "message",
"target_field": "elasticsearch.audit"
}
},
{
"dot_expander": {
"field": "event.action",
"path": "elasticsearch.audit"
}
},
{
"rename": {
"field": "elasticsearch.audit.event.action",
"target_field": "event.action"
}
},
{
"dot_expander": {
"field": "event.type",
"path": "elasticsearch.audit"
}
},
{
"rename": {
"field": "elasticsearch.audit.event.type",
"target_field": "elasticsearch.audit.layer"
}
},
{
"dot_expander": {
"field": "origin.address",
Copy link
Contributor

Choose a reason for hiding this comment

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

I would instead rename this field to source.address (and keep it around).

"path": "elasticsearch.audit"
}
},
{
"grok": {
"field": "elasticsearch.audit.origin.address",
"patterns": [
"\\[%{IPORHOST:source.ip}\\]:%{INT:source.port:int}",
"%{IPORHOST:source.ip}:%{INT:source.port:int}"
]
}
},
{
"rename": {
"field": "elasticsearch.audit.origin.address",
"target_field": "source.address"
}
},
{
"dot_expander": {
"field": "url.path",
"path": "elasticsearch.audit"
}
},
{
"dot_expander": {
"field": "url.query",
"path": "elasticsearch.audit"
}
},
{
"set": {
"if": "ctx.elasticsearch.audit?.url?.path != null && ctx.elasticsearch.audit?.url?.query == null",
"field": "url.original",
"value": "{{elasticsearch.audit.url.path}}"
}
},
{
"set": {
"if": "ctx.elasticsearch.audit?.url?.path != null && ctx.elasticsearch.audit?.url?.query != null",
"field": "url.original",
"value": "{{elasticsearch.audit.url.path}}?{{elasticsearch.audit.url.query}}"
}
},
{
"remove": {
"if": "ctx.elasticsearch.audit?.url?.path != null",
"field": "elasticsearch.audit.url.path"
}
},
{
"remove": {
"if": "ctx.elasticsearch.audit?.url?.query != null",
"field": "elasticsearch.audit.url.query"
}
},
{
"dot_expander": {
"field": "node.id",
"path": "elasticsearch.audit"
}
},
{
"dot_expander": {
"field": "node.name",
"path": "elasticsearch.audit"
}
},
{
"rename": {
"field": "elasticsearch.audit.node",
"target_field": "elasticsearch.node"
}
},
{
"dot_expander": {
"field": "user.name",
"path": "elasticsearch.audit"
}
},
{
"rename": {
"field": "elasticsearch.audit.user.name",
"target_field": "user.name"
Copy link
Contributor

Choose a reason for hiding this comment

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

Can't we dot_expand in place? If the original key is "user.name", I would think that the output to "user": { "name": "..." } doesn't conflict.

It would simplify the code in a few places where you have the same pattern happening.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure I follow what you mean by doing "dot_expand in place"? The dot_expander processor right above this one is necessary to go from:

{
  "elasticsearch.audit.user.name": "foo"
}

to:

{
  "elasticsearch.audit.user": {
    "name": "foo"
  }
}

That then allows us to call the rename processor as we are doing over here.

Copy link
Contributor

Choose a reason for hiding this comment

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

I haven't used dot_expander yet, so perhaps I'm misunderstanding it. But I was under the impression that the following did the equivalent of the 2 processors above:

{ "dot_expander": { "field": "user.name" } }

And in cases where the output isn't the object equivalent of the dotted notation, you would use path this way, to get the equivalent of the two node.name processors above:

{ "dot_expander": { "field": "node.name", "path": "elasticsearch.node" } }

If that's not the case, you can ignore this ;-)

}
}
],
"on_failure": [
{
"set": {
"field": "error.message",
"value": "{{ _ingest.on_failure_message }}"
}
}
]
}
63 changes: 63 additions & 0 deletions filebeat/module/elasticsearch/audit/ingest/pipeline-plaintext.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"description": "Pipeline for parsing elasticsearch audit logs in plaintext format",
"processors": [
{
"grok": {
"field": "message",
"pattern_definitions": {
"ES_TIMESTAMP": "\\[%{TIMESTAMP_ISO8601:elasticsearch.audit.@timestamp}\\]",
"ES_NODE_NAME": "(\\[%{DATA:elasticsearch.node.name}\\])?",
"ES_AUDIT_LAYER": "\\[%{WORD:elasticsearch.audit.layer}\\]",
"ES_AUDIT_EVENT_TYPE": "\\[%{WORD:event.type}\\]",
"ES_AUDIT_ORIGIN_TYPE": "(origin_type\\=\\[%{WORD:elasticsearch.audit.origin.type}\\])?",
"ES_AUDIT_ORIGIN_ADDRESS": "(origin_address\\=\\[%{IPORHOST:source.ip}\\])?",
"ES_AUDIT_PRINCIPAL": "(principal\\=\\[%{WORD:user.name}\\])?",
"ES_AUDIT_REALM": "(realm\\=\\[%{WORD:elasticsearch.audit.user.realm}\\])?",
"ES_AUDIT_ROLES": "(roles\\=\\[%{DATA:elasticsearch.audit.user.roles}\\])?",
"ES_AUDIT_ACTION": "(action\\=\\[%{DATA:elasticsearch.audit.action}(\\[%{DATA:elasticsearch.audit.sub_action}\\])?\\])?",
"ES_AUDIT_URI": "(uri=\\[%{DATA:url.original}\\])?",
"ES_AUDIT_INDICES": "(indices\\=\\[%{DATA:elasticsearch.audit.indices}\\])?",
"ES_AUDIT_REQUEST": "(request\\=\\[%{WORD:elasticsearch.audit.request.name}\\])?",
"ES_AUDIT_REQUEST_BODY": "(request_body\\=\\[%{DATA:http.request.body.content}\\])?"
},
"patterns": [
"%{ES_TIMESTAMP}\\s*%{ES_NODE_NAME}\\s*%{ES_AUDIT_LAYER}\\s*%{ES_AUDIT_EVENT_TYPE}\\s*%{ES_AUDIT_ORIGIN_TYPE},?\\s*%{ES_AUDIT_ORIGIN_ADDRESS},?\\s*%{ES_AUDIT_PRINCIPAL},?\\s*%{ES_AUDIT_REALM},?\\s*%{ES_AUDIT_ROLES},?\\s*%{ES_AUDIT_ACTION},?\\s*%{ES_AUDIT_INDICES},?\\s*%{ES_AUDIT_URI},?\\s*%{ES_AUDIT_REQUEST},?\\s*%{ES_AUDIT_REQUEST_BODY},?"
]
}
},
{
"split": {
"field": "elasticsearch.audit.user.roles",
"separator": ",",
"ignore_missing": true
}
},
{
"split": {
"field": "elasticsearch.audit.indices",
"separator": ",",
"ignore_missing": true
}
},
{
"script": {
"lang": "painless",
"source": "if (ctx.elasticsearch.audit.sub_action != null) { ctx.elasticsearch.audit.action += '[' + ctx.elasticsearch.audit.sub_action + ']' }"
}
},
{
"remove": {
"field": "elasticsearch.audit.sub_action",
"ignore_missing": true
}
}
],
"on_failure": [
{
"set": {
"field": "error.message",
"value": "{{ _ingest.on_failure_message }}"
}
}
]
}
Loading