Elastic and OpenSearch
Works with: Elasticsearch 8 and 9 (self-managed or Elastic Cloud, including Elastic Security), OpenSearch 2 and 3 (including Amazon OpenSearch Service with a master user), and the Wazuh indexer.
SafeHanded writes with the _bulk API. Each event has a fixed document id (<org_id>-<seq>), so an
event sent twice is stored once.
Elasticsearch / Elastic Cloud
Section titled “Elasticsearch / Elastic Cloud”-
Create an API key that can only write SafeHanded events. In Kibana → Dev Tools:
POST /_security/api_key{"name": "safehanded","role_descriptors": {"safehanded_writer": {"cluster": ["monitor"],"indices": [{ "names": ["logs-safehanded.audit-*"], "privileges": ["create_doc", "auto_configure"] }]}}}Copy the encoded value from the response. Kibana’s Stack Management → API keys works too, with the same role descriptor.
-
Copy your Elasticsearch endpoint (Elastic Cloud: the deployment’s overview page).
-
In SafeHanded: Settings → Integrations → Connect → Elastic / OpenSearch. Enter the URL, choose API key, paste the encoded key, and leave Index or data stream blank. Save, then Send test event.
Events go to the data stream logs-safehanded.audit-default, which Elasticsearch’s built-in logs
template accepts. In Kibana, create a data view for logs-safehanded.audit-*. Each document has
@timestamp set to when the event happened.
OpenSearch and Wazuh
Section titled “OpenSearch and Wazuh”- Create an internal user, e.g.
safehanded, with a role that hascreate_index,writeandcreate_docon the index patternsafehanded-audit*. - In SafeHanded choose Username and password, and enter the cluster URL, the user, and
safehanded-auditas the index.
Troubleshooting
Section titled “Troubleshooting”- Rejected the credentials (HTTP 401/403): wrong key or password, or the role lacks
create_doc/auto_configureon the target. - The destination refused an event (mapper_parsing_exception …): an existing mapping on the index conflicts with SafeHanded’s fields. Use a new index or data stream name.
- Re-sent events are stored once only while they land in the same index. After a data stream rolls over,
a rare re-send can be stored twice. De-duplicate on
org_id+seqif that matters.