OpenSearch - Hardened Search and Analytics Suite
by Lynxroute
OpenSearch 3.7.0 - CIS Level 1 hardened search + analytics suite on Ubuntu 24.04, SBOM + CIS
What is OpenSearch
OpenSearch is a community-driven, open-source suite for search, log analytics and observability, governed by the OpenSearch Software Foundation under the Linux Foundation and licensed Apache-2.0. This image runs the suite single-node on one host: the OpenSearch engine - a Java/Lucene distributed search and analytics engine that indexes JSON documents and serves a REST API - and OpenSearch Dashboards, the Node.js visualization and management UI. It powers full-text and vector search, log and event analytics, dashboards, alerting and anomaly detection, with role-based access control and TLS enforced by the bundled security plugin. Apache-2.0 across engine and Dashboards means the full stack is auditable, with no lock-in or SaaS fees.
Why self-host OpenSearch
Running OpenSearch on a VM you control keeps your indexed documents, logs and search analytics - often sensitive customer, application and security-event data - inside your own tenant rather than a managed search service. Self-hosting suits teams with data-residency requirements, organisations under GDPR, HIPAA or ISO 27001, and any product where indexed data must stay within your own perimeter with no per-query fees. Apache-2.0, fully auditable, no lock-in.
What this VM image adds
Security hardening:
- Per-instance TLS certificates - the security plugin's well-known demo certificates are regenerated at first launch (a fresh private certificate authority plus node and admin certificates); the demo certificates never reach your instance
- Random administrator password generated per instance at first launch - no default admin credential - stored in /root/opensearch-credentials.txt (mode 0600)
- REST API on port 9200 is TLS-encrypted and authenticated by the security plugin, so it is safe to expose for ingestion; the inter-node transport port 9300 is bound to 127.0.0.1 only
- Dashboards over HTTPS - Dashboards listens on 127.0.0.1:5601 and is reachable only through a TLS-terminating nginx on port 443, with a loading splash and readiness gate during startup
- JVM heap sized to the VM RAM and locked into memory; vm.max_map_count set so the engine starts reliably
- UFW firewall - TCP 443 (Dashboards) and TCP 9200 (REST API) open externally for buyer use, TCP 22 for SSH; all other inbound dropped; Azure IMDS and WireServer egress pre-configured
- fail2ban - SSH brute-force protection
- AppArmor - mandatory access control
- CVE scan - every image is scanned with Trivy before release
OS hardening (CIS Level 1):
- CIS Ubuntu 24.04 LTS Level 1 Benchmark via ansible-lockdown
- auditd for system call auditing of critical paths
- SSH hardening - PasswordAuthentication disabled, key-only access, PermitRootLogin no, LoginGraceTime 60
- Kernel hardening - SYN cookies, ASLR, rp_filter, kexec disabled, IPv6 off
- /tmp as tmpfs with nosuid, nodev, noexec
Compliance artifacts (inside the VM):
- SBOM - CycloneDX 1.6 at /etc/lynxroute/sbom.json with OpenSearch pinned by version, PURL, Apache-2.0 license, supplier, and hash
- CIS Conformance Report at /etc/lynxroute/cis-report.html (OpenSCAP, Azure tailoring profile, 0 FAIL rules)
- Tailored CIS profile at /usr/share/doc/lynxroute/CIS_TAILORED_PROFILE.md
- Operator credentials file at /root/opensearch-credentials.txt (mode 0600) with the admin password, the Dashboards HTTPS URL, and the REST API endpoint
Quick Start
- Deploy VM from Azure Marketplace (Standard_D4s_v3 recommended)
- Open NSG: TCP 443 and TCP 9200 from your trusted sources, TCP 22 from your management IPs only
- SSH: ssh -i key.pem azureuser@<PUBLIC_IP>, then sudo cat /root/opensearch-credentials.txt for the admin password
- Open https://<PUBLIC_IP>/ in your browser, accept the self-signed certificate warning, and log in to OpenSearch Dashboards as admin with the password from the credentials file
- Use the REST API over TLS with authentication: curl -k -u admin:<password> https://<PUBLIC_IP>:9200
The REST API runs over TLS on 9200 and Dashboards over HTTPS on 443; transport 9300 and Dashboards backend 5601 stay bound to localhost. On a single node, cluster health is yellow when an index requests replicas (no second node) - this is expected. Replace the self-signed certificate (or run sudo certbot --nginx) for production, then restart nginx.