diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b934f13eb62..a371c9535eb 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -168,3 +168,4 @@ /packages/zscaler @elastic/security-external-integrations /packages/zscaler_zia @elastic/security-external-integrations /packages/zscaler_zpa @elastic/security-external-integrations +/packages/platform_observability @elastic/infra-monitoring-ui diff --git a/packages/platform_observability/_dev/build/build.yml b/packages/platform_observability/_dev/build/build.yml new file mode 100644 index 00000000000..5661d603a89 --- /dev/null +++ b/packages/platform_observability/_dev/build/build.yml @@ -0,0 +1,3 @@ +dependencies: + ecs: + reference: git@v8.3.0 diff --git a/packages/platform_observability/_dev/build/docs/README.md b/packages/platform_observability/_dev/build/docs/README.md new file mode 100644 index 00000000000..036ddc400d8 --- /dev/null +++ b/packages/platform_observability/_dev/build/docs/README.md @@ -0,0 +1,27 @@ +# Platform Observability + +## Compatibility + +This package works with Kibana 8.3.0 and later. + +## Kibana logs + +The Kibana integration collects logs from [Kibana](https://www.elastic.co/guide/en/kibana/current/introduction.html) instance. + +### Logs + +#### Audit + +Audit logs collects the [Kibana audit logs](https://www.elastic.co/guide/en/kibana/current/security-settings-kb.html). + +{{event "kibana_audit"}} + +{{fields "kibana_audit"}} + +#### Log + +Log collects the [Kibana logs](https://www.elastic.co/guide/en/kibana/current/logging-configuration.html). + +{{event "kibana_log"}} + +{{fields "kibana_log"}} diff --git a/packages/platform_observability/changelog.yml b/packages/platform_observability/changelog.yml new file mode 100644 index 00000000000..1a514de9064 --- /dev/null +++ b/packages/platform_observability/changelog.yml @@ -0,0 +1,6 @@ +# newer versions go on top +- version: "0.0.1" + changes: + - description: Initial draft of the package + type: enhancement + link: https://github.com/elastic/integrations/pull/3622 diff --git a/packages/platform_observability/data_stream/kibana_audit/_dev/test/pipeline/test-common-config.yml b/packages/platform_observability/data_stream/kibana_audit/_dev/test/pipeline/test-common-config.yml new file mode 100644 index 00000000000..c39dc386179 --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_audit/_dev/test/pipeline/test-common-config.yml @@ -0,0 +1,2 @@ +dynamic_fields: + event.ingested: ".*" diff --git a/packages/platform_observability/data_stream/kibana_audit/_dev/test/pipeline/test-kibana-audit-logs.log b/packages/platform_observability/data_stream/kibana_audit/_dev/test/pipeline/test-kibana-audit-logs.log new file mode 100644 index 00000000000..ed7cd51a51b --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_audit/_dev/test/pipeline/test-kibana-audit-logs.log @@ -0,0 +1 @@ +{"event":{"action":"http_request","category":["web"],"outcome":"unknown"},"http":{"request":{"method":"get"}},"url":{"domain":"localhost","path":"/internal/security/session","port":5601,"scheme":"http"},"user":{"name":"elastic","roles":["superuser"]},"kibana":{"space_id":"default","session_id":"ccZ0sbxrmmJwo+/y2Mn1tmGIrKOuZYaF8voUh0SkA/k="},"trace":{"id":"1c8c5808-d2d6-41fc-8cb7-998aa8996be9"},"ecs":{"version":"8.0.0"},"@timestamp":"2022-06-29T12:05:03.742+00:00","message":"User is requesting [/internal/security/session] endpoint","log":{"level":"INFO","logger":"plugins.security.audit.ecs"},"process":{"pid":7},"transaction":{"id":"f8863d86567119e6"}} \ No newline at end of file diff --git a/packages/platform_observability/data_stream/kibana_audit/_dev/test/pipeline/test-kibana-audit-logs.log-expected.json b/packages/platform_observability/data_stream/kibana_audit/_dev/test/pipeline/test-kibana-audit-logs.log-expected.json new file mode 100644 index 00000000000..b5f9281a2f1 --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_audit/_dev/test/pipeline/test-kibana-audit-logs.log-expected.json @@ -0,0 +1,60 @@ +{ + "expected": [ + { + "@timestamp": "2022-06-29T12:05:03.742+00:00", + "data_stream": { + "dataset": "kibana-audit-log", + "namespace": "platform-observability", + "type": "logs" + }, + "ecs": { + "version": "8.0.0" + }, + "event": { + "action": "http_request", + "category": [ + "web" + ], + "dataset": "kibana-audit-log", + "ingested": "2022-07-20T08:36:57.202942842Z", + "kind": "event", + "outcome": "unknown" + }, + "http": { + "request": { + "method": "get" + } + }, + "kibana": { + "session_id": "ccZ0sbxrmmJwo+/y2Mn1tmGIrKOuZYaF8voUh0SkA/k=", + "space_id": "default" + }, + "log": { + "level": "INFO", + "logger": "plugins.security.audit.ecs" + }, + "message": "User is requesting [/internal/security/session] endpoint", + "process": { + "pid": 7 + }, + "trace": { + "id": "1c8c5808-d2d6-41fc-8cb7-998aa8996be9" + }, + "transaction": { + "id": "f8863d86567119e6" + }, + "url": { + "domain": "localhost", + "path": "/internal/security/session", + "port": 5601, + "scheme": "http" + }, + "user": { + "name": "elastic", + "roles": [ + "superuser" + ] + } + } + ] +} \ No newline at end of file diff --git a/packages/platform_observability/data_stream/kibana_audit/agent/stream/log.yml.hbs b/packages/platform_observability/data_stream/kibana_audit/agent/stream/log.yml.hbs new file mode 100644 index 00000000000..5042f840763 --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_audit/agent/stream/log.yml.hbs @@ -0,0 +1,8 @@ +paths: +{{#each paths}} + - {{this}} +{{/each}} +{{#if processors}} +processors: +{{processors}} +{{/if}} \ No newline at end of file diff --git a/packages/platform_observability/data_stream/kibana_audit/elasticsearch/ingest_pipeline/default.yml b/packages/platform_observability/data_stream/kibana_audit/elasticsearch/ingest_pipeline/default.yml new file mode 100644 index 00000000000..45755cf29fa --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_audit/elasticsearch/ingest_pipeline/default.yml @@ -0,0 +1,33 @@ +--- +description: Pipeline for parsing Kibana Audit ECS formatted logs +processors: + - pipeline: + name: '{{ IngestPipeline "ecs-logs-pipeline" }}' + if: |- + def message = ctx.message; + return message != null + && message.startsWith('{') + && message.endsWith('}') + && message.contains('"@timestamp"') + - set: + field: data_stream.type + value: logs + - set: + field: data_stream.dataset + value: kibana-audit-log + - set: + field: data_stream.namespace + value: platform-observability + - set: + field: event.dataset + copy_from: data_stream.dataset + - set: + field: event.ingested + value: "{{_ingest.timestamp}}" + - set: + field: event.kind + value: event +on_failure: + - set: + field: error.message + value: "{{ _ingest.on_failure_message }}" diff --git a/packages/platform_observability/data_stream/kibana_audit/elasticsearch/ingest_pipeline/ecs-logs-pipeline.yml b/packages/platform_observability/data_stream/kibana_audit/elasticsearch/ingest_pipeline/ecs-logs-pipeline.yml new file mode 100644 index 00000000000..16db6d98a0f --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_audit/elasticsearch/ingest_pipeline/ecs-logs-pipeline.yml @@ -0,0 +1,31 @@ +--- +processors: + - rename: + field: message + target_field: _ecs_json_message + ignore_missing: true + - json: + field: _ecs_json_message + add_to_root: true + add_to_root_conflict_strategy: merge + allow_duplicate_keys: true + if: ctx.containsKey('_ecs_json_message') + on_failure: + - rename: + field: _ecs_json_message + target_field: message + ignore_missing: true + - set: + field: error.message + value: Error while parsing JSON + override: false + - remove: + field: _ecs_json_message + ignore_missing: true + - dot_expander: + field: "*" + override: true + - join: + field: error.stack_trace + separator: "\n" + if: ctx.error?.stack_trace instanceof Collection diff --git a/packages/platform_observability/data_stream/kibana_audit/fields/base-fields.yml b/packages/platform_observability/data_stream/kibana_audit/fields/base-fields.yml new file mode 100644 index 00000000000..0d1791ffed6 --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_audit/fields/base-fields.yml @@ -0,0 +1,12 @@ +- name: data_stream.type + type: constant_keyword + description: Data stream type. +- name: data_stream.dataset + type: constant_keyword + description: Data stream dataset. +- name: data_stream.namespace + type: constant_keyword + description: Data stream namespace. +- name: "@timestamp" + type: date + description: Event timestamp. diff --git a/packages/platform_observability/data_stream/kibana_audit/fields/ecs.yml b/packages/platform_observability/data_stream/kibana_audit/fields/ecs.yml new file mode 100644 index 00000000000..88a28b751bb --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_audit/fields/ecs.yml @@ -0,0 +1,42 @@ +- name: ecs.version + external: ecs +- name: event.action + external: ecs +- name: event.category + external: ecs +- name: event.dataset + external: ecs +- name: event.kind + external: ecs +- name: event.ingested + external: ecs +- name: event.outcome + external: ecs +- name: http.request.method + external: ecs +- name: log.level + external: ecs +- name: log.logger + external: ecs +- name: message + external: ecs +- name: process.pid + external: ecs +- name: trace.id + external: ecs +- name: transaction.id + external: ecs +- name: url.domain + external: ecs +- name: url.path + external: ecs +- name: url.port + external: ecs +- name: url.query + external: ecs +- name: url.scheme + external: ecs +- name: user.name + external: ecs +- name: user.roles + external: ecs diff --git a/packages/platform_observability/data_stream/kibana_audit/fields/package-fields.yml b/packages/platform_observability/data_stream/kibana_audit/fields/package-fields.yml new file mode 100644 index 00000000000..8099b58debb --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_audit/fields/package-fields.yml @@ -0,0 +1,33 @@ +- name: kibana + type: group + fields: + - name: session_id + type: keyword + description: The ID of the user session associated with this event. Each login attempt results in a unique session id. + - name: space_id + type: keyword + description: The id of the space associated with this event. + - name: saved_object.type + type: keyword + description: The type of the saved object associated with this event. + - name: saved_object.id + type: keyword + description: The id of the saved object associated with this event. + - name: add_to_spaces + type: keyword + description: The set of space ids that a saved object was shared to. + - name: delete_from_spaces + type: keyword + description: The set of space ids that a saved object was removed from. + - name: authentication_provider + type: keyword + description: The authentication provider associated with a login event. + - name: authentication_type + type: keyword + description: The authentication provider type associated with a login event. + - name: authentication_realm + type: keyword + description: The Elasticsearch authentication realm name which fulfilled a login event. + - name: lookup_realm + type: keyword + description: The Elasticsearch lookup realm which fulfilled a login event. diff --git a/packages/platform_observability/data_stream/kibana_audit/manifest.yml b/packages/platform_observability/data_stream/kibana_audit/manifest.yml new file mode 100644 index 00000000000..31c7cf1655d --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_audit/manifest.yml @@ -0,0 +1,16 @@ +type: logs +title: Platform Observability Kibana audit logs +streams: + - input: logfile + vars: + - name: paths + type: text + title: Paths + multi: true + required: true + show_user: true + default: + - /var/log/kibana/*_audit.json + template_path: log.yml.hbs + title: Kibana audit logs + description: Collect Kibana audit logs diff --git a/packages/platform_observability/data_stream/kibana_audit/sample_event.json b/packages/platform_observability/data_stream/kibana_audit/sample_event.json new file mode 100644 index 00000000000..83e716705d4 --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_audit/sample_event.json @@ -0,0 +1,48 @@ +{ + "event": { + "action": "http_request", + "category": [ + "web" + ], + "outcome": "unknown" + }, + "http": { + "request": { + "method": "get" + } + }, + "url": { + "domain": "localhost", + "path": "/internal/security/session", + "port": 5601, + "scheme": "http" + }, + "user": { + "name": "elastic", + "roles": [ + "superuser" + ] + }, + "kibana": { + "space_id": "default", + "session_id": "ccZ0sbxrmmJwo+/y2Mn1tmGIrKOuZYaF8voUh0SkA/k=" + }, + "trace": { + "id": "1c8c5808-d2d6-41fc-8cb7-998aa8996be9" + }, + "ecs": { + "version": "8.0.0" + }, + "@timestamp": "2022-06-29T12:05:03.742+00:00", + "message": "User is requesting [/internal/security/session] endpoint", + "log": { + "level": "INFO", + "logger": "plugins.security.audit.ecs" + }, + "process": { + "pid": 7 + }, + "transaction": { + "id": "f8863d86567119e6" + } +} \ No newline at end of file diff --git a/packages/platform_observability/data_stream/kibana_log/_dev/test/pipeline/test-common-config.yml b/packages/platform_observability/data_stream/kibana_log/_dev/test/pipeline/test-common-config.yml new file mode 100644 index 00000000000..c39dc386179 --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_log/_dev/test/pipeline/test-common-config.yml @@ -0,0 +1,2 @@ +dynamic_fields: + event.ingested: ".*" diff --git a/packages/platform_observability/data_stream/kibana_log/_dev/test/pipeline/test-kibana-logs.log b/packages/platform_observability/data_stream/kibana_log/_dev/test/pipeline/test-kibana-logs.log new file mode 100644 index 00000000000..3a1f92f7649 --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_log/_dev/test/pipeline/test-kibana-logs.log @@ -0,0 +1,2 @@ +{"ecs":{"version":"8.0.0"},"@timestamp":"2022-06-29T11:24:17.898+00:00","message":"Trying to authenticate user request to /login.","log":{"level":"DEBUG","logger":"plugins.security.http"},"process":{"pid":7},"trace":{"id":"e6e1c25936546ec690b11a3b78b2a8db"},"transaction":{"id":"3be6994d7f6d5465"}} +{"http":{"request":{"id":"unknownId","method":"GET"},"response":{"body":{"bytes":118},"status_code":200}},"url":{"path":"/_nodes","query":"filter_path=nodes.*.version%2Cnodes.*.http.publish_address%2Cnodes.*.ip"},"ecs":{"version":"8.0.0"},"@timestamp":"2022-07-14T10:35:25.366+00:00","message":"200 - 118.0B\nGET /_nodes?filter_path=nodes.*.version%2Cnodes.*.http.publish_address%2Cnodes.*.ip","log":{"level":"DEBUG","logger":"elasticsearch.query.data"},"process":{"pid":7},"trace":{"id":"0cd8dd5a3483159a43c07e9205432775"},"transaction":{"id":"6301eca88fba8d99"}} \ No newline at end of file diff --git a/packages/platform_observability/data_stream/kibana_log/_dev/test/pipeline/test-kibana-logs.log-expected.json b/packages/platform_observability/data_stream/kibana_log/_dev/test/pipeline/test-kibana-logs.log-expected.json new file mode 100644 index 00000000000..a341db9656d --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_log/_dev/test/pipeline/test-kibana-logs.log-expected.json @@ -0,0 +1,81 @@ +{ + "expected": [ + { + "@timestamp": "2022-06-29T11:24:17.898+00:00", + "data_stream": { + "dataset": "kibana-logs", + "namespace": "platform-observability", + "type": "logs" + }, + "ecs": { + "version": "8.0.0" + }, + "event": { + "dataset": "kibana-logs", + "ingested": "2022-07-20T08:36:57.436382217Z", + "kind": "event" + }, + "log": { + "level": "DEBUG", + "logger": "plugins.security.http" + }, + "message": "Trying to authenticate user request to /login.", + "process": { + "pid": 7 + }, + "trace": { + "id": "e6e1c25936546ec690b11a3b78b2a8db" + }, + "transaction": { + "id": "3be6994d7f6d5465" + } + }, + { + "@timestamp": "2022-07-14T10:35:25.366+00:00", + "data_stream": { + "dataset": "kibana-logs", + "namespace": "platform-observability", + "type": "logs" + }, + "ecs": { + "version": "8.0.0" + }, + "event": { + "dataset": "kibana-logs", + "ingested": "2022-07-20T08:36:57.436384342Z", + "kind": "event", + "outcome": "success" + }, + "http": { + "request": { + "id": "unknownId", + "method": "GET" + }, + "response": { + "body": { + "bytes": 118 + }, + "status_code": 200 + } + }, + "log": { + "level": "DEBUG", + "logger": "elasticsearch.query.data" + }, + "message": "200 - 118.0B\nGET /_nodes?filter_path=nodes.*.version%2Cnodes.*.http.publish_address%2Cnodes.*.ip", + "process": { + "pid": 7 + }, + "trace": { + "id": "0cd8dd5a3483159a43c07e9205432775" + }, + "transaction": { + "id": "6301eca88fba8d99" + }, + "url": { + "path": "/_nodes", + "query": "filter_path=nodes.*.version%2Cnodes.*.http.publish_address%2Cnodes.*.ip" + } + } + ] +} \ No newline at end of file diff --git a/packages/platform_observability/data_stream/kibana_log/agent/stream/log.yml.hbs b/packages/platform_observability/data_stream/kibana_log/agent/stream/log.yml.hbs new file mode 100644 index 00000000000..5042f840763 --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_log/agent/stream/log.yml.hbs @@ -0,0 +1,8 @@ +paths: +{{#each paths}} + - {{this}} +{{/each}} +{{#if processors}} +processors: +{{processors}} +{{/if}} \ No newline at end of file diff --git a/packages/platform_observability/data_stream/kibana_log/elasticsearch/ingest_pipeline/default.yml b/packages/platform_observability/data_stream/kibana_log/elasticsearch/ingest_pipeline/default.yml new file mode 100644 index 00000000000..e7070f68af6 --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_log/elasticsearch/ingest_pipeline/default.yml @@ -0,0 +1,41 @@ +--- +description: Pipeline for parsing Kibana ECS formatted logs +processors: + - pipeline: + name: '{{ IngestPipeline "ecs-logs-pipeline" }}' + if: |- + def message = ctx.message; + return message != null + && message.startsWith('{') + && message.endsWith('}') + && message.contains('"@timestamp"') + - set: + field: data_stream.type + value: logs + - set: + field: data_stream.dataset + value: kibana-logs + - set: + field: data_stream.namespace + value: platform-observability + - set: + field: event.dataset + copy_from: data_stream.dataset + - set: + field: event.ingested + value: "{{_ingest.timestamp}}" + - set: + field: event.kind + value: event + - set: + field: event.outcome + value: success + if: "ctx?.http?.response?.status_code != null && ctx.http.response.status_code < 400" + - set: + field: event.outcome + value: failure + if: "ctx?.http?.response?.status_code != null && ctx.http.response.status_code >= 400" +on_failure: + - set: + field: error.message + value: "{{ _ingest.on_failure_message }}" diff --git a/packages/platform_observability/data_stream/kibana_log/elasticsearch/ingest_pipeline/ecs-logs-pipeline.yml b/packages/platform_observability/data_stream/kibana_log/elasticsearch/ingest_pipeline/ecs-logs-pipeline.yml new file mode 100644 index 00000000000..16db6d98a0f --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_log/elasticsearch/ingest_pipeline/ecs-logs-pipeline.yml @@ -0,0 +1,31 @@ +--- +processors: + - rename: + field: message + target_field: _ecs_json_message + ignore_missing: true + - json: + field: _ecs_json_message + add_to_root: true + add_to_root_conflict_strategy: merge + allow_duplicate_keys: true + if: ctx.containsKey('_ecs_json_message') + on_failure: + - rename: + field: _ecs_json_message + target_field: message + ignore_missing: true + - set: + field: error.message + value: Error while parsing JSON + override: false + - remove: + field: _ecs_json_message + ignore_missing: true + - dot_expander: + field: "*" + override: true + - join: + field: error.stack_trace + separator: "\n" + if: ctx.error?.stack_trace instanceof Collection diff --git a/packages/platform_observability/data_stream/kibana_log/fields/base-fields.yml b/packages/platform_observability/data_stream/kibana_log/fields/base-fields.yml new file mode 100644 index 00000000000..0d1791ffed6 --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_log/fields/base-fields.yml @@ -0,0 +1,12 @@ +- name: data_stream.type + type: constant_keyword + description: Data stream type. +- name: data_stream.dataset + type: constant_keyword + description: Data stream dataset. +- name: data_stream.namespace + type: constant_keyword + description: Data stream namespace. +- name: "@timestamp" + type: date + description: Event timestamp. diff --git a/packages/platform_observability/data_stream/kibana_log/fields/ecs.yml b/packages/platform_observability/data_stream/kibana_log/fields/ecs.yml new file mode 100644 index 00000000000..6335dc892e4 --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_log/fields/ecs.yml @@ -0,0 +1,34 @@ +- name: ecs.version + external: ecs +- name: event.dataset + external: ecs +- name: event.kind + external: ecs +- name: event.ingested + external: ecs +- name: event.outcome + external: ecs +- name: http.request.id + external: ecs +- name: http.request.method + external: ecs +- name: http.response.body.bytes + external: ecs +- name: http.response.status_code + external: ecs +- name: log.level + external: ecs +- name: log.logger + external: ecs +- name: message + external: ecs +- name: process.pid + external: ecs +- name: trace.id + external: ecs +- name: transaction.id + external: ecs +- name: url.path + external: ecs +- name: url.query + external: ecs diff --git a/packages/platform_observability/data_stream/kibana_log/manifest.yml b/packages/platform_observability/data_stream/kibana_log/manifest.yml new file mode 100644 index 00000000000..cbd6fc42457 --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_log/manifest.yml @@ -0,0 +1,16 @@ +type: logs +title: Platform Observability Kibana logs +streams: + - input: logfile + vars: + - name: paths + type: text + title: Paths + multi: true + required: true + show_user: true + default: + - /var/log/kibana/kibana.log + template_path: log.yml.hbs + title: Kibana logs + description: Collect Kibana logs diff --git a/packages/platform_observability/data_stream/kibana_log/sample_event.json b/packages/platform_observability/data_stream/kibana_log/sample_event.json new file mode 100644 index 00000000000..53f1d0d99eb --- /dev/null +++ b/packages/platform_observability/data_stream/kibana_log/sample_event.json @@ -0,0 +1,36 @@ +{ + "http": { + "request": { + "id": "unknownId", + "method": "GET" + }, + "response": { + "body": { + "bytes": 118 + }, + "status_code": 200 + } + }, + "url": { + "path": "/_nodes", + "query": "filter_path=nodes.*.version%2Cnodes.*.http.publish_address%2Cnodes.*.ip" + }, + "ecs": { + "version": "8.0.0" + }, + "@timestamp": "2022-07-14T10:35:25.366+00:00", + "message": "200 - 118.0B\nGET /_nodes?filter_path=nodes.*.version%2Cnodes.*.http.publish_address%2Cnodes.*.ip", + "log": { + "level": "DEBUG", + "logger": "elasticsearch.query.data" + }, + "process": { + "pid": 7 + }, + "trace": { + "id": "0cd8dd5a3483159a43c07e9205432775" + }, + "transaction": { + "id": "6301eca88fba8d99" + } +} \ No newline at end of file diff --git a/packages/platform_observability/docs/README.md b/packages/platform_observability/docs/README.md new file mode 100644 index 00000000000..bd116db6eca --- /dev/null +++ b/packages/platform_observability/docs/README.md @@ -0,0 +1,182 @@ +# Platform Observability + +## Compatibility + +This package works with Kibana 8.3.0 and later. + +## Kibana logs + +The Kibana integration collects logs from [Kibana](https://www.elastic.co/guide/en/kibana/current/introduction.html) instance. + +### Logs + +#### Audit + +Audit logs collects the [Kibana audit logs](https://www.elastic.co/guide/en/kibana/current/security-settings-kb.html). + +An example event for `kibana_audit` looks as following: + +```json +{ + "event": { + "action": "http_request", + "category": [ + "web" + ], + "outcome": "unknown" + }, + "http": { + "request": { + "method": "get" + } + }, + "url": { + "domain": "localhost", + "path": "/internal/security/session", + "port": 5601, + "scheme": "http" + }, + "user": { + "name": "elastic", + "roles": [ + "superuser" + ] + }, + "kibana": { + "space_id": "default", + "session_id": "ccZ0sbxrmmJwo+/y2Mn1tmGIrKOuZYaF8voUh0SkA/k=" + }, + "trace": { + "id": "1c8c5808-d2d6-41fc-8cb7-998aa8996be9" + }, + "ecs": { + "version": "8.0.0" + }, + "@timestamp": "2022-06-29T12:05:03.742+00:00", + "message": "User is requesting [/internal/security/session] endpoint", + "log": { + "level": "INFO", + "logger": "plugins.security.audit.ecs" + }, + "process": { + "pid": 7 + }, + "transaction": { + "id": "f8863d86567119e6" + } +} +``` + +**Exported fields** + +| Field | Description | Type | +|---|---|---| +| @timestamp | Event timestamp. | date | +| data_stream.dataset | Data stream dataset. | constant_keyword | +| data_stream.namespace | Data stream namespace. | constant_keyword | +| data_stream.type | Data stream type. | constant_keyword | +| ecs.version | ECS version this event conforms to. `ecs.version` is a required field and must exist in all events. When querying across multiple indices -- which may conform to slightly different ECS versions -- this field lets integrations adjust to the schema version of the events. | keyword | +| event.action | The action captured by the event. This describes the information in the event. It is more specific than `event.category`. Examples are `group-add`, `process-started`, `file-created`. The value is normally defined by the implementer. | keyword | +| event.category | This is one of four ECS Categorization Fields, and indicates the second level in the ECS category hierarchy. `event.category` represents the "big buckets" of ECS categories. For example, filtering on `event.category:process` yields all events relating to process activity. This field is closely related to `event.type`, which is used as a subcategory. This field is an array. This will allow proper categorization of some events that fall in multiple categories. | keyword | +| event.dataset | Name of the dataset. If an event source publishes more than one type of log or events (e.g. access log, error log), the dataset is used to specify which one the event comes from. It's recommended but not required to start the dataset name with the module name, followed by a dot, then the dataset name. | keyword | +| event.ingested | Timestamp when an event arrived in the central data store. This is different from `@timestamp`, which is when the event originally occurred. It's also different from `event.created`, which is meant to capture the first time an agent saw the event. In normal conditions, assuming no tampering, the timestamps should chronologically look like this: `@timestamp` \< `event.created` \< `event.ingested`. | date | +| event.kind | This is one of four ECS Categorization Fields, and indicates the highest level in the ECS category hierarchy. `event.kind` gives high-level information about what type of information the event contains, without being specific to the contents of the event. For example, values of this field distinguish alert events from metric events. The value of this field can be used to inform how these kinds of events should be handled. They may warrant different retention, different access control, it may also help understand whether the data coming in at a regular interval or not. | keyword | +| event.outcome | This is one of four ECS Categorization Fields, and indicates the lowest level in the ECS category hierarchy. `event.outcome` simply denotes whether the event represents a success or a failure from the perspective of the entity that produced the event. Note that when a single transaction is described in multiple events, each event may populate different values of `event.outcome`, according to their perspective. Also note that in the case of a compound event (a single event that contains multiple logical events), this field should be populated with the value that best captures the overall success or failure from the perspective of the event producer. Further note that not all events will have an associated outcome. For example, this field is generally not populated for metric events, events with `event.type:info`, or any events for which an outcome does not make logical sense. | keyword | +| http.request.method | HTTP request method. The value should retain its casing from the original event. For example, `GET`, `get`, and `GeT` are all considered valid values for this field. | keyword | +| kibana.add_to_spaces | The set of space ids that a saved object was shared to. | keyword | +| kibana.authentication_provider | The authentication provider associated with a login event. | keyword | +| kibana.authentication_realm | The Elasticsearch authentication realm name which fulfilled a login event. | keyword | +| kibana.authentication_type | The authentication provider type associated with a login event. | keyword | +| kibana.delete_from_spaces | The set of space ids that a saved object was removed from. | keyword | +| kibana.lookup_realm | The Elasticsearch lookup realm which fulfilled a login event. | keyword | +| kibana.saved_object.id | The id of the saved object associated with this event. | keyword | +| kibana.saved_object.type | The type of the saved object associated with this event. | keyword | +| kibana.session_id | The ID of the user session associated with this event. Each login attempt results in a unique session id. | keyword | +| kibana.space_id | The id of the space associated with this event. | keyword | +| log.level | Original log level of the log event. If the source of the event provides a log level or textual severity, this is the one that goes in `log.level`. If your source doesn't specify one, you may put your event transport's severity here (e.g. Syslog severity). Some examples are `warn`, `err`, `i`, `informational`. | keyword | +| log.logger | The name of the logger inside an application. This is usually the name of the class which initialized the logger, or can be a custom name. | keyword | +| message | For log events the message field contains the log message, optimized for viewing in a log viewer. For structured logs without an original message field, other fields can be concatenated to form a human-readable summary of the event. If multiple messages exist, they can be combined into one message. | match_only_text | +| process.pid | Process id. | long | +| trace.id | Unique identifier of the trace. A trace groups multiple events like transactions that belong together. For example, a user request handled by multiple inter-connected services. | keyword | +| transaction.id | Unique identifier of the transaction within the scope of its trace. A transaction is the highest level of work measured within a service, such as a request to a server. | keyword | +| url.domain | Domain of the url, such as "www.elastic.co". In some cases a URL may refer to an IP and/or port directly, without a domain name. In this case, the IP address would go to the `domain` field. If the URL contains a literal IPv6 address enclosed by `[` and `]` (IETF RFC 2732), the `[` and `]` characters should also be captured in the `domain` field. | keyword | +| url.path | Path of the request, such as "/search". | wildcard | +| url.port | Port of the request, such as 443. | long | +| url.query | The query field describes the query string of the request, such as "q=elasticsearch". The `?` is excluded from the query string. If a URL contains no `?`, there is no query field. If there is a `?` but no query, the query field exists with an empty string. The `exists` query can be used to differentiate between the two cases. | keyword | +| url.scheme | Scheme of the request, such as "https". Note: The `:` is not part of the scheme. | keyword | +| user.name | Short name or login of the user. | keyword | +| user.name.text | Multi-field of `user.name`. | match_only_text | +| user.roles | Array of user roles at the time of the event. | keyword | + + +#### Log + +Log collects the [Kibana logs](https://www.elastic.co/guide/en/kibana/current/logging-configuration.html). + +An example event for `kibana_log` looks as following: + +```json +{ + "http": { + "request": { + "id": "unknownId", + "method": "GET" + }, + "response": { + "body": { + "bytes": 118 + }, + "status_code": 200 + } + }, + "url": { + "path": "/_nodes", + "query": "filter_path=nodes.*.version%2Cnodes.*.http.publish_address%2Cnodes.*.ip" + }, + "ecs": { + "version": "8.0.0" + }, + "@timestamp": "2022-07-14T10:35:25.366+00:00", + "message": "200 - 118.0B\nGET /_nodes?filter_path=nodes.*.version%2Cnodes.*.http.publish_address%2Cnodes.*.ip", + "log": { + "level": "DEBUG", + "logger": "elasticsearch.query.data" + }, + "process": { + "pid": 7 + }, + "trace": { + "id": "0cd8dd5a3483159a43c07e9205432775" + }, + "transaction": { + "id": "6301eca88fba8d99" + } +} +``` + +**Exported fields** + +| Field | Description | Type | +|---|---|---| +| @timestamp | Event timestamp. | date | +| data_stream.dataset | Data stream dataset. | constant_keyword | +| data_stream.namespace | Data stream namespace. | constant_keyword | +| data_stream.type | Data stream type. | constant_keyword | +| ecs.version | ECS version this event conforms to. `ecs.version` is a required field and must exist in all events. When querying across multiple indices -- which may conform to slightly different ECS versions -- this field lets integrations adjust to the schema version of the events. | keyword | +| event.dataset | Name of the dataset. If an event source publishes more than one type of log or events (e.g. access log, error log), the dataset is used to specify which one the event comes from. It's recommended but not required to start the dataset name with the module name, followed by a dot, then the dataset name. | keyword | +| event.ingested | Timestamp when an event arrived in the central data store. This is different from `@timestamp`, which is when the event originally occurred. It's also different from `event.created`, which is meant to capture the first time an agent saw the event. In normal conditions, assuming no tampering, the timestamps should chronologically look like this: `@timestamp` \< `event.created` \< `event.ingested`. | date | +| event.kind | This is one of four ECS Categorization Fields, and indicates the highest level in the ECS category hierarchy. `event.kind` gives high-level information about what type of information the event contains, without being specific to the contents of the event. For example, values of this field distinguish alert events from metric events. The value of this field can be used to inform how these kinds of events should be handled. They may warrant different retention, different access control, it may also help understand whether the data coming in at a regular interval or not. | keyword | +| event.outcome | This is one of four ECS Categorization Fields, and indicates the lowest level in the ECS category hierarchy. `event.outcome` simply denotes whether the event represents a success or a failure from the perspective of the entity that produced the event. Note that when a single transaction is described in multiple events, each event may populate different values of `event.outcome`, according to their perspective. Also note that in the case of a compound event (a single event that contains multiple logical events), this field should be populated with the value that best captures the overall success or failure from the perspective of the event producer. Further note that not all events will have an associated outcome. For example, this field is generally not populated for metric events, events with `event.type:info`, or any events for which an outcome does not make logical sense. | keyword | +| http.request.id | A unique identifier for each HTTP request to correlate logs between clients and servers in transactions. The id may be contained in a non-standard HTTP header, such as `X-Request-ID` or `X-Correlation-ID`. | keyword | +| http.request.method | HTTP request method. The value should retain its casing from the original event. For example, `GET`, `get`, and `GeT` are all considered valid values for this field. | keyword | +| http.response.body.bytes | Size in bytes of the response body. | long | +| http.response.status_code | HTTP response status code. | long | +| log.level | Original log level of the log event. If the source of the event provides a log level or textual severity, this is the one that goes in `log.level`. If your source doesn't specify one, you may put your event transport's severity here (e.g. Syslog severity). Some examples are `warn`, `err`, `i`, `informational`. | keyword | +| log.logger | The name of the logger inside an application. This is usually the name of the class which initialized the logger, or can be a custom name. | keyword | +| message | For log events the message field contains the log message, optimized for viewing in a log viewer. For structured logs without an original message field, other fields can be concatenated to form a human-readable summary of the event. If multiple messages exist, they can be combined into one message. | match_only_text | +| process.pid | Process id. | long | +| trace.id | Unique identifier of the trace. A trace groups multiple events like transactions that belong together. For example, a user request handled by multiple inter-connected services. | keyword | +| transaction.id | Unique identifier of the transaction within the scope of its trace. A transaction is the highest level of work measured within a service, such as a request to a server. | keyword | +| url.path | Path of the request, such as "/search". | wildcard | +| url.query | The query field describes the query string of the request, such as "q=elasticsearch". The `?` is excluded from the query string. If a URL contains no `?`, there is no query field. If there is a `?` but no query, the query field exists with an empty string. The `exists` query can be used to differentiate between the two cases. | keyword | + diff --git a/packages/platform_observability/img/logo_kibana.svg b/packages/platform_observability/img/logo_kibana.svg new file mode 100644 index 00000000000..8e5571acc1b --- /dev/null +++ b/packages/platform_observability/img/logo_kibana.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/platform_observability/manifest.yml b/packages/platform_observability/manifest.yml new file mode 100644 index 00000000000..7a87abfcc55 --- /dev/null +++ b/packages/platform_observability/manifest.yml @@ -0,0 +1,26 @@ +format_version: 1.0.0 +name: platform_observability +title: "Platform Observability" +version: 0.0.1 +license: basic +description: "Collect stack component logs with Elastic Agent" +type: integration +icons: + - src: /img/logo_kibana.svg + title: logo kibana + size: 32x32 + type: image/svg+xml +categories: ["elastic_stack"] +conditions: + kibana.version: "^8.3.0" + elastic.subscription: "basic" +policy_templates: + - name: platform_observability_kibana_logs + title: Kibana logs + description: Collect logs from Kibana + inputs: + - type: logfile + title: "Collect Kibana logs" + description: "Collecting audit and application logs from Kibana instances" +owner: + github: elastic/infra-monitoring-ui