Skip to content

[Armis] Initial release of the armis #13429

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

sharadcrest
Copy link
Contributor

Proposed commit message

The initial release includes alert, device, and vulnerability data streams,
along with associated dashboards and visualizations.

Armis fields are mapped to their corresponding ECS fields where possible.

Test samples were derived from live data samples, which were subsequently
sanitized.

Checklist

  • I have reviewed tips for building integrations and this pull request is aligned with them.
  • I have verified that all data streams collect metrics or logs.
  • I have added an entry to my package's changelog.yml file.
  • I have verified that Kibana version constraints are current according to guidelines.
  • I have verified that any added dashboard complies with Kibana's Dashboard good practices

How to test this PR locally

  • Clone integrations repo.
  • Install elastic package locally.
  • Start elastic stack using elastic-package.
  • Move to integrations/packages/armis directory.
  • Run the following command to run tests.

elastic-package test

--- Test results for package: armis - START ---
╭─────────┬───────────────┬───────────┬────────────────────────────────────────────────────────────────┬────────┬──────────────╮
│ PACKAGE │ DATA STREAM   │ TEST TYPE │ TEST NAME                                                      │ RESULT │ TIME ELAPSED │
├─────────┼───────────────┼───────────┼────────────────────────────────────────────────────────────────┼────────┼──────────────┤
│ armis   │               │ asset     │ dashboard armis-68592f5a-9c7b-4398-a723-510d5e48a8b1 is loaded │ PASS   │      1.534µs │
│ armis   │               │ asset     │ dashboard armis-8a59c91d-69fd-4cf4-ab75-e9205ecbd095 is loaded │ PASS   │        227ns │
│ armis   │               │ asset     │ dashboard armis-f988ffbb-80b9-42c2-8009-bbcc59d33347 is loaded │ PASS   │        217ns │
│ armis   │               │ asset     │ search armis-4f132e91-3d6d-4e05-b67a-f00b2e87b95d is loaded    │ PASS   │        318ns │
│ armis   │               │ asset     │ search armis-a231edf5-54ef-45ee-bcb1-cfe2a41ff33d is loaded    │ PASS   │        166ns │
│ armis   │               │ asset     │ search armis-b7925646-4f62-4db4-8779-8d9202575fdd is loaded    │ PASS   │        156ns │
│ armis   │ alert         │ asset     │ index_template logs-armis.alert is loaded                      │ PASS   │        114ns │
│ armis   │ alert         │ asset     │ ingest_pipeline logs-armis.alert-0.1.0 is loaded               │ PASS   │        179ns │
│ armis   │ device        │ asset     │ index_template logs-armis.device is loaded                     │ PASS   │        208ns │
│ armis   │ device        │ asset     │ ingest_pipeline logs-armis.device-0.1.0 is loaded              │ PASS   │         99ns │
│ armis   │ vulnerability │ asset     │ index_template logs-armis.vulnerability is loaded              │ PASS   │        229ns │
│ armis   │ vulnerability │ asset     │ ingest_pipeline logs-armis.vulnerability-0.1.0 is loaded       │ PASS   │        250ns │
╰─────────┴───────────────┴───────────┴────────────────────────────────────────────────────────────────┴────────┴──────────────╯
--- Test results for package: armis - END   ---
Done
Run pipeline tests for the package
--- Test results for package: armis - START ---
╭─────────┬───────────────┬───────────┬───────────────────────────────────────────────────┬────────┬──────────────╮
│ PACKAGE │ DATA STREAM   │ TEST TYPE │ TEST NAME                                         │ RESULT │ TIME ELAPSED │
├─────────┼───────────────┼───────────┼───────────────────────────────────────────────────┼────────┼──────────────┤
│ armis   │ alert         │ pipeline  │ (ingest pipeline warnings test-alert.log)         │ PASS   │  321.55827ms │
│ armis   │ alert         │ pipeline  │ test-alert.log                                    │ PASS   │ 138.557967ms │
│ armis   │ device        │ pipeline  │ (ingest pipeline warnings test-device.log)        │ PASS   │ 326.537572ms │
│ armis   │ device        │ pipeline  │ test-device.log                                   │ PASS   │ 137.515809ms │
│ armis   │ vulnerability │ pipeline  │ (ingest pipeline warnings test-vulnerability.log) │ PASS   │ 320.894811ms │
│ armis   │ vulnerability │ pipeline  │ test-vulnerability.log                            │ PASS   │ 197.328375ms │
╰─────────┴───────────────┴───────────┴───────────────────────────────────────────────────┴────────┴──────────────╯
--- Test results for package: armis - END   ---
Done
Run policy tests for the package
--- Test results for package: armis - START ---
No test results
--- Test results for package: armis - END   ---
Done
Run static tests for the package
--- Test results for package: armis - START ---
╭─────────┬───────────────┬───────────┬──────────────────────────┬────────┬──────────────╮
│ PACKAGE │ DATA STREAM   │ TEST TYPE │ TEST NAME                │ RESULT │ TIME ELAPSED │
├─────────┼───────────────┼───────────┼──────────────────────────┼────────┼──────────────┤
│ armis   │ alert         │ static    │ Verify sample_event.json │ PASS   │ 121.115611ms │
│ armis   │ device        │ static    │ Verify sample_event.json │ PASS   │ 111.266479ms │
│ armis   │ vulnerability │ static    │ Verify sample_event.json │ PASS   │ 118.070424ms │
╰─────────┴───────────────┴───────────┴──────────────────────────┴────────┴──────────────╯
--- Test results for package: armis - END   ---
Done
Run system tests for the package
2025/04/04 20:30:49  INFO License text found in "/home/devuser/bitbucket/integrations/LICENSE.txt" will be included in package
2025/04/04 20:31:31  INFO Write container logs to file: /home/devuser/bitbucket/integrations/build/container-logs/armis-1743778891265719894.log
2025/04/04 20:31:35  INFO Write container logs to file: /home/devuser/bitbucket/integrations/build/container-logs/elastic-agent-1743778895016525468.log
2025/04/04 20:32:20  INFO Write container logs to file: /home/devuser/bitbucket/integrations/build/container-logs/armis-1743778940482732779.log
2025/04/04 20:32:24  INFO Write container logs to file: /home/devuser/bitbucket/integrations/build/container-logs/elastic-agent-1743778944023020535.log
2025/04/04 20:33:08  INFO Write container logs to file: /home/devuser/bitbucket/integrations/build/container-logs/armis-1743778988505549996.log
2025/04/04 20:33:12  INFO Write container logs to file: /home/devuser/bitbucket/integrations/build/container-logs/elastic-agent-1743778992041042826.log
--- Test results for package: armis - START ---
╭─────────┬───────────────┬───────────┬───────────┬────────┬───────────────╮
│ PACKAGE │ DATA STREAM   │ TEST TYPE │ TEST NAME │ RESULT │  TIME ELAPSED │
├─────────┼───────────────┼───────────┼───────────┼────────┼───────────────┤
│ armis   │ alert         │ system    │ default   │ PASS   │ 37.506199742s │
│ armis   │ device        │ system    │ default   │ PASS   │  36.17114454s │
│ armis   │ vulnerability │ system    │ default   │ PASS   │ 36.128174346s │
╰─────────┴───────────────┴───────────┴───────────┴────────┴───────────────╯
--- Test results for package: armis - END   ---
Done

