diff --git a/packages/axonius/_dev/build/docs/README.md b/packages/axonius/_dev/build/docs/README.md index 457a6e46891..f30b1b445bb 100644 --- a/packages/axonius/_dev/build/docs/README.md +++ b/packages/axonius/_dev/build/docs/README.md @@ -17,11 +17,15 @@ This integration collects log messages of the following type: - `Adapter`: Collect details of all adapters (endpoint: `/api/v2/adapters`). +- `User`: Collect details of all users (endpoint: `/api/v2/users`). + ### Supported use cases -Integrating the Axonius Adapters with Elastic SIEM provides clear visibility into adapter health and data-collection performance across the environment. The dashboard highlights overall adapter status, offering a quick understanding of which integrations are functioning normally and which require attention. Essential adapter details are surfaced to help analysts validate configurations, identify failing plugins, and understand the distribution of adapters across nodes. +Integrating the Axonius Adapter and User Data streams with Elastic SIEM provides centralized visibility into both data-collection health and user identity context across the environment. Together, these data streams help analysts understand how data is being ingested through adapters and how that data maps to user identities and access posture. + +The dashboards highlight overall adapter status and connection behavior, making it easy to identify healthy integrations, failing plugins, and error-prone connections that may impact asset visibility. At the same time, user-focused views surface role distribution and essential identity attributes, helping analysts quickly assess access patterns and identify high-privileged or unusual user activity. Consolidated user details and source information provide clarity on where identity data originates and whether coverage gaps exist. -It also provides insight into connection behavior for each adapter, revealing patterns of active, inactive, and error-prone connections. Error-specific views make it easy to spot problematic integrations and prioritize troubleshooting efforts. These insights enable teams to maintain reliable data ingestion, reduce blind spots, and ensure complete and accurate asset collection across all connected systems. +By combining adapter health insights with user identity visibility, security teams can ensure reliable data ingestion, detect identity-related anomalies, reduce blind spots, and streamline investigations that depend on accurate, end-to-end context from both integrations and users. ## What do I need to use this integration? @@ -39,7 +43,13 @@ To collect data through the Axonius APIs, you need to provide the **URL**, **API 2. Your instance URL is your Base **URL**. 3. Navigate to **User Settings > API Key**. 4. Generate an **API Key**. -5. Copy both values including **API Key and Secret Key** and store them securely for use in the Integration configuration. +5. If you do not see the API Key tab in your user settings, follow these steps: + 1. Go to **System Settings** > **User and Role Management** > **Service Accounts**. + 2. Create a Service Account, and then generate an **API Key**. +6. Copy both values including **API Key and Secret Key** and store them securely for use in the Integration configuration. + +**Note:** +To generate or reset an API key, your role must be **Admin**, and you must have **API Access** permissions, which include **API Access Enabled** and **Reset API Key**. ## How do I deploy this integration? @@ -106,6 +116,16 @@ The `adapter` data stream provides adapter logs from axonius. {{ event "adapter" }} +### User + +The `user` data stream provides user events from axonius. + +#### user fields + +{{ fields "user" }} + +{{ event "user" }} + ### Inputs used {{/* All inputs used by this package will be automatically listed here. */}} {{ inputDocs }} @@ -115,7 +135,8 @@ The `adapter` data stream provides adapter logs from axonius. These APIs are used with this integration: * Adapter (endpoint: `/api/v2/adapters`) +* User (endpoint: `/api/v2/users`) -#### ILM Policy +### ILM Policy -To facilitate adapter data, source data stream-backed indices `.ds-logs-axonius.adapter-*` are allowed to contain duplicates from each polling interval. ILM policy `logs-axonius.adapter-default_policy` is added to these source indices, so it doesn't lead to unbounded growth. This means that in these source indices data will be deleted after `30 days` from ingested date. +To facilitate adapter and user data, source data stream-backed indices `.ds-logs-axonius.adapter-*` and `.ds-logs-axonius.user-*` respectively are allowed to contain duplicates from each polling interval. ILM policies `logs-axonius.adapter-default_policy` and `logs-axonius.user-default_policy` are added to these source indices, so it doesn't lead to unbounded growth. This means that in these source indices data will be deleted after `30 days` from ingested date. diff --git a/packages/axonius/_dev/deploy/docker/files/config.yml b/packages/axonius/_dev/deploy/docker/files/config.yml index a0b00ff9ba8..cf0145e8086 100644 --- a/packages/axonius/_dev/deploy/docker/files/config.yml +++ b/packages/axonius/_dev/deploy/docker/files/config.yml @@ -97,3 +97,61 @@ rules: ] } `}} + - path: /api/v2/users + methods: ['GET'] + request_headers: + Accept: application/json + api-key: xxxx + api-secret: xxxx + responses: + - status_code: 200 + headers: + Content-Type: + - 'application/json' + body: |- + {{ minify_json ` + { + "users": [ + { + "role_id": "63622vfed93d274d9489dbbgresdcv6a1cf", + "data_scope_id": "fgreg63622d93d274d9489db6a1cf", + "allowed_scopes_impersonation": [ + "63622d93d27cvdsfa4d9489db6a1cf", + "63622d93d2dvfwe74d9489db6a1cc" + ], + "first_name": "alias", + "last_name": "doe", + "email": "alias.doe@example.com", + "title": "Security Analyst", + "department": "test", + "user_name": "alias.doe", + "last_updated": "Sun, 11 Mar 2025 18:53:09 GMT", + "source": "test source", + "uuid": "63622d93d274ihvbngvbhd9489db6a1cf", + "role_name": "test role", + "data_scope_name": "test data scope", + "last_login": "Sun, 09 Mar 2025 18:53:09 GMT" + }, + { + "role_id": "63622d93d27xcvdgre4d9489dbbgresdcv6a1cf", + "data_scope_id": "fgreghtgrtefdgrt63622d93d274d9489db6a1cf", + "allowed_scopes_impersonation": [ + "63622d93d27vdfrew4d9489db6a1cf", + "63622d93d27fvdwe4d9489db6a1cc" + ], + "first_name": "bob", + "last_name": "doe", + "email": "bob.doe@example.com", + "title": "Cloud Operations Engineer", + "department": "sample", + "user_name": "bob.doe", + "last_updated": "Mon, 12 Mar 2025 18:53:09 GMT", + "source": "sample source", + "uuid": "78ij63622d93d274d9489db6a1cf", + "role_name": " role", + "data_scope_name": "sample data scope", + "last_login": "Mon, 08 Mar 2025 18:53:09 GMT" + } + ] + } + `}} \ No newline at end of file diff --git a/packages/axonius/changelog.yml b/packages/axonius/changelog.yml index 20b11e55e32..23fd698480f 100644 --- a/packages/axonius/changelog.yml +++ b/packages/axonius/changelog.yml @@ -3,4 +3,4 @@ changes: - description: Initial release. type: enhancement - link: https://github.com/elastic/integrations/pull/16171 + link: https://github.com/elastic/integrations/pull/16142 diff --git a/packages/axonius/data_stream/user/_dev/test/pipeline/test-common-config.yml b/packages/axonius/data_stream/user/_dev/test/pipeline/test-common-config.yml new file mode 100644 index 00000000000..37e8fa225fd --- /dev/null +++ b/packages/axonius/data_stream/user/_dev/test/pipeline/test-common-config.yml @@ -0,0 +1,3 @@ +fields: + tags: + - preserve_duplicate_custom_fields diff --git a/packages/axonius/data_stream/user/_dev/test/pipeline/test-user.log b/packages/axonius/data_stream/user/_dev/test/pipeline/test-user.log new file mode 100644 index 00000000000..9075b7f1e31 --- /dev/null +++ b/packages/axonius/data_stream/user/_dev/test/pipeline/test-user.log @@ -0,0 +1,3 @@ +{"role_id":"63622d93d274d9489dbbgresdcv6a1cf","data_scope_id":"fgreg63622d93d274d9489db6a1cf","allowed_scopes_impersonation":["63622d93d274d9489db6a1cf","63622d93d274d9489db6a1cc"],"first_name":"john","last_name":"doe","email":"john.doe@example.com","title":"Software Engineer","department":"example","user_name":"john.doe","last_updated":"Sat, 10 Mar 2025 18:53:09 GMT","source":"example source","uuid":"63622d93d274d9489db6a1cf","role_name":"example role","data_scope_name":"example data scope","last_login":"Sat, 08 Mar 2025 18:53:09 GMT"} +{"role_id":"63622vfed93d274d9489dbbgresdcv6a1cf","data_scope_id":"fgreg63622d93d274d9489db6a1cf","allowed_scopes_impersonation":["63622d93d27cvdsfa4d9489db6a1cf","63622d93d2dvfwe74d9489db6a1cc"],"first_name":"alias","last_name":"doe","email":"alias.doe@example.com","title":"Security Analyst","department":"test","user_name":"alias.doe","last_updated":"Sun, 11 Mar 2025 18:53:09 GMT","source":"test source","uuid":"63622d93d274ihvbngvbhd9489db6a1cf","role_name":"test role","data_scope_name":"test data scope","last_login":"Sun, 09 Mar 2025 18:53:09 GMT"} +{"role_id":"63622d93d27xcvdgre4d9489dbbgresdcv6a1cf","data_scope_id":"fgreghtgrtefdgrt63622d93d274d9489db6a1cf","allowed_scopes_impersonation":["63622d93d27vdfrew4d9489db6a1cf","63622d93d27fvdwe4d9489db6a1cc"],"first_name":"bob","last_name":"doe","email":"bob.doe@example.com","title":"Cloud Operations Engineer","department":"sample","user_name":"bob.doe","last_updated":"Mon, 12 Mar 2025 18:53:09 GMT","source":"sample source","uuid":"78ij63622d93d274d9489db6a1cf","role_name":" role","data_scope_name":"sample data scope","last_login":"Mon, 08 Mar 2025 18:53:09 GMT"} diff --git a/packages/axonius/data_stream/user/_dev/test/pipeline/test-user.log-expected.json b/packages/axonius/data_stream/user/_dev/test/pipeline/test-user.log-expected.json new file mode 100644 index 00000000000..a62f84c0736 --- /dev/null +++ b/packages/axonius/data_stream/user/_dev/test/pipeline/test-user.log-expected.json @@ -0,0 +1,160 @@ +{ + "expected": [ + { + "axonius": { + "user": { + "allowed_scopes_impersonation": [ + "63622d93d274d9489db6a1cf", + "63622d93d274d9489db6a1cc" + ], + "data_scope_id": "fgreg63622d93d274d9489db6a1cf", + "data_scope_name": "example data scope", + "department": "example", + "email": "john.doe@example.com", + "first_name": "john", + "last_login": "2025-03-08T18:53:09.000Z", + "last_name": "doe", + "last_updated": "2025-03-10T18:53:09.000Z", + "role_id": "63622d93d274d9489dbbgresdcv6a1cf", + "role_name": "example role", + "source": "example source", + "title": "Software Engineer", + "user_name": "john.doe", + "uuid": "63622d93d274d9489db6a1cf" + } + }, + "ecs": { + "version": "9.2.0" + }, + "event": { + "kind": "event", + "original": "{\"role_id\":\"63622d93d274d9489dbbgresdcv6a1cf\",\"data_scope_id\":\"fgreg63622d93d274d9489db6a1cf\",\"allowed_scopes_impersonation\":[\"63622d93d274d9489db6a1cf\",\"63622d93d274d9489db6a1cc\"],\"first_name\":\"john\",\"last_name\":\"doe\",\"email\":\"john.doe@example.com\",\"title\":\"Software Engineer\",\"department\":\"example\",\"user_name\":\"john.doe\",\"last_updated\":\"Sat, 10 Mar 2025 18:53:09 GMT\",\"source\":\"example source\",\"uuid\":\"63622d93d274d9489db6a1cf\",\"role_name\":\"example role\",\"data_scope_name\":\"example data scope\",\"last_login\":\"Sat, 08 Mar 2025 18:53:09 GMT\"}" + }, + "related": { + "user": [ + "john doe", + "john.doe@example.com", + "john.doe", + "63622d93d274d9489db6a1cf" + ] + }, + "tags": [ + "preserve_duplicate_custom_fields" + ], + "user": { + "domain": "example.com", + "email": "john.doe@example.com", + "full_name": "john doe", + "id": "63622d93d274d9489db6a1cf", + "name": "john.doe", + "roles": [ + "example role" + ] + } + }, + { + "axonius": { + "user": { + "allowed_scopes_impersonation": [ + "63622d93d27cvdsfa4d9489db6a1cf", + "63622d93d2dvfwe74d9489db6a1cc" + ], + "data_scope_id": "fgreg63622d93d274d9489db6a1cf", + "data_scope_name": "test data scope", + "department": "test", + "email": "alias.doe@example.com", + "first_name": "alias", + "last_login": "2025-03-09T18:53:09.000Z", + "last_name": "doe", + "last_updated": "2025-03-11T18:53:09.000Z", + "role_id": "63622vfed93d274d9489dbbgresdcv6a1cf", + "role_name": "test role", + "source": "test source", + "title": "Security Analyst", + "user_name": "alias.doe", + "uuid": "63622d93d274ihvbngvbhd9489db6a1cf" + } + }, + "ecs": { + "version": "9.2.0" + }, + "event": { + "kind": "event", + "original": "{\"role_id\":\"63622vfed93d274d9489dbbgresdcv6a1cf\",\"data_scope_id\":\"fgreg63622d93d274d9489db6a1cf\",\"allowed_scopes_impersonation\":[\"63622d93d27cvdsfa4d9489db6a1cf\",\"63622d93d2dvfwe74d9489db6a1cc\"],\"first_name\":\"alias\",\"last_name\":\"doe\",\"email\":\"alias.doe@example.com\",\"title\":\"Security Analyst\",\"department\":\"test\",\"user_name\":\"alias.doe\",\"last_updated\":\"Sun, 11 Mar 2025 18:53:09 GMT\",\"source\":\"test source\",\"uuid\":\"63622d93d274ihvbngvbhd9489db6a1cf\",\"role_name\":\"test role\",\"data_scope_name\":\"test data scope\",\"last_login\":\"Sun, 09 Mar 2025 18:53:09 GMT\"}" + }, + "related": { + "user": [ + "alias doe", + "alias.doe@example.com", + "alias.doe", + "63622d93d274ihvbngvbhd9489db6a1cf" + ] + }, + "tags": [ + "preserve_duplicate_custom_fields" + ], + "user": { + "domain": "example.com", + "email": "alias.doe@example.com", + "full_name": "alias doe", + "id": "63622d93d274ihvbngvbhd9489db6a1cf", + "name": "alias.doe", + "roles": [ + "test role" + ] + } + }, + { + "axonius": { + "user": { + "allowed_scopes_impersonation": [ + "63622d93d27vdfrew4d9489db6a1cf", + "63622d93d27fvdwe4d9489db6a1cc" + ], + "data_scope_id": "fgreghtgrtefdgrt63622d93d274d9489db6a1cf", + "data_scope_name": "sample data scope", + "department": "sample", + "email": "bob.doe@example.com", + "first_name": "bob", + "last_login": "2025-03-08T18:53:09.000Z", + "last_name": "doe", + "last_updated": "2025-03-12T18:53:09.000Z", + "role_id": "63622d93d27xcvdgre4d9489dbbgresdcv6a1cf", + "role_name": " role", + "source": "sample source", + "title": "Cloud Operations Engineer", + "user_name": "bob.doe", + "uuid": "78ij63622d93d274d9489db6a1cf" + } + }, + "ecs": { + "version": "9.2.0" + }, + "event": { + "kind": "event", + "original": "{\"role_id\":\"63622d93d27xcvdgre4d9489dbbgresdcv6a1cf\",\"data_scope_id\":\"fgreghtgrtefdgrt63622d93d274d9489db6a1cf\",\"allowed_scopes_impersonation\":[\"63622d93d27vdfrew4d9489db6a1cf\",\"63622d93d27fvdwe4d9489db6a1cc\"],\"first_name\":\"bob\",\"last_name\":\"doe\",\"email\":\"bob.doe@example.com\",\"title\":\"Cloud Operations Engineer\",\"department\":\"sample\",\"user_name\":\"bob.doe\",\"last_updated\":\"Mon, 12 Mar 2025 18:53:09 GMT\",\"source\":\"sample source\",\"uuid\":\"78ij63622d93d274d9489db6a1cf\",\"role_name\":\" role\",\"data_scope_name\":\"sample data scope\",\"last_login\":\"Mon, 08 Mar 2025 18:53:09 GMT\"}" + }, + "related": { + "user": [ + "bob doe", + "bob.doe@example.com", + "bob.doe", + "78ij63622d93d274d9489db6a1cf" + ] + }, + "tags": [ + "preserve_duplicate_custom_fields" + ], + "user": { + "domain": "example.com", + "email": "bob.doe@example.com", + "full_name": "bob doe", + "id": "78ij63622d93d274d9489db6a1cf", + "name": "bob.doe", + "roles": [ + " role" + ] + } + } + ] +} diff --git a/packages/axonius/data_stream/user/_dev/test/system/test-default-config.yml b/packages/axonius/data_stream/user/_dev/test/system/test-default-config.yml new file mode 100644 index 00000000000..456301a9199 --- /dev/null +++ b/packages/axonius/data_stream/user/_dev/test/system/test-default-config.yml @@ -0,0 +1,12 @@ +input: cel +service: axonius +vars: + url: http://{{Hostname}}:{{Port}} + api_key: xxxx + secret_key: xxxx +data_stream: + vars: + preserve_original_event: true + preserve_duplicate_custom_fields: true +assert: + hit_count: 2 diff --git a/packages/axonius/data_stream/user/agent/stream/cel.yml.hbs b/packages/axonius/data_stream/user/agent/stream/cel.yml.hbs new file mode 100644 index 00000000000..ee8f9da255d --- /dev/null +++ b/packages/axonius/data_stream/user/agent/stream/cel.yml.hbs @@ -0,0 +1,79 @@ +config_version: 2 +interval: {{interval}} +resource.tracer: + enabled: {{enable_request_tracer}} + filename: "../../logs/cel/http-request-trace-*.ndjson" + maxbackups: 5 +{{#if proxy_url}} +resource.proxy_url: {{proxy_url}} +{{/if}} +{{#if ssl}} +resource.ssl: {{ssl}} +{{/if}} +{{#if http_client_timeout}} +resource.timeout: {{http_client_timeout}} +{{/if}} +resource.url: {{url}} + +state: + api_key: {{api_key}} + secret_key: {{secret_key}} +redact: + fields: + - api_key + - secret_key +program: | + request( + "GET", + state.url.trim_right("/") + "/api/v2/users" + ).with({ + "Header":{ + "Accept": ["application/json"], + "api-key": [state.api_key], + "api-secret": [state.secret_key], + } + }).do_request().as(resp, resp.StatusCode == 200 ? + resp.Body.decode_json().as(body, + { + "events": body.?users.orValue([]).map(e, { + "message": e.encode_json(), + }), + "api_key": state.api_key, + "secret_key": state.secret_key, + } + ) + : + { + "events": { + "error": { + "code": string(resp.StatusCode), + "id": string(resp.Status), + "message": "GET" + state.url.trim_right("/") + "/api/v2/users/: " + ( + size(resp.Body) != 0 ? + string(resp.Body) + : + string(resp.Status) + ' (' + string(resp.StatusCode) + ')' + ), + }, + }, + "api_key": state.api_key, + "secret_key": state.secret_key, + } + ) +tags: +{{#if preserve_original_event}} + - preserve_original_event +{{/if}} +{{#if preserve_duplicate_custom_fields}} + - preserve_duplicate_custom_fields +{{/if}} +{{#each tags as |tag|}} + - {{tag}} +{{/each}} +{{#contains "forwarded" tags}} +publisher_pipeline.disable_host: true +{{/contains}} +{{#if processors}} +processors: +{{processors}} +{{/if}} diff --git a/packages/axonius/data_stream/user/elasticsearch/ilm/default_policy.json b/packages/axonius/data_stream/user/elasticsearch/ilm/default_policy.json new file mode 100644 index 00000000000..24bbfc79405 --- /dev/null +++ b/packages/axonius/data_stream/user/elasticsearch/ilm/default_policy.json @@ -0,0 +1,20 @@ +{ + "policy": { + "phases": { + "hot": { + "actions": { + "rollover": { + "max_age": "30d", + "max_primary_shard_size": "50gb" + } + } + }, + "delete": { + "min_age": "30d", + "actions": { + "delete": {} + } + } + } + } +} diff --git a/packages/axonius/data_stream/user/elasticsearch/ingest_pipeline/default.yml b/packages/axonius/data_stream/user/elasticsearch/ingest_pipeline/default.yml new file mode 100644 index 00000000000..e0893c5cb08 --- /dev/null +++ b/packages/axonius/data_stream/user/elasticsearch/ingest_pipeline/default.yml @@ -0,0 +1,208 @@ +--- +description: Pipeline for processing user logs. +processors: + - set: + tag: set_ecs_version_to_9_2_0_3273339c + field: ecs.version + value: 9.2.0 + - terminate: + description: error message set and no data to process. + tag: terminate_data_collection_error_4c75f12b + if: ctx.error?.message != null && ctx.message == null && ctx.event?.original == null + + # remove agentless metadata + - remove: + description: Removes the fields added by Agentless as metadata, as they can collide with ECS fields. + tag: remove_agentless_tags_44eed408 + if: ctx.organization instanceof String && ctx.division instanceof String && ctx.team instanceof String + field: + - organization + - division + - team + ignore_missing: true + + # parse the event JSON + - rename: + description: Renames the original `message` field to `event.original` to store a copy of the original message. The `event.original` field is not touched if the document already has one; it may happen when Logstash sends the document. + tag: rename_message_to_event_original_c74b1d7e + if: ctx.event?.original == null + field: message + target_field: event.original + ignore_missing: true + - remove: + description: The `message` field is no longer required if the document has an `event.original` field. + tag: remove_message_84808ee4 + if: ctx.event?.original != null + field: message + ignore_missing: true + - json: + tag: json_event_original_into_axonius_user_f966e964 + field: event.original + target_field: axonius.user + + # Set event.* fields + - set: + tag: set_event_kind_to_event_de80643c + field: event.kind + value: event + + # Date processors + - date: + tag: date_axonius_user_last_updated_into_axonius_user_last_updated_f5979b5d + if: ctx.axonius?.user?.last_updated != null && ctx.axonius.user.last_updated != '' + field: axonius.user.last_updated + target_field: axonius.user.last_updated + formats: + - EEE, dd MMM yyyy HH:mm:ss 'GMT' + - yyyy-MM-dd + on_failure: + - remove: + tag: remove_axonius_user_last_updated_b724d1df + field: + - axonius.user.last_updated + - append: + tag: append_error_message_1eeda773 + field: error.message + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - date: + tag: date_axonius_user_last_login_into_axonius_user_last_login_d048bf89 + if: ctx.axonius?.user?.last_login != null && ctx.axonius.user.last_login != '' + field: axonius.user.last_login + target_field: axonius.user.last_login + formats: + - EEE, dd MMM yyyy HH:mm:ss 'GMT' + - yyyy-MM-dd + on_failure: + - remove: + tag: remove_axonius_user_last_login_4862e3f9 + field: + - axonius.user.last_login + - append: + tag: append_error_message_88d433ff + field: error.message + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + + # Map custom fields to corresponding ECS and related fields. + - set: + tag: set_user_email_from_axonius_user_email_0ae2ec9a + field: user.email + copy_from: axonius.user.email + ignore_empty_value: true + - set: + tag: set_user_name_from_axonius_user_user_name_e9c71082 + field: user.name + copy_from: axonius.user.user_name + ignore_empty_value: true + - set: + tag: set_user_id_from_axonius_user_uuid_95c9b11e + field: user.id + copy_from: axonius.user.uuid + ignore_empty_value: true + - append: + tag: append_user_roles_from_axonius_user_role_name_33de7d10 + if: ctx.axonius?.user?.role_name != null + field: user.roles + value: '{{{axonius.user.role_name}}}' + allow_duplicates: false + - set: + tag: set_user_full_name_from_axonius_user_first_name_and_axonius_user_last_name_e0840ddf + if: ctx.axonius?.user?.first_name != null && ctx.axonius?.user?.last_name != null + field: user.full_name + value: '{{{axonius.user.first_name}}} {{{axonius.user.last_name}}}' + - set: + tag: set_user_email_from_user_name_e02da544 + if: ctx.user?.email == null && ctx.user?.name != null && ctx.user?.name.contains('@') + field: user.email + copy_from: user.name + - dissect: + tag: dissect_user_email_6a0555c7 + if: ctx.user?.email != null && ctx.user.email.contains('@') + field: user.email + pattern: '%{}@%{user.domain}' + - append: + tag: append_related_user_from_axonius_user_full_name_3fd45cce + if: ctx.user?.full_name != null + field: related.user + value: '{{{user.full_name}}}' + allow_duplicates: false + - append: + tag: append_related_user_from_axonius_user_email_65d83a00 + if: ctx.axonius?.user?.email != null + field: related.user + value: '{{{axonius.user.email}}}' + allow_duplicates: false + - append: + tag: append_related_user_from_axonius_user_user_name_4cbc4dac + if: ctx.axonius?.user?.user_name != null + field: related.user + value: '{{{axonius.user.user_name}}}' + allow_duplicates: false + - append: + tag: append_related_user_from_axonius_user_uuid_536e32f8 + if: ctx.axonius?.user?.uuid != null + field: related.user + value: '{{{axonius.user.uuid}}}' + allow_duplicates: false + + # Remove duplicate custom fields if preserve_duplicate_custom_fields are not enabled + - remove: + tag: remove_custom_duplicate_fields_8b053065 + if: ctx.tags == null || !ctx.tags.contains('preserve_duplicate_custom_fields') + field: + - axonius.user.email + - axonius.user.user_name + - axonius.user.uuid + ignore_missing: true + + # Cleanup + - script: + description: This script processor iterates over the whole document to remove fields with null values. + tag: script_to_drop_null_values_8360f3de + lang: painless + source: |- + void handleMap(Map map) { + map.values().removeIf(v -> { + if (v instanceof Map) { + handleMap(v); + } else if (v instanceof List) { + handleList(v); + } + return v == null || v == '' || (v instanceof Map && v.size() == 0) || (v instanceof List && v.size() == 0) + }); + } + void handleList(List list) { + list.removeIf(v -> { + if (v instanceof Map) { + handleMap(v); + } else if (v instanceof List) { + handleList(v); + } + return v == null || v == '' || (v instanceof Map && v.size() == 0) || (v instanceof List && v.size() == 0) + }); + } + handleMap(ctx); + - set: + tag: set_event_kind_to_pipeline_error_92954dfa + if: ctx.error?.message != null + field: event.kind + value: pipeline_error + - append: + tag: append_tags_9fe66b2c + if: ctx.error?.message != null + field: tags + value: preserve_original_event + allow_duplicates: false +on_failure: + - append: + tag: append_error_message_e0c9bd63 + field: error.message + value: 'Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}' + - set: + tag: set_event_kind_to_pipeline_error_f51b77ad + field: event.kind + value: pipeline_error + - append: + tag: append_tags_d762b9c5 + field: tags + value: preserve_original_event + allow_duplicates: false diff --git a/packages/axonius/data_stream/user/fields/base-fields.yml b/packages/axonius/data_stream/user/fields/base-fields.yml new file mode 100644 index 00000000000..d73c58561ed --- /dev/null +++ b/packages/axonius/data_stream/user/fields/base-fields.yml @@ -0,0 +1,16 @@ +- name: data_stream.dataset + external: ecs +- name: data_stream.namespace + external: ecs +- name: data_stream.type + external: ecs +- name: event.dataset + type: constant_keyword + external: ecs + value: axonius.user +- name: event.module + type: constant_keyword + external: ecs + value: axonius +- name: '@timestamp' + external: ecs diff --git a/packages/axonius/data_stream/user/fields/beats.yml b/packages/axonius/data_stream/user/fields/beats.yml new file mode 100644 index 00000000000..4084f1dc7f5 --- /dev/null +++ b/packages/axonius/data_stream/user/fields/beats.yml @@ -0,0 +1,6 @@ +- name: input.type + type: keyword + description: Type of filebeat input. +- name: log.offset + type: long + description: Log offset. diff --git a/packages/axonius/data_stream/user/fields/ecs.yml b/packages/axonius/data_stream/user/fields/ecs.yml new file mode 100644 index 00000000000..e1d89be8ab4 --- /dev/null +++ b/packages/axonius/data_stream/user/fields/ecs.yml @@ -0,0 +1,5 @@ +# Define ECS constant fields as constant_keyword +- name: observer.vendor + external: ecs + type: constant_keyword + value: Axonius diff --git a/packages/axonius/data_stream/user/fields/fields.yml b/packages/axonius/data_stream/user/fields/fields.yml new file mode 100644 index 00000000000..1a87b2e0cde --- /dev/null +++ b/packages/axonius/data_stream/user/fields/fields.yml @@ -0,0 +1,36 @@ +- name: axonius + type: group + fields: + - name: user + type: group + fields: + - name: allowed_scopes_impersonation + type: keyword + - name: data_scope_id + type: keyword + - name: data_scope_name + type: keyword + - name: department + type: keyword + - name: email + type: keyword + - name: first_name + type: keyword + - name: last_login + type: date + - name: last_name + type: keyword + - name: last_updated + type: date + - name: role_id + type: keyword + - name: role_name + type: keyword + - name: source + type: keyword + - name: title + type: keyword + - name: user_name + type: keyword + - name: uuid + type: keyword diff --git a/packages/axonius/data_stream/user/fields/is-transform-source-true.yml b/packages/axonius/data_stream/user/fields/is-transform-source-true.yml new file mode 100644 index 00000000000..af7c0ae72aa --- /dev/null +++ b/packages/axonius/data_stream/user/fields/is-transform-source-true.yml @@ -0,0 +1,4 @@ +- name: labels.is_transform_source + type: constant_keyword + value: 'true' + description: Indicates whether a user is in the raw source data stream, or in the latest destination index. diff --git a/packages/axonius/data_stream/user/lifecycle.yml b/packages/axonius/data_stream/user/lifecycle.yml new file mode 100644 index 00000000000..f7b0d98d5aa --- /dev/null +++ b/packages/axonius/data_stream/user/lifecycle.yml @@ -0,0 +1 @@ +data_retention: '30d' diff --git a/packages/axonius/data_stream/user/manifest.yml b/packages/axonius/data_stream/user/manifest.yml new file mode 100644 index 00000000000..240ba04cf40 --- /dev/null +++ b/packages/axonius/data_stream/user/manifest.yml @@ -0,0 +1,72 @@ +title: User +type: logs +ilm_policy: logs-axonius.user-default_policy +streams: + - input: cel + title: User + description: Collect User logs from Axonius. + template_path: cel.yml.hbs + vars: + - name: interval + type: text + title: Interval + description: Duration between requests to the Axonius API. Supported units for this parameter are h/m/s. + multi: false + required: true + show_user: true + default: 24h + - name: enable_request_tracer + type: bool + title: Enable request tracing + multi: false + default: false + required: false + show_user: false + description: >- + The request tracer logs requests and responses to the agent's local file-system for debugging configurations. + Enabling this request tracing compromises security and should only be used for debugging. Disabling the request + tracer will delete any stored traces. + See [documentation](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-cel.html#_resource_tracer_enable) + for details. + - name: preserve_original_event + type: bool + title: Preserve original event + description: Preserves a raw copy of the original event, added to the field event.original. + multi: false + required: false + show_user: true + default: false + - name: tags + type: text + title: Tags + description: Tags for the data-stream. + multi: true + required: true + show_user: false + default: + - forwarded + - axonius-user + - name: http_client_timeout + type: text + title: HTTP Client Timeout + description: Duration before declaring that the HTTP client connection has timed out. Supported time units are ns, us, ms, s, m, h. + multi: false + required: true + show_user: false + default: 30s + - name: preserve_duplicate_custom_fields + required: false + title: Preserve duplicate custom fields + description: Preserve axonius.user.* fields that were copied to Elastic Common Schema (ECS) fields. + type: bool + multi: false + show_user: false + default: false + - name: processors + type: yaml + title: Processors + multi: false + required: false + show_user: false + description: >- + Processors are used to reduce the number of fields in the exported event or to enhance the event with metadata. This executes in the agent before the logs are parsed. diff --git a/packages/axonius/data_stream/user/sample_event.json b/packages/axonius/data_stream/user/sample_event.json new file mode 100644 index 00000000000..94e2de0ba4c --- /dev/null +++ b/packages/axonius/data_stream/user/sample_event.json @@ -0,0 +1,79 @@ +{ + "@timestamp": "2026-01-05T09:31:18.314Z", + "agent": { + "ephemeral_id": "6be29bb7-8260-424e-932e-b14aa7f1fdda", + "id": "718d4ca7-c29e-4508-be01-a3b7ef816c4b", + "name": "elastic-agent-14268", + "type": "filebeat", + "version": "8.18.0" + }, + "axonius": { + "user": { + "allowed_scopes_impersonation": [ + "63622d93d27cvdsfa4d9489db6a1cf", + "63622d93d2dvfwe74d9489db6a1cc" + ], + "data_scope_id": "fgreg63622d93d274d9489db6a1cf", + "data_scope_name": "test data scope", + "department": "test", + "email": "alias.doe@example.com", + "first_name": "alias", + "last_login": "2025-03-09T18:53:09.000Z", + "last_name": "doe", + "last_updated": "2025-03-11T18:53:09.000Z", + "role_id": "63622vfed93d274d9489dbbgresdcv6a1cf", + "role_name": "test role", + "source": "test source", + "title": "Security Analyst", + "user_name": "alias.doe", + "uuid": "63622d93d274ihvbngvbhd9489db6a1cf" + } + }, + "data_stream": { + "dataset": "axonius.user", + "namespace": "36432", + "type": "logs" + }, + "ecs": { + "version": "9.2.0" + }, + "elastic_agent": { + "id": "718d4ca7-c29e-4508-be01-a3b7ef816c4b", + "snapshot": false, + "version": "8.18.0" + }, + "event": { + "agent_id_status": "verified", + "dataset": "axonius.user", + "ingested": "2026-01-05T09:31:21Z", + "kind": "event", + "original": "{\"allowed_scopes_impersonation\":[\"63622d93d27cvdsfa4d9489db6a1cf\",\"63622d93d2dvfwe74d9489db6a1cc\"],\"data_scope_id\":\"fgreg63622d93d274d9489db6a1cf\",\"data_scope_name\":\"test data scope\",\"department\":\"test\",\"email\":\"alias.doe@example.com\",\"first_name\":\"alias\",\"last_login\":\"Sun, 09 Mar 2025 18:53:09 GMT\",\"last_name\":\"doe\",\"last_updated\":\"Sun, 11 Mar 2025 18:53:09 GMT\",\"role_id\":\"63622vfed93d274d9489dbbgresdcv6a1cf\",\"role_name\":\"test role\",\"source\":\"test source\",\"title\":\"Security Analyst\",\"user_name\":\"alias.doe\",\"uuid\":\"63622d93d274ihvbngvbhd9489db6a1cf\"}" + }, + "input": { + "type": "cel" + }, + "related": { + "user": [ + "alias doe", + "alias.doe@example.com", + "alias.doe", + "63622d93d274ihvbngvbhd9489db6a1cf" + ] + }, + "tags": [ + "preserve_original_event", + "preserve_duplicate_custom_fields", + "forwarded", + "axonius-user" + ], + "user": { + "domain": "example.com", + "email": "alias.doe@example.com", + "full_name": "alias doe", + "id": "63622d93d274ihvbngvbhd9489db6a1cf", + "name": "alias.doe", + "roles": [ + "test role" + ] + } +} diff --git a/packages/axonius/docs/README.md b/packages/axonius/docs/README.md index d13565db8a4..6d4f4fa8dc8 100644 --- a/packages/axonius/docs/README.md +++ b/packages/axonius/docs/README.md @@ -17,11 +17,15 @@ This integration collects log messages of the following type: - `Adapter`: Collect details of all adapters (endpoint: `/api/v2/adapters`). +- `User`: Collect details of all users (endpoint: `/api/v2/users`). + ### Supported use cases -Integrating the Axonius Adapters with Elastic SIEM provides clear visibility into adapter health and data-collection performance across the environment. The dashboard highlights overall adapter status, offering a quick understanding of which integrations are functioning normally and which require attention. Essential adapter details are surfaced to help analysts validate configurations, identify failing plugins, and understand the distribution of adapters across nodes. +Integrating the Axonius Adapter and User Data streams with Elastic SIEM provides centralized visibility into both data-collection health and user identity context across the environment. Together, these data streams help analysts understand how data is being ingested through adapters and how that data maps to user identities and access posture. + +The dashboards highlight overall adapter status and connection behavior, making it easy to identify healthy integrations, failing plugins, and error-prone connections that may impact asset visibility. At the same time, user-focused views surface role distribution and essential identity attributes, helping analysts quickly assess access patterns and identify high-privileged or unusual user activity. Consolidated user details and source information provide clarity on where identity data originates and whether coverage gaps exist. -It also provides insight into connection behavior for each adapter, revealing patterns of active, inactive, and error-prone connections. Error-specific views make it easy to spot problematic integrations and prioritize troubleshooting efforts. These insights enable teams to maintain reliable data ingestion, reduce blind spots, and ensure complete and accurate asset collection across all connected systems. +By combining adapter health insights with user identity visibility, security teams can ensure reliable data ingestion, detect identity-related anomalies, reduce blind spots, and streamline investigations that depend on accurate, end-to-end context from both integrations and users. ## What do I need to use this integration? @@ -39,7 +43,13 @@ To collect data through the Axonius APIs, you need to provide the **URL**, **API 2. Your instance URL is your Base **URL**. 3. Navigate to **User Settings > API Key**. 4. Generate an **API Key**. -5. Copy both values including **API Key and Secret Key** and store them securely for use in the Integration configuration. +5. If you do not see the API Key tab in your user settings, follow these steps: + 1. Go to **System Settings** > **User and Role Management** > **Service Accounts**. + 2. Create a Service Account, and then generate an **API Key**. +6. Copy both values including **API Key and Secret Key** and store them securely for use in the Integration configuration. + +**Note:** +To generate or reset an API key, your role must be **Admin**, and you must have **API Access** permissions, which include **API Access Enabled** and **Reset API Key**. ## How do I deploy this integration? @@ -230,6 +240,127 @@ An example event for `adapter` looks as following: } ``` +### User + +The `user` data stream provides user events from axonius. + +#### user fields + +**Exported fields** + +| Field | Description | Type | +|---|---|---| +| @timestamp | Date/time when the event originated. This is the date/time extracted from the event, typically representing when the event was generated by the source. If the event source has no original timestamp, this value is typically populated by the first time the event was received by the pipeline. Required field for all events. | date | +| axonius.user.allowed_scopes_impersonation | | keyword | +| axonius.user.data_scope_id | | keyword | +| axonius.user.data_scope_name | | keyword | +| axonius.user.department | | keyword | +| axonius.user.email | | keyword | +| axonius.user.first_name | | keyword | +| axonius.user.last_login | | date | +| axonius.user.last_name | | keyword | +| axonius.user.last_updated | | date | +| axonius.user.role_id | | keyword | +| axonius.user.role_name | | keyword | +| axonius.user.source | | keyword | +| axonius.user.title | | keyword | +| axonius.user.user_name | | keyword | +| axonius.user.uuid | | keyword | +| data_stream.dataset | The field can contain anything that makes sense to signify the source of the data. Examples include `nginx.access`, `prometheus`, `endpoint` etc. For data streams that otherwise fit, but that do not have dataset set we use the value "generic" for the dataset value. `event.dataset` should have the same value as `data_stream.dataset`. Beyond the Elasticsearch data stream naming criteria noted above, the `dataset` value has additional restrictions: \* Must not contain `-` \* No longer than 100 characters | constant_keyword | +| data_stream.namespace | A user defined namespace. Namespaces are useful to allow grouping of data. Many users already organize their indices this way, and the data stream naming scheme now provides this best practice as a default. Many users will populate this field with `default`. If no value is used, it falls back to `default`. Beyond the Elasticsearch index naming criteria noted above, `namespace` value has the additional restrictions: \* Must not contain `-` \* No longer than 100 characters | constant_keyword | +| data_stream.type | An overarching type for the data stream. Currently allowed values are "logs" and "metrics". We expect to also add "traces" and "synthetics" in the near future. | constant_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. | constant_keyword | +| event.module | Name of the module this data is coming from. If your monitoring agent supports the concept of modules or plugins to process events of a given source (e.g. Apache logs), `event.module` should contain the name of this module. | constant_keyword | +| input.type | Type of filebeat input. | keyword | +| labels.is_transform_source | Indicates whether a user is in the raw source data stream, or in the latest destination index. | constant_keyword | +| log.offset | Log offset. | long | +| observer.vendor | Vendor name of the observer. | constant_keyword | + + +An example event for `user` looks as following: + +```json +{ + "@timestamp": "2026-01-05T09:31:18.314Z", + "agent": { + "ephemeral_id": "6be29bb7-8260-424e-932e-b14aa7f1fdda", + "id": "718d4ca7-c29e-4508-be01-a3b7ef816c4b", + "name": "elastic-agent-14268", + "type": "filebeat", + "version": "8.18.0" + }, + "axonius": { + "user": { + "allowed_scopes_impersonation": [ + "63622d93d27cvdsfa4d9489db6a1cf", + "63622d93d2dvfwe74d9489db6a1cc" + ], + "data_scope_id": "fgreg63622d93d274d9489db6a1cf", + "data_scope_name": "test data scope", + "department": "test", + "email": "alias.doe@example.com", + "first_name": "alias", + "last_login": "2025-03-09T18:53:09.000Z", + "last_name": "doe", + "last_updated": "2025-03-11T18:53:09.000Z", + "role_id": "63622vfed93d274d9489dbbgresdcv6a1cf", + "role_name": "test role", + "source": "test source", + "title": "Security Analyst", + "user_name": "alias.doe", + "uuid": "63622d93d274ihvbngvbhd9489db6a1cf" + } + }, + "data_stream": { + "dataset": "axonius.user", + "namespace": "36432", + "type": "logs" + }, + "ecs": { + "version": "9.2.0" + }, + "elastic_agent": { + "id": "718d4ca7-c29e-4508-be01-a3b7ef816c4b", + "snapshot": false, + "version": "8.18.0" + }, + "event": { + "agent_id_status": "verified", + "dataset": "axonius.user", + "ingested": "2026-01-05T09:31:21Z", + "kind": "event", + "original": "{\"allowed_scopes_impersonation\":[\"63622d93d27cvdsfa4d9489db6a1cf\",\"63622d93d2dvfwe74d9489db6a1cc\"],\"data_scope_id\":\"fgreg63622d93d274d9489db6a1cf\",\"data_scope_name\":\"test data scope\",\"department\":\"test\",\"email\":\"alias.doe@example.com\",\"first_name\":\"alias\",\"last_login\":\"Sun, 09 Mar 2025 18:53:09 GMT\",\"last_name\":\"doe\",\"last_updated\":\"Sun, 11 Mar 2025 18:53:09 GMT\",\"role_id\":\"63622vfed93d274d9489dbbgresdcv6a1cf\",\"role_name\":\"test role\",\"source\":\"test source\",\"title\":\"Security Analyst\",\"user_name\":\"alias.doe\",\"uuid\":\"63622d93d274ihvbngvbhd9489db6a1cf\"}" + }, + "input": { + "type": "cel" + }, + "related": { + "user": [ + "alias doe", + "alias.doe@example.com", + "alias.doe", + "63622d93d274ihvbngvbhd9489db6a1cf" + ] + }, + "tags": [ + "preserve_original_event", + "preserve_duplicate_custom_fields", + "forwarded", + "axonius-user" + ], + "user": { + "domain": "example.com", + "email": "alias.doe@example.com", + "full_name": "alias doe", + "id": "63622d93d274ihvbngvbhd9489db6a1cf", + "name": "alias.doe", + "roles": [ + "test role" + ] + } +} +``` + ### Inputs used These inputs can be used with this integration: @@ -264,7 +395,8 @@ To collect logs via API endpoint, configure the following parameters: These APIs are used with this integration: * Adapter (endpoint: `/api/v2/adapters`) +* User (endpoint: `/api/v2/users`) -#### ILM Policy +### ILM Policy -To facilitate adapter data, source data stream-backed indices `.ds-logs-axonius.adapter-*` are allowed to contain duplicates from each polling interval. ILM policy `logs-axonius.adapter-default_policy` is added to these source indices, so it doesn't lead to unbounded growth. This means that in these source indices data will be deleted after `30 days` from ingested date. +To facilitate adapter and user data, source data stream-backed indices `.ds-logs-axonius.adapter-*` and `.ds-logs-axonius.user-*` respectively are allowed to contain duplicates from each polling interval. ILM policies `logs-axonius.adapter-default_policy` and `logs-axonius.user-default_policy` are added to these source indices, so it doesn't lead to unbounded growth. This means that in these source indices data will be deleted after `30 days` from ingested date. diff --git a/packages/axonius/elasticsearch/transform/latest_user/fields/base-fields.yml b/packages/axonius/elasticsearch/transform/latest_user/fields/base-fields.yml new file mode 100644 index 00000000000..d73c58561ed --- /dev/null +++ b/packages/axonius/elasticsearch/transform/latest_user/fields/base-fields.yml @@ -0,0 +1,16 @@ +- name: data_stream.dataset + external: ecs +- name: data_stream.namespace + external: ecs +- name: data_stream.type + external: ecs +- name: event.dataset + type: constant_keyword + external: ecs + value: axonius.user +- name: event.module + type: constant_keyword + external: ecs + value: axonius +- name: '@timestamp' + external: ecs diff --git a/packages/axonius/elasticsearch/transform/latest_user/fields/beats.yml b/packages/axonius/elasticsearch/transform/latest_user/fields/beats.yml new file mode 100644 index 00000000000..4084f1dc7f5 --- /dev/null +++ b/packages/axonius/elasticsearch/transform/latest_user/fields/beats.yml @@ -0,0 +1,6 @@ +- name: input.type + type: keyword + description: Type of filebeat input. +- name: log.offset + type: long + description: Log offset. diff --git a/packages/axonius/elasticsearch/transform/latest_user/fields/ecs.yml b/packages/axonius/elasticsearch/transform/latest_user/fields/ecs.yml new file mode 100644 index 00000000000..180bb321217 --- /dev/null +++ b/packages/axonius/elasticsearch/transform/latest_user/fields/ecs.yml @@ -0,0 +1,43 @@ +- external: ecs + name: agent.ephemeral_id +- external: ecs + name: agent.id +- external: ecs + name: agent.name +- external: ecs + name: agent.type +- external: ecs + name: agent.version +- external: ecs + name: ecs.version +- external: ecs + name: error.code +- external: ecs + name: error.id +- external: ecs + name: error.message +- external: ecs + name: event.agent_id_status +- external: ecs + name: event.ingested + type: date +- external: ecs + name: event.kind +- external: ecs + name: observer.vendor + type: constant_keyword + value: Axonius +- external: ecs + name: related.user +- external: ecs + name: user.domain +- external: ecs + name: user.email +- external: ecs + name: user.full_name +- external: ecs + name: user.id +- external: ecs + name: user.name +- external: ecs + name: user.roles diff --git a/packages/axonius/elasticsearch/transform/latest_user/fields/fields.yml b/packages/axonius/elasticsearch/transform/latest_user/fields/fields.yml new file mode 100644 index 00000000000..1a87b2e0cde --- /dev/null +++ b/packages/axonius/elasticsearch/transform/latest_user/fields/fields.yml @@ -0,0 +1,36 @@ +- name: axonius + type: group + fields: + - name: user + type: group + fields: + - name: allowed_scopes_impersonation + type: keyword + - name: data_scope_id + type: keyword + - name: data_scope_name + type: keyword + - name: department + type: keyword + - name: email + type: keyword + - name: first_name + type: keyword + - name: last_login + type: date + - name: last_name + type: keyword + - name: last_updated + type: date + - name: role_id + type: keyword + - name: role_name + type: keyword + - name: source + type: keyword + - name: title + type: keyword + - name: user_name + type: keyword + - name: uuid + type: keyword diff --git a/packages/axonius/elasticsearch/transform/latest_user/fields/is-transform-source-false.yml b/packages/axonius/elasticsearch/transform/latest_user/fields/is-transform-source-false.yml new file mode 100644 index 00000000000..adcf9b1fa96 --- /dev/null +++ b/packages/axonius/elasticsearch/transform/latest_user/fields/is-transform-source-false.yml @@ -0,0 +1,4 @@ +- name: labels.is_transform_source + type: constant_keyword + value: 'false' + description: Indicates whether a user is in the raw source data stream, or in the latest destination index. diff --git a/packages/axonius/elasticsearch/transform/latest_user/manifest.yml b/packages/axonius/elasticsearch/transform/latest_user/manifest.yml new file mode 100644 index 00000000000..1d35e28177e --- /dev/null +++ b/packages/axonius/elasticsearch/transform/latest_user/manifest.yml @@ -0,0 +1,18 @@ +start: true +destination_index_template: + settings: + index: + sort: + field: + - '@timestamp' + order: + - desc + mappings: + dynamic: true + dynamic_templates: + - strings_as_keyword: + match_mapping_type: string + mapping: + ignore_above: 1024 + type: keyword + date_detection: true diff --git a/packages/axonius/elasticsearch/transform/latest_user/transform.yml b/packages/axonius/elasticsearch/transform/latest_user/transform.yml new file mode 100644 index 00000000000..49a65331641 --- /dev/null +++ b/packages/axonius/elasticsearch/transform/latest_user/transform.yml @@ -0,0 +1,37 @@ +# Use of "*" to use all namespaces defined. +source: + index: + - "logs-axonius.user-*" +dest: + index: "logs-axonius_latest.dest_user-1" + aliases: + - alias: "logs-axonius_latest.user" + move_on_creation: true +latest: + unique_key: + - event.dataset + - user.id + sort: "@timestamp" +description: >- + Latest Users from Axonius. As users get updated, this transform stores only the latest state of each user inside the destination index. Thus the transform's destination index contains only the latest state of the user. +frequency: 30s +settings: + # This is required to prevent the transform from clobbering the Fleet-managed mappings. + deduce_mappings: false + unattended: true +sync: + time: + field: "event.ingested" + # Updated to 120s because of refresh delay in Serverless. With default 60s, + # sometimes transform wouldn't process all documents. + delay: 120s +retention_policy: + time: + field: "event.ingested" + max_age: 24h +_meta: + managed: false + # Bump this version to delete, reinstall, and restart the transform during + # package installation. + fleet_transform_version: 0.1.0 + run_as_kibana_system: false diff --git a/packages/axonius/img/axonius-logo.svg b/packages/axonius/img/axonius-logo.svg index 7fd81b1eaad..4a7fe63c0f5 100644 --- a/packages/axonius/img/axonius-logo.svg +++ b/packages/axonius/img/axonius-logo.svg @@ -1,10 +1,3 @@ - - - - - - - - - + + diff --git a/packages/axonius/img/axonius-user-dashboard.png b/packages/axonius/img/axonius-user-dashboard.png new file mode 100644 index 00000000000..7bc72e9aa24 Binary files /dev/null and b/packages/axonius/img/axonius-user-dashboard.png differ diff --git a/packages/axonius/kibana/dashboard/axonius-cc6c1878-aa15-4765-a4d9-76eca1cc4078.json b/packages/axonius/kibana/dashboard/axonius-cc6c1878-aa15-4765-a4d9-76eca1cc4078.json new file mode 100644 index 00000000000..ef915d58b21 --- /dev/null +++ b/packages/axonius/kibana/dashboard/axonius-cc6c1878-aa15-4765-a4d9-76eca1cc4078.json @@ -0,0 +1,489 @@ +{ + "attributes": { + "controlGroupInput": { + "chainingSystem": "HIERARCHICAL", + "controlStyle": "oneLine", + "ignoreParentSettingsJSON": { + "ignoreFilters": false, + "ignoreQuery": false, + "ignoreTimerange": false, + "ignoreValidations": false + }, + "panelsJSON": {}, + "showApplySelections": false + }, + "description": "This dashboard shows Users collected by the Axonius Integration.", + "kibanaSavedObjectMeta": { + "searchSourceJSON": { + "filter": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "axonius.user" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "axonius.user" + } + } + }, + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "labels.is_transform_source", + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index", + "key": "labels.is_transform_source", + "negate": false, + "params": { + "query": "false" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "labels.is_transform_source": "false" + } + } + } + ], + "query": { + "language": "kuery", + "query": "" + } + } + }, + "optionsJSON": { + "hidePanelTitles": false, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false, + "useMargins": true + }, + "panelsJSON": [ + { + "embeddableConfig": { + "attributes": { + "references": [ + { + "id": "logs-*", + "name": "indexpattern-datasource-layer-72d89ae4-5fb9-4fff-8316-38587a70f491", + "type": "index-pattern" + } + ], + "state": { + "adHocDataViews": {}, + "datasourceStates": { + "formBased": { + "layers": { + "72d89ae4-5fb9-4fff-8316-38587a70f491": { + "columnOrder": [ + "d439c5fa-00fa-47a5-81e5-af449d0342f0", + "ea982f27-414d-4ddf-babd-6b0c3e674fdd" + ], + "columns": { + "d439c5fa-00fa-47a5-81e5-af449d0342f0": { + "customLabel": true, + "dataType": "string", + "isBucketed": true, + "label": "Role", + "operationType": "terms", + "params": { + "exclude": [], + "excludeIsRegex": false, + "include": [], + "includeIsRegex": false, + "missingBucket": false, + "orderBy": { + "columnId": "ea982f27-414d-4ddf-babd-6b0c3e674fdd", + "type": "column" + }, + "orderDirection": "desc", + "otherBucket": true, + "parentFormat": { + "id": "terms" + }, + "size": 10 + }, + "scale": "ordinal", + "sourceField": "user.roles" + }, + "ea982f27-414d-4ddf-babd-6b0c3e674fdd": { + "customLabel": true, + "dataType": "number", + "isBucketed": false, + "label": "User", + "operationType": "count", + "params": { + "emptyAsNull": false, + "format": { + "id": "number", + "params": { + "decimals": 0 + } + } + }, + "scale": "ratio", + "sourceField": "user.id" + } + }, + "incompleteColumns": {}, + "sampling": 1 + } + } + }, + "indexpattern": { + "layers": {} + }, + "textBased": { + "layers": {} + } + }, + "filters": [], + "internalReferences": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "axisTitlesVisibilitySettings": { + "x": true, + "yLeft": true, + "yRight": true + }, + "fittingFunction": "Linear", + "gridlinesVisibilitySettings": { + "x": true, + "yLeft": true, + "yRight": true + }, + "labelsOrientation": { + "x": 0, + "yLeft": 0, + "yRight": 0 + }, + "layers": [ + { + "accessors": [ + "ea982f27-414d-4ddf-babd-6b0c3e674fdd" + ], + "colorMapping": { + "assignments": [], + "colorMode": { + "type": "categorical" + }, + "paletteId": "eui_amsterdam_color_blind", + "specialAssignments": [ + { + "color": { + "type": "loop" + }, + "rule": { + "type": "other" + }, + "touched": false + } + ] + }, + "layerId": "72d89ae4-5fb9-4fff-8316-38587a70f491", + "layerType": "data", + "position": "top", + "seriesType": "bar_horizontal_stacked", + "showGridlines": false, + "xAccessor": "d439c5fa-00fa-47a5-81e5-af449d0342f0" + } + ], + "legend": { + "isVisible": true, + "position": "right", + "shouldTruncate": false + }, + "preferredSeriesType": "bar_stacked", + "tickLabelsVisibilitySettings": { + "x": true, + "yLeft": true, + "yRight": true + }, + "valueLabels": "hide" + } + }, + "title": "", + "type": "lens", + "visualizationType": "lnsXY" + }, + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "filters": [], + "query": { + "language": "kuery", + "query": "" + }, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false + }, + "gridData": { + "h": 15, + "i": "a78b4a88-730d-4f04-b0c3-3e4b5ac7df3e", + "w": 24, + "x": 0, + "y": 7 + }, + "panelIndex": "a78b4a88-730d-4f04-b0c3-3e4b5ac7df3e", + "title": "Users by Role", + "type": "lens" + }, + { + "embeddableConfig": { + "attributes": { + "references": [ + { + "id": "logs-*", + "name": "indexpattern-datasource-layer-8129a09a-0d6c-4adc-a437-7b2e56144661", + "type": "index-pattern" + } + ], + "state": { + "adHocDataViews": {}, + "datasourceStates": { + "formBased": { + "layers": { + "8129a09a-0d6c-4adc-a437-7b2e56144661": { + "columnOrder": [ + "794a47e8-cee9-450f-a72c-496e0313fd06", + "7c4ce11d-518b-42ae-afc1-5a927679a345" + ], + "columns": { + "794a47e8-cee9-450f-a72c-496e0313fd06": { + "customLabel": true, + "dataType": "string", + "isBucketed": true, + "label": "Source", + "operationType": "terms", + "params": { + "exclude": [], + "excludeIsRegex": false, + "include": [], + "includeIsRegex": false, + "missingBucket": false, + "orderBy": { + "columnId": "7c4ce11d-518b-42ae-afc1-5a927679a345", + "type": "column" + }, + "orderDirection": "desc", + "otherBucket": false, + "parentFormat": { + "id": "terms" + }, + "size": 10 + }, + "scale": "ordinal", + "sourceField": "axonius.user.source" + }, + "7c4ce11d-518b-42ae-afc1-5a927679a345": { + "customLabel": true, + "dataType": "number", + "isBucketed": false, + "label": "Count", + "operationType": "count", + "params": { + "emptyAsNull": false, + "format": { + "id": "number", + "params": { + "decimals": 0 + } + } + }, + "scale": "ratio", + "sourceField": "___records___" + } + }, + "incompleteColumns": {}, + "sampling": 1 + } + } + }, + "indexpattern": { + "layers": {} + }, + "textBased": { + "layers": {} + } + }, + "filters": [], + "internalReferences": [], + "query": { + "language": "kuery", + "query": "" + }, + "visualization": { + "columns": [ + { + "columnId": "794a47e8-cee9-450f-a72c-496e0313fd06" + }, + { + "columnId": "7c4ce11d-518b-42ae-afc1-5a927679a345" + } + ], + "layerId": "8129a09a-0d6c-4adc-a437-7b2e56144661", + "layerType": "data" + } + }, + "title": "", + "type": "lens", + "visualizationType": "lnsDatatable" + }, + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "filters": [], + "query": { + "language": "kuery", + "query": "" + }, + "syncColors": false, + "syncCursor": true, + "syncTooltips": false + }, + "gridData": { + "h": 15, + "i": "e5e76904-5943-44db-b3b4-cf6919e1292d", + "w": 24, + "x": 24, + "y": 7 + }, + "panelIndex": "e5e76904-5943-44db-b3b4-cf6919e1292d", + "title": "Top Sources", + "type": "lens" + }, + { + "embeddableConfig": { + "enhancements": { + "dynamicActions": { + "events": [] + } + }, + "savedVis": { + "data": { + "aggs": [], + "searchSource": { + "filter": [], + "query": { + "language": "kuery", + "query": "" + } + } + }, + "description": "", + "id": "", + "params": { + "fontSize": 12, + "markdown": "This dashboard provides a clear view of user activity collected from Axonius.\n\nIt includes a bar chart for Users by Role, giving a quick understanding of user distribution. A Top Sources table highlights where the user data is coming from. A saved search shows User Essential Details.\n\n**[Integration Page](/app/integrations/detail/axonius)**", + "openLinksInNewTab": false + }, + "title": "", + "type": "markdown", + "uiState": {} + } + }, + "gridData": { + "h": 7, + "i": "a6a31baa-4811-4a51-97d2-2680c69e0c88", + "w": 48, + "x": 0, + "y": 0 + }, + "panelIndex": "a6a31baa-4811-4a51-97d2-2680c69e0c88", + "title": "Overview", + "type": "visualization" + }, + { + "embeddableConfig": { + "description": "", + "enhancements": { + "dynamicActions": { + "events": [] + } + } + }, + "gridData": { + "h": 17, + "i": "adc01019-216a-4a74-80ba-0973092bc421", + "w": 48, + "x": 0, + "y": 22 + }, + "panelIndex": "adc01019-216a-4a74-80ba-0973092bc421", + "panelRefName": "panel_adc01019-216a-4a74-80ba-0973092bc421", + "title": "[Logs Axonius] User Essential Details", + "type": "search" + } + ], + "timeRestore": false, + "title": "[Logs Axonius] User", + "version": 3 + }, + "coreMigrationVersion": "8.8.0", + "created_at": "2025-12-15T08:28:20.518Z", + "id": "axonius-cc6c1878-aa15-4765-a4d9-76eca1cc4078", + "references": [ + { + "id": "logs-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index", + "type": "index-pattern" + }, + { + "id": "axonius-355d0bbf-7a56-41b1-aa19-d23b85e07d99", + "name": "adc01019-216a-4a74-80ba-0973092bc421:panel_adc01019-216a-4a74-80ba-0973092bc421", + "type": "search" + }, + { + "id": "logs-*", + "name": "a78b4a88-730d-4f04-b0c3-3e4b5ac7df3e:indexpattern-datasource-layer-72d89ae4-5fb9-4fff-8316-38587a70f491", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "e5e76904-5943-44db-b3b4-cf6919e1292d:indexpattern-datasource-layer-8129a09a-0d6c-4adc-a437-7b2e56144661", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index", + "type": "index-pattern" + } + ], + "type": "dashboard", + "typeMigrationVersion": "10.2.0", + "updated_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0" +} \ No newline at end of file diff --git a/packages/axonius/kibana/search/axonius-355d0bbf-7a56-41b1-aa19-d23b85e07d99.json b/packages/axonius/kibana/search/axonius-355d0bbf-7a56-41b1-aa19-d23b85e07d99.json new file mode 100644 index 00000000000..29619f87f52 --- /dev/null +++ b/packages/axonius/kibana/search/axonius-355d0bbf-7a56-41b1-aa19-d23b85e07d99.json @@ -0,0 +1,102 @@ +{ + "attributes": { + "columns": [ + "user.id", + "user.full_name", + "user.email", + "axonius.user.title", + "user.name" + ], + "description": "", + "grid": {}, + "hideChart": false, + "isTextBasedQuery": false, + "kibanaSavedObjectMeta": { + "searchSourceJSON": { + "filter": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "axonius.user" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "axonius.user" + } + } + }, + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "labels.is_transform_source", + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index", + "key": "labels.is_transform_source", + "negate": false, + "params": { + "query": "false" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "labels.is_transform_source": "false" + } + } + } + ], + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.index", + "query": { + "language": "kuery", + "query": "" + } + } + }, + "sort": [ + [ + "@timestamp", + "desc" + ] + ], + "timeRestore": false, + "title": "[Logs Axonius] User Essential Details" + }, + "coreMigrationVersion": "8.8.0", + "created_at": "2025-12-15T08:32:32.285Z", + "created_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", + "id": "axonius-355d0bbf-7a56-41b1-aa19-d23b85e07d99", + "references": [ + { + "id": "logs-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[1].meta.index", + "type": "index-pattern" + } + ], + "type": "search", + "typeMigrationVersion": "10.5.0", + "updated_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0" +} \ No newline at end of file diff --git a/packages/axonius/kibana/search/axonius-723a9fbe-5e79-4c85-b6c8-486aa02fd95c.json b/packages/axonius/kibana/search/axonius-723a9fbe-5e79-4c85-b6c8-486aa02fd95c.json new file mode 100644 index 00000000000..f2f50178ad3 --- /dev/null +++ b/packages/axonius/kibana/search/axonius-723a9fbe-5e79-4c85-b6c8-486aa02fd95c.json @@ -0,0 +1,75 @@ +{ + "attributes": { + "columns": [ + "user.id", + "user.full_name", + "user.email", + "axonius.user.title", + "user.name" + ], + "description": "", + "grid": {}, + "hideChart": false, + "isTextBasedQuery": false, + "kibanaSavedObjectMeta": { + "searchSourceJSON": { + "filter": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "field": "data_stream.dataset", + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", + "key": "data_stream.dataset", + "negate": false, + "params": { + "query": "axonius.user" + }, + "type": "phrase" + }, + "query": { + "match_phrase": { + "data_stream.dataset": "axonius.user" + } + } + } + ], + "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.index", + "query": { + "language": "kuery", + "query": "" + } + } + }, + "sort": [ + [ + "@timestamp", + "desc" + ] + ], + "timeRestore": false, + "title": "[Logs Axonius] User Essential Details" + }, + "coreMigrationVersion": "8.8.0", + "created_at": "2025-11-24T05:39:49.780Z", + "created_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", + "id": "axonius-723a9fbe-5e79-4c85-b6c8-486aa02fd95c", + "references": [ + { + "id": "logs-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + }, + { + "id": "logs-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", + "type": "index-pattern" + } + ], + "type": "search", + "typeMigrationVersion": "10.5.0", + "updated_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0" +} \ No newline at end of file diff --git a/packages/axonius/manifest.yml b/packages/axonius/manifest.yml index 95e2177305a..5f3d86eb61c 100644 --- a/packages/axonius/manifest.yml +++ b/packages/axonius/manifest.yml @@ -8,7 +8,7 @@ categories: - security conditions: kibana: - version: ^8.18.0 || ^9.1.0 + version: ^8.19.10 || ~9.1.10 || ~9.2.4 || ^9.3.1 elastic: subscription: basic screenshots: @@ -16,6 +16,10 @@ screenshots: title: Adapter Dashboard size: 600x600 type: image/png + - src: /img/axonius-user-dashboard.png + title: User Dashboard + size: 600x600 + type: image/png icons: - src: /img/axonius-logo.svg title: Axonius Logo