Jaeger - Hardened Distributed Tracing (OpenTelemetry)
بواسطة Lynxroute
Jaeger 2.21.0 - CIS Level 1 hardened distributed tracing on Ubuntu 24.04 LTS, SBOM + CIS
What is Jaeger
Jaeger is a CNCF-graduated, open-source distributed tracing platform used to monitor and troubleshoot transactions across microservices. This image runs Jaeger v2 as a single self-contained Go binary in all-in-one mode: an OpenTelemetry-native collector, a query service and a React web UI in one process. Applications send spans over OTLP - gRPC on 4317, HTTP on 4318 - and operators search traces, inspect service dependency graphs, view Gantt-style timelines and perform root-cause and latency analysis in the UI. Traces are persisted locally with an embedded Badger key-value store, so they survive restarts and reboots with a configurable retention window. Any OpenTelemetry SDK or Collector can export to it, and the same image scales out to Cassandra or Elasticsearch backends when volume grows. Apache-2.0 license, fully auditable, no vendor lock-in.
Why self-host Jaeger
Running Jaeger on a VM you control keeps every span - which often carries request payloads, user identifiers, hostnames and infrastructure topology - inside your own tenant rather than a third-party observability service. Self-hosting suits teams with data residency requirements, organisations operating under GDPR or ISO 27001, and any architecture where the trace store must sit next to the workloads it observes with no per-span ingest fees. This single-node image targets development, testing and small-team environments; for high-volume production point Jaeger at a Cassandra or Elasticsearch backend.
What this VM image adds
Security hardening:
- HTTP Basic Auth credential generated at first boot - a unique password is created per instance and stored in /root/jaeger-credentials.txt; the Jaeger UI has no native authentication
- Nginx TLS reverse proxy on port 443 - the query UI is reached only through Nginx, self-signed at build, one command to a CA-signed certificate
- Query UI, query gRPC, health and metrics endpoints bound to 127.0.0.1 only - never exposed directly; only OTLP 4317/4318 and HTTPS 443 are reachable
- Persistent Badger storage - traces survive restarts and reboots, not the default ephemeral in-memory store
- certbot and the Nginx plugin pre-installed - one-command CA-signed HTTPS to replace the self-signed certificate
- UFW firewall - SSH on 22, HTTPS 443, and OTLP 4317/4318 only; 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 Jaeger pinned by version, PURL, Apache-2.0 license, supplier, and SHA-256 hash of the binary
- 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
- Basic Auth credentials file at /root/jaeger-credentials.txt with the admin username and password
Quick Start
- Deploy VM from Azure Marketplace (Standard_D2s_v3 recommended)
- SSH: ssh -i key.pem azureuser@<PUBLIC_IP>, then sudo cat /root/jaeger-credentials.txt for the admin Basic Auth password
- Open NSG: TCP 443 from your trusted sources and TCP 22 from your management IPs only; open TCP 4317 and 4318 only to the subnets of the services that send traces
- Open https://<PUBLIC_IP>/ in your browser, accept the self-signed certificate warning, and authenticate as admin to reach the Jaeger UI
- Point your application's OpenTelemetry exporter at OTLP gRPC <PUBLIC_IP>:4317 or OTLP HTTP http://<PUBLIC_IP>:4318; traces appear in the UI Search view within seconds
Traces are persisted locally with Badger at /var/lib/jaeger/badger and survive reboots (default retention 7 days). Keep both OTLP ports closed to the public internet.