Related Issues

Screenshots

Browse Integration Armis
Integrations Armis

@sharadcrest sharadcrest requested a review from a team as a code owner April 4, 2025 15:47
@andrewkroh andrewkroh added dashboard Relates to a Kibana dashboard bug, enhancement, or modification. Integration:armis [Integration not found in source] Crest Contributions from Crest developement team. New Integration Issue or pull request for creating a new integration package. labels Apr 4, 2025
@kcreddy
Copy link
Contributor

kcreddy commented Apr 7, 2025

/test

@elastic-vault-github-plugin-prod

🚀 Benchmarks report

To see the full report comment with /test benchmark fullreport

@elasticmachine
Copy link

💚 Build Succeeded

@jsoriano jsoriano requested a review from a team April 7, 2025 09:47
@kcreddy kcreddy added the Team:Security-Service Integrations Security Service Integrations team [elastic/security-service-integrations] label Apr 8, 2025
@elasticmachine
Copy link

Pinging @elastic/security-service-integrations (Team:Security-Service Integrations)

Comment on lines +73 to +75
1. In the **alert data stream**, based on the documentation, we initially expected to use the `statusChangeTime` field for filtering updates. However, the `"after"` filter applies only to the primary `time` field from the alert endpoint and does not support filtering based on `statusChangeTime`. As a result, when an alert's status changes, the data collection process does not capture these updates.

