OpenSearch/Wazuh Indexer Setup and Management Guide
This document provides instructions for setting up, configuring, and managing an OpenSearch cluster that serves as a Wazuh indexer. It covers installation, backup procedures, configuration paths, and basic health checks.
System Overview
The setup consists of:
- OpenSearch 2.11.1+ (latest stable) serving as a Wazuh indexer
- Compatible with Wazuh 4.7.x and 4.8.x
- Single-node cluster configuration (with multi-node scaling options)
- Security plugin enabled with admin authentication
Updated Installation Process (2025)
Prerequisites
-
Hardware Requirements:
- Minimum: 8GB RAM, 4 CPU cores, 100GB SSD
- Recommended: 16GB RAM, 8 CPU cores, 500GB NVMe SSD
- Enterprise: 32GB+ RAM, 16+ CPU cores, 1TB+ NVMe SSD in RAID configuration
-
Software Requirements:
- Ubuntu 22.04 LTS or RHEL 8.x/9.x
- Java 11 or 17 (OpenJDK recommended)
- Python 3.8+ for management scripts
Quick Installation Script
#!/bin/bash# OpenSearch/Wazuh Indexer Quick Setup Script - 2025
# Set version variablesOPENSEARCH_VERSION="2.11.1"WAZUH_VERSION="4.8.0"
# Update systemsudo apt-get update && sudo apt-get upgrade -y
# Install dependenciessudo apt-get install -y curl wget unzip apt-transport-https ca-certificates gnupg lsb-release
# Install Javasudo apt-get install -y openjdk-11-jdk
# Set JAVA_HOMEecho "export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64" | sudo tee -a /etc/environmentsource /etc/environment
# Download and install OpenSearchwget https://artifacts.opensearch.org/releases/bundle/opensearch/${OPENSEARCH_VERSION}/opensearch-${OPENSEARCH_VERSION}-linux-x64.tar.gztar -xzf opensearch-${OPENSEARCH_VERSION}-linux-x64.tar.gzsudo mv opensearch-${OPENSEARCH_VERSION} /opt/opensearch
# Configure system limitsecho "opensearch soft nofile 65536" | sudo tee -a /etc/security/limits.confecho "opensearch hard nofile 65536" | sudo tee -a /etc/security/limits.confecho "opensearch soft memlock unlimited" | sudo tee -a /etc/security/limits.confecho "opensearch hard memlock unlimited" | sudo tee -a /etc/security/limits.conf
# Configure sysctlecho "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.confsudo sysctl -p
# Create opensearch usersudo useradd -m -s /bin/bash opensearchsudo chown -R opensearch:opensearch /opt/opensearch
# Create necessary directoriessudo mkdir -p /var/log/opensearchsudo mkdir -p /var/lib/opensearchsudo chown -R opensearch:opensearch /var/log/opensearchsudo chown -R opensearch:opensearch /var/lib/opensearch
Directory Structure
The key directories and configuration files are:
/opt/opensearch/ # Main installation directory├── config/ # Configuration files│ ├── opensearch.yml # Main configuration│ ├── jvm.options # JVM settings│ ├── log4j2.properties # Logging configuration│ └── opensearch-security/ # Security plugin configs├── logs/ # Log files├── data/ # Index data└── plugins/ # Installed plugins
/etc/systemd/system/opensearch.service # Systemd service file/var/log/opensearch/ # Alternative log location/var/lib/opensearch/ # Alternative data location
Configuration
1. Basic OpenSearch Configuration
Edit /opt/opensearch/config/opensearch.yml
:
# Cluster Settingscluster.name: wazuh-clusternode.name: wazuh-node-1
# Network Settingsnetwork.host: 0.0.0.0http.port: 9200transport.port: 9300
# Discovery Settings (for single node)discovery.type: single-node
# Path Settingspath.data: /var/lib/opensearchpath.logs: /var/log/opensearch
# Memory Lockbootstrap.memory_lock: true
# Security Settingsplugins.security.ssl.transport.pemcert_filepath: esnode.pemplugins.security.ssl.transport.pemkey_filepath: esnode-key.pemplugins.security.ssl.transport.pemtrustedcas_filepath: root-ca.pemplugins.security.ssl.transport.enforce_hostname_verification: falseplugins.security.ssl.http.enabled: trueplugins.security.ssl.http.pemcert_filepath: esnode.pemplugins.security.ssl.http.pemkey_filepath: esnode-key.pemplugins.security.ssl.http.pemtrustedcas_filepath: root-ca.pemplugins.security.allow_unsafe_democertificates: trueplugins.security.allow_default_init_securityindex: trueplugins.security.authcz.admin_dn: - CN=admin,OU=UNIT,O=ORG,L=CITY,ST=STATE,C=USplugins.security.audit.type: internal_opensearchplugins.security.enable_snapshot_restore_privilege: trueplugins.security.check_snapshot_restore_write_privileges: trueplugins.security.restapi.roles_enabled: ["all_access", "security_rest_api_access"]plugins.security.system_indices.enabled: trueplugins.security.system_indices.indices: [".opendistro-*", ".opensearch-*", ".kibana*", ".wazuh*"]
2. JVM Configuration
Edit /opt/opensearch/config/jvm.options
:
# Heap size (set to 50% of available RAM, max 32GB)-Xms8g-Xmx8g
# GC configuration-XX:+UseG1GC-XX:G1ReservePercent=25-XX:InitiatingHeapOccupancyPercent=30
# GC logging-XX:+PrintGCDetails-XX:+PrintGCDateStamps-XX:+PrintTenuringDistribution-XX:+PrintGCApplicationStoppedTime
# Error handling-XX:+ExitOnOutOfMemoryError
3. Systemd Service Configuration
Create /etc/systemd/system/opensearch.service
:
[Unit]Description=OpenSearchDocumentation=https://opensearch.org/docs/Wants=network-online.targetAfter=network-online.target
[Service]Type=notifyRuntimeDirectory=opensearchPrivateTmp=trueEnvironment=OPENSEARCH_HOME=/opt/opensearchEnvironment=OPENSEARCH_PATH_CONF=/opt/opensearch/configEnvironment=JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
WorkingDirectory=/opt/opensearch
User=opensearchGroup=opensearch
ExecStart=/opt/opensearch/bin/opensearch
StandardOutput=journalStandardError=inherit
LimitNOFILE=65536LimitNPROC=4096LimitAS=infinityLimitFSIZE=infinityLimitMEMLOCK=infinity
TimeoutStopSec=0KillSignal=SIGTERMKillMode=processSendSIGKILL=noSuccessExitStatus=143
[Install]WantedBy=multi-user.target
Enable and start the service:
sudo systemctl daemon-reloadsudo systemctl enable opensearchsudo systemctl start opensearch
Security Configuration
1. Generate SSL Certificates
#!/bin/bash# Generate SSL certificates for OpenSearch
cd /opt/opensearch/config/
# Generate root CAopenssl genrsa -out root-ca-key.pem 2048openssl req -new -x509 -sha256 -key root-ca-key.pem -out root-ca.pem -days 730 \ -subj "/C=US/ST=STATE/L=CITY/O=ORG/OU=UNIT/CN=root"
# Generate admin certopenssl genrsa -out admin-key-temp.pem 2048openssl pkcs8 -inform PEM -outform PEM -in admin-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out admin-key.pemopenssl req -new -key admin-key.pem -out admin.csr \ -subj "/C=US/ST=STATE/L=CITY/O=ORG/OU=UNIT/CN=admin"openssl x509 -req -in admin.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out admin.pem -days 730
# Generate node certopenssl genrsa -out esnode-key-temp.pem 2048openssl pkcs8 -inform PEM -outform PEM -in esnode-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out esnode-key.pemopenssl req -new -key esnode-key.pem -out esnode.csr \ -subj "/C=US/ST=STATE/L=CITY/O=ORG/OU=UNIT/CN=node1"openssl x509 -req -in esnode.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out esnode.pem -days 730
# Clean uprm admin-key-temp.pem esnode-key-temp.pem admin.csr esnode.csr
# Set permissionschown opensearch:opensearch *.pemchmod 600 *-key.pemchmod 644 *.pem
2. Initialize Security
cd /opt/opensearch/plugins/opensearch-security/tools/sudo -u opensearch ./securityadmin.sh -cd ../securityconfig/ -icl -nhnv \ -cacert /opt/opensearch/config/root-ca.pem \ -cert /opt/opensearch/config/admin.pem \ -key /opt/opensearch/config/admin-key.pem
3. Create Wazuh User
# Generate password hashWAZUH_PASSWORD="MySecurePassword123!"HASH=$(sh /opt/opensearch/plugins/opensearch-security/tools/hash.sh -p "$WAZUH_PASSWORD")
# Create internal usercurl -XPUT https://localhost:9200/_plugins/_security/api/internalusers/wazuh \ -u admin:admin \ -k \ -H 'Content-Type: application/json' \ -d '{ "password": "'$WAZUH_PASSWORD'", "backend_roles": ["wazuh_admin"], "attributes": { "attribute1": "value1" }}'
# Create rolecurl -XPUT https://localhost:9200/_plugins/_security/api/roles/wazuh_admin \ -u admin:admin \ -k \ -H 'Content-Type: application/json' \ -d '{ "cluster_permissions": ["cluster_all"], "index_permissions": [{ "index_patterns": ["wazuh-*", ".wazuh*"], "allowed_actions": ["indices_all"] }]}'
# Map user to rolecurl -XPUT https://localhost:9200/_plugins/_security/api/rolesmapping/wazuh_admin \ -u admin:admin \ -k \ -H 'Content-Type: application/json' \ -d '{ "backend_roles": ["wazuh_admin"], "users": ["wazuh"]}'
Performance Tuning
1. Index Settings
# Create index template for Wazuh indicescurl -XPUT https://localhost:9200/_index_template/wazuh-template \ -u admin:admin \ -k \ -H 'Content-Type: application/json' \ -d '{ "index_patterns": ["wazuh-alerts-*", "wazuh-archives-*"], "template": { "settings": { "index": { "number_of_shards": 3, "number_of_replicas": 0, "refresh_interval": "5s", "translog.durability": "async", "translog.sync_interval": "5s", "codec": "best_compression" } }, "mappings": { "dynamic_templates": [{ "strings_as_keywords": { "match_mapping_type": "string", "mapping": { "type": "keyword", "ignore_above": 1024 } } }] } }, "priority": 1}'
2. Shard Allocation Settings
# Configure shard allocationcurl -XPUT https://localhost:9200/_cluster/settings \ -u admin:admin \ -k \ -H 'Content-Type: application/json' \ -d '{ "persistent": { "cluster.routing.allocation.disk.threshold_enabled": true, "cluster.routing.allocation.disk.watermark.low": "85%", "cluster.routing.allocation.disk.watermark.high": "90%", "cluster.routing.allocation.disk.watermark.flood_stage": "95%", "indices.breaker.total.limit": "75%", "indices.breaker.request.limit": "60%", "indices.breaker.fielddata.limit": "40%" }}'
Monitoring and Health Checks
1. Cluster Health Script
Create /opt/opensearch/scripts/health_check.sh
:
#!/bin/bash# OpenSearch Health Check Script
OPENSEARCH_URL="https://localhost:9200"AUTH="admin:admin"
echo "=== OpenSearch Cluster Health ==="curl -s -k -u $AUTH "$OPENSEARCH_URL/_cluster/health?pretty"
echo -e "\n=== Node Statistics ==="curl -s -k -u $AUTH "$OPENSEARCH_URL/_nodes/stats/os,jvm,indices?pretty" | \ jq '.nodes[] | { name: .name, cpu_percent: .os.cpu.percent, memory_used_percent: .os.mem.used_percent, heap_used_percent: .jvm.mem.heap_used_percent, disk_used: .indices.store.size_in_bytes }'
echo -e "\n=== Index Statistics ==="curl -s -k -u $AUTH "$OPENSEARCH_URL/_cat/indices?v&h=index,docs.count,store.size,health,status&s=index"
echo -e "\n=== Pending Tasks ==="curl -s -k -u $AUTH "$OPENSEARCH_URL/_cluster/pending_tasks?pretty"
echo -e "\n=== Thread Pool Stats ==="curl -s -k -u $AUTH "$OPENSEARCH_URL/_cat/thread_pool?v&h=name,active,queue,rejected"
2. Automated Monitoring
Create /opt/opensearch/scripts/monitor.py
:
#!/usr/bin/env python3import requestsimport jsonimport smtplibfrom email.mime.text import MIMETextfrom datetime import datetimeimport urllib3urllib3.disable_warnings()
# ConfigurationOPENSEARCH_URL = "https://localhost:9200"AUTH = ("admin", "admin")THRESHOLDS = { "heap_percent": 85, "disk_percent": 85, "cpu_percent": 90}ALERT_EMAIL = "admin@example.com"SMTP_SERVER = "localhost"
def check_cluster_health(): response = requests.get( f"{OPENSEARCH_URL}/_cluster/health", auth=AUTH, verify=False ) health = response.json()
alerts = [] if health['status'] != 'green': alerts.append(f"Cluster status is {health['status']}")
return alerts
def check_node_stats(): response = requests.get( f"{OPENSEARCH_URL}/_nodes/stats", auth=AUTH, verify=False ) stats = response.json()
alerts = [] for node_id, node in stats['nodes'].items(): name = node['name'] heap_percent = node['jvm']['mem']['heap_used_percent']
if heap_percent > THRESHOLDS['heap_percent']: alerts.append(f"Node {name}: Heap usage is {heap_percent}%")
return alerts
def send_alerts(alerts): if not alerts: return
body = "OpenSearch Alerts:\n\n" + "\n".join(alerts) msg = MIMEText(body) msg['Subject'] = f"OpenSearch Alert - {datetime.now()}" msg['From'] = "opensearch@example.com" msg['To'] = ALERT_EMAIL
with smtplib.SMTP(SMTP_SERVER) as s: s.send_message(msg)
if __name__ == "__main__": all_alerts = [] all_alerts.extend(check_cluster_health()) all_alerts.extend(check_node_stats())
if all_alerts: print("Alerts found:") for alert in all_alerts: print(f" - {alert}") send_alerts(all_alerts) else: print("All checks passed")
Backup and Recovery
1. Snapshot Repository Setup
# Create snapshot repositorycurl -XPUT https://localhost:9200/_snapshot/wazuh_backup \ -u admin:admin \ -k \ -H 'Content-Type: application/json' \ -d '{ "type": "fs", "settings": { "location": "/var/lib/opensearch/snapshots", "compress": true }}'
# Create snapshot directorysudo mkdir -p /var/lib/opensearch/snapshotssudo chown opensearch:opensearch /var/lib/opensearch/snapshots
2. Automated Backup Script
Create /opt/opensearch/scripts/backup.sh
:
#!/bin/bash# OpenSearch Backup Script
OPENSEARCH_URL="https://localhost:9200"AUTH="admin:admin"REPO_NAME="wazuh_backup"SNAPSHOT_NAME="snapshot_$(date +%Y%m%d_%H%M%S)"RETENTION_DAYS=7
echo "Creating snapshot: $SNAPSHOT_NAME"
# Create snapshotcurl -XPUT "$OPENSEARCH_URL/_snapshot/$REPO_NAME/$SNAPSHOT_NAME?wait_for_completion=false" \ -u $AUTH \ -k \ -H 'Content-Type: application/json' \ -d '{ "indices": "wazuh-*", "ignore_unavailable": true, "include_global_state": false}'
# Check snapshot statussleep 5while true; do STATUS=$(curl -s -k -u $AUTH "$OPENSEARCH_URL/_snapshot/$REPO_NAME/$SNAPSHOT_NAME" | \ jq -r '.snapshots[0].state')
if [ "$STATUS" = "SUCCESS" ]; then echo "Snapshot completed successfully" break elif [ "$STATUS" = "FAILED" ]; then echo "Snapshot failed!" exit 1 else echo "Snapshot in progress..." sleep 10 fidone
# Clean up old snapshotsecho "Cleaning up old snapshots..."CUTOFF_DATE=$(date -d "$RETENTION_DAYS days ago" +%Y%m%d)
curl -s -k -u $AUTH "$OPENSEARCH_URL/_snapshot/$REPO_NAME/_all" | \ jq -r '.snapshots[].snapshot' | \ while read snapshot; do SNAPSHOT_DATE=$(echo $snapshot | grep -oP 'snapshot_\K\d{8}') if [ "$SNAPSHOT_DATE" -lt "$CUTOFF_DATE" ]; then echo "Deleting old snapshot: $snapshot" curl -XDELETE "$OPENSEARCH_URL/_snapshot/$REPO_NAME/$snapshot" \ -u $AUTH -k fi done
3. Restore Procedure
# List available snapshotscurl -s -k -u admin:admin \ "https://localhost:9200/_snapshot/wazuh_backup/_all?pretty"
# Restore specific snapshotcurl -XPOST "https://localhost:9200/_snapshot/wazuh_backup/snapshot_20250105_120000/_restore" \ -u admin:admin \ -k \ -H 'Content-Type: application/json' \ -d '{ "indices": "wazuh-alerts-*", "ignore_unavailable": true, "include_global_state": false, "rename_pattern": "(.+)", "rename_replacement": "restored_$1"}'
Troubleshooting
Common Issues and Solutions
- High Memory Usage
# Check memory usagecurl -s -k -u admin:admin \ "https://localhost:9200/_nodes/stats/jvm?pretty" | \ jq '.nodes[].jvm.mem'
# Clear field data cachecurl -XPOST -k -u admin:admin \ "https://localhost:9200/_cache/clear?fielddata=true"
- Slow Queries
# Enable slow logcurl -XPUT "https://localhost:9200/wazuh-alerts-*/_settings" \ -u admin:admin -k \ -H 'Content-Type: application/json' \ -d '{ "index.search.slowlog.threshold.query.warn": "10s", "index.search.slowlog.threshold.query.info": "5s", "index.search.slowlog.threshold.query.debug": "2s", "index.search.slowlog.level": "info"}'
- Disk Space Issues
# Check disk usagecurl -s -k -u admin:admin \ "https://localhost:9200/_cat/allocation?v&h=node,disk.used,disk.avail,disk.percent"
# Force merge old indicescurl -XPOST -k -u admin:admin \ "https://localhost:9200/wazuh-alerts-4.x-2024.*/_forcemerge?max_num_segments=1"
Log Locations
- OpenSearch logs:
/var/log/opensearch/wazuh-cluster.log
- GC logs:
/var/log/opensearch/gc.log
- Slow logs:
/var/log/opensearch/wazuh-cluster_index_search_slowlog.log
Integration with Wazuh
Configure Wazuh Manager
Edit /var/ossec/etc/ossec.conf
:
<ossec_config> <indexer> <enabled>yes</enabled> <hosts> <host>https://your-opensearch-host:9200</host> </hosts> <username>wazuh</username> <password>MySecurePassword123!</password> <ssl> <certificate_authorities> <ca>/etc/filebeat/certs/root-ca.pem</ca> </certificate_authorities> <certificate>/etc/filebeat/certs/filebeat.pem</certificate> <key>/etc/filebeat/certs/filebeat-key.pem</key> </ssl> </indexer></ossec_config>
Configure Filebeat
Edit /etc/filebeat/filebeat.yml
:
output.elasticsearch: hosts: ["https://your-opensearch-host:9200"] protocol: "https" username: "wazuh" password: "MySecurePassword123!" ssl.certificate_authorities: ["/etc/filebeat/certs/root-ca.pem"] ssl.certificate: "/etc/filebeat/certs/filebeat.pem" ssl.key: "/etc/filebeat/certs/filebeat-key.pem" ssl.verification_mode: "none"
Maintenance Tasks
Daily Tasks
- Monitor cluster health and disk usage
- Check for failed shards
- Review slow query logs
Weekly Tasks
- Analyze index patterns and optimize mappings
- Review and update index lifecycle policies
- Check backup success rate
Monthly Tasks
- Update OpenSearch and plugins
- Review and optimize JVM settings
- Audit user permissions and access logs
- Performance benchmarking
Conclusion
This guide provides a comprehensive approach to deploying and managing OpenSearch as a Wazuh indexer. Regular monitoring, proper backup procedures, and performance optimization are key to maintaining a healthy and efficient SIEM infrastructure.
For more information, refer to: