Apache ActiveMQ - Hardened Open-Source JMS Message Broker
بواسطة Lynxroute
Apache ActiveMQ 6.3.2 - CIS Level 1 hardened JMS broker on Ubuntu 24.04 LTS, SBOM + CIS
What is Apache ActiveMQ
Apache ActiveMQ Classic is an open-source message broker written in Java and a widely deployed implementation of the Jakarta Messaging (JMS) API. It moves messages between producers and consumers through queues and topics over the OpenWire protocol, covering work queues, publish/subscribe, request/reply and message-group ordering. Message selectors, durable subscriptions, scheduled delivery, redelivery policies, dead-letter queues and virtual destinations cover common routing patterns. The embedded KahaDB store keeps durable messages across restarts and producer flow control protects the broker under load. A bundled web console with a Jolokia JMX bridge administers queues, topics, connections and subscribers. Apache-2.0 licensed, fully auditable, no vendor lock-in.
Why self-host Apache ActiveMQ
Running the broker on a VM you control keeps every message - which routinely carries customer records, transactions and operational data - inside your own tenant and network perimeter. Self-hosting suits data-residency obligations, GDPR, HIPAA or ISO 27001 programmes, and any product where the message bus must stay private and free of per-message fees.
What this VM image adds
Security hardening:
- Broker authentication and authorization enabled - every transport demands credentials from a JAAS realm, and destination access is restricted to the admin role
- Unique admin credential per instance generated at first boot into /root/activemq-credentials.txt (mode 0600); one credential covers the console, the JMX bridge and both transports
- No credentials baked into the image - the password, the broker keystore and its password are created on your own instance at first boot
- Web console bound to 127.0.0.1:8161 only, published through an nginx TLS reverse proxy on 443 and enforcing its own HTTP Basic login
- OpenWire over TLS on 61617 with a per-instance certificate and a ready-made client truststore; plaintext OpenWire on 61616 also requires credentials
- ObjectMessage deserialization blocked by default - a known remote-code-execution vector in JMS deployments; add a trusted package list if you need it
- Store limits sized to the volume so a runaway producer triggers flow control instead of filling the disk
- Minimal exposed surface - only the OpenWire transports are enabled; AMQP, STOMP, MQTT and WebSocket connectors stay off until you enable one
- Trivy CVE scan before release, UFW allowing only TCP 22, 443, 61617 and 61616 inbound, fail2ban SSH brute-force protection and AppArmor mandatory access control
OS hardening (CIS Level 1):
- CIS Ubuntu 24.04 LTS Level 1 Benchmark via ansible-lockdown
- auditd - system call auditing
- SSH hardening - key-only access, PermitRootLogin no, LoginGraceTime 60
- Kernel hardening - SYN cookies, ASLR, rp_filter, kexec disabled, IPv6 off
- /tmp as tmpfs - nosuid, nodev, noexec
- Azure IMDS egress pre-configured (169.254.169.254, 168.63.129.16)
Compliance artifacts (inside the VM):
- SBOM - CycloneDX 1.6 at /etc/lynxroute/sbom.json with ActiveMQ pinned by version, PURL, license 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/activemq-credentials.txt (mode 0600) with the admin credential, the console URL and both broker endpoints
Quick Start
- Deploy VM from Azure Marketplace (Standard_D2s_v3 recommended)
- Open NSG: TCP 443 and 61617 from your trusted sources, TCP 22 from your management IPs only
- SSH: ssh -i key.pem azureuser@<PUBLIC_IP>, then sudo cat /root/activemq-credentials.txt
- Open https://<PUBLIC_IP>/admin/, accept the self-signed certificate warning and log in as admin
- Point JMS clients at ssl://<PUBLIC_IP>:61617 with the same credential, trusting /var/lib/activemq/tls/broker-truststore.ks
The web console listens on 127.0.0.1:8161 only; nginx is the TLS perimeter on 443. Prefer the TLS transport on 61617, and replace the self-signed certificate with a CA-signed one for production.