2. In the **vulnerability data stream**, our filtering mechanism for the **vulnerability search API** relies specifically on the `lastDetected` field. This means that when a user takes action on a vulnerability and `lastDetected` updates, only then will the event for that vulnerability be retrieved. Initially, we assumed this field would always have a value and could be used as a cursor timestamp for fetching data between intervals. However, due to inconsistencies in the API response, we observed cases where `lastDetected` is `null`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you please share API docs via DM (if private) or the link (if public)?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also if the docs are public, please add a link to README.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don’t have public API documentation at the moment. We can share a PDF version with you via DM.

:
state.?cursor.last_timestamp,
},
"want_more": has(body.?data.next) && body.data.next != null,
Copy link
Contributor

Choose a reason for hiding this comment

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

Both conditions has(body.?data.next) && body.data.next != null are checking the same thing. Here body.data.next != null may not be required.

Copy link
Contributor

Choose a reason for hiding this comment

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

Same for other data streams if applicable

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The condition body.data.next != null is indeed necessary in this context. On the last page, body.data.next can have a value of null, and using only has(body.?data.next) would still return true for a null value. Therefore, the additional check ensures the logic handles this scenario correctly.

Copy link
Contributor

Choose a reason for hiding this comment

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

Are there any cases that it is not present? When does this happen? If it's always present, we don't need to use the has, or the optional types above, we can just compare against null.

"length": [string(state.page_size)],
"orderBy": ["time"],
?"from": has(state.offset) && state.offset != null ? optional.of([string(state.offset)]) : optional.none(),
"aql":["in:alerts " + "after:" + state.start_time]
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there documentation for this AQL?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can share the AQL documentation as a PDF via DM.

Comment on lines +20 to +21
"device-abc",
"server-xyz"
Copy link
Contributor

Choose a reason for hiding this comment

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

In live data, are these IPs/domains? Can they be added to related* or destination* ECS fields?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don’t have live data for this field; the values are just examples provided.

"469"
],
"friendly_name": "Unusual Network Scanning Activity",
"last_alert_update_time": "2025-03-29T02:50:06.124Z",
Copy link
Contributor

Choose a reason for hiding this comment

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

Whats the diff between last_alert_update_time and status_change_time and time?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  • time: Alert timestamp.
  • status_change_time: When the alert's status was last changed.
  • last_alert_update_time: We don't have live data for this field and are not sure what it represents.

"mac_address": "46-A7-4B-5D-B0-76",
"manufacturer": "test",
"model": "test",
"name": "49f9ef97_1b8",
Copy link
Contributor

Choose a reason for hiding this comment

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

In live data, do you see this field good to populate host.name?

Copy link
Contributor Author

@sharadcrest sharadcrest Apr 11, 2025

Choose a reason for hiding this comment

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

We have mapped names to host.name as it looks like super set of name in live data.

"host": {
"id": "469",
"ip": [
"175.16.199.0"
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you populate host.geo.*?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The ipAddress field may contain comma-separated IPs, so it's not ideal to map it directly to host.geo.*, which expects a single IP for accurate geolocation enrichment.

"tags": [
"Misconfigurations"
],
"type": "Servers",
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this "type": "Servers", makes more sense for host.type. or just use type_enum field.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We’ve already mapped category to host.type. Do we need to map the type field instead of category to host.type?

@@ -0,0 +1,34 @@
# Use of "*" to use all namespaces defined.
Copy link
Contributor

Choose a reason for hiding this comment

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

As part of https://docs.elastic.dev/security-solution/cloud-security/cdr/3p-dev-guide, we will be adding a transform later on for this data. So, we don't need a transform right now for vulnerability.

- host.id
sort: "@timestamp"
description: >-
Latest Devices from Armis. As devices get updated, this transform stores only the latest state of each device inside the destination index. Thus the transform's destination index contains only the latest state of the device.
Copy link
Contributor

Choose a reason for hiding this comment

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

I am curious about the use case of this transform and what we are trying to solve.
I believe you can get total hosts number using unique counts aggregation without having to use a latest transform.

Are there properties of hosts that get modified and the latest values of such properties are important to the users?

Copy link
Contributor Author

@sharadcrest sharadcrest Apr 9, 2025

Choose a reason for hiding this comment

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

Yes, whenever any property of a device is updated for a particular host ID, the lastSeen field is also updated in the same log entry. The updated properties are reflected alongside it.
That’s why we’ve added the transform to retain the latest state of each host ID based on the most recent updates.

@sharadcrest sharadcrest requested a review from kcreddy April 11, 2025 13:39
:
state.?cursor.last_timestamp,
},
"want_more": has(body.?data.next) && body.data.next != null,
Copy link
Contributor

Choose a reason for hiding this comment

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

Are there any cases that it is not present? When does this happen? If it's always present, we don't need to use the has, or the optional types above, we can just compare against null.

@sharadcrest
Copy link
Contributor Author

sharadcrest commented Apr 14, 2025

#13429 (comment)
Thanks for the suggestion! We had initially added this extra check as a best practice to guard against any edge cases. However, so far we haven’t encountered a scenario where the next value is missing in a 200 response. Given that, we're removing this additional check from each datastream to simplify the code.

@sharadcrest sharadcrest requested a review from efd6 April 14, 2025 12:18
Comment on lines +100 to +108
:
resp.StatusCode == 401 ?
{
"events": [{"message":"retry"}],
"is_token_valid": false,
"offset": has(state.offset) && state.offset != null ? state.offset : 0,
"want_more": true,
}
// Armis doesn't support multiple sessions per token; generate a new token on 401 (expired)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
:
resp.StatusCode == 401 ?
{
"events": [{"message":"retry"}],
"is_token_valid": false,
"offset": has(state.offset) && state.offset != null ? state.offset : 0,
"want_more": true,
}
// Armis doesn't support multiple sessions per token; generate a new token on 401 (expired)
: resp.StatusCode == 401 ?
// Armis doesn't support multiple sessions per token; generate a new token on 401 (expired).
{
"events": [{"message":"retry"}],
"is_token_valid": false,
"offset": has(state.offset) && state.offset != null ? state.offset : 0,
"want_more": true,
}

(similar below)

@piyush-elastic
Copy link
Contributor

Hey @kcreddy, @efd6, @james-elastic - Just a quick update — there might be a delay in addressing the comments on this PR as we’ve been in touch with the Armis team and shared our observations. They are considering incorporating the changes as part of a future enhancement, which we can expect in a week or two., so we are currently not prioritising this.

@kcreddy
Copy link
Contributor

kcreddy commented Apr 15, 2025

Hey @kcreddy, @efd6, @james-elastic - Just a quick update — there might be a delay in addressing the comments on this PR as we’ve been in touch with the Armis team and shared our observations. They are considering incorporating the changes as part of a future enhancement, which we can expect in a week or two., so we are currently not prioritising this.

@piyush-elastic, can you make the PR as draft in the mean time?

@sharadcrest sharadcrest marked this pull request as draft April 15, 2025 10:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Crest Contributions from Crest developement team. dashboard Relates to a Kibana dashboard bug, enhancement, or modification. Integration:armis [Integration not found in source] New Integration Issue or pull request for creating a new integration package. Team:Security-Service Integrations Security Service Integrations team [elastic/security-service-integrations]
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[New Integration] Armis
6 participants