TLS Configuration
TLS Configuration
Section titled “TLS Configuration”Secure RabbitMQ connections with TLS encryption and client certificates.
Overview
Section titled “Overview”Certificate Requirements
Section titled “Certificate Requirements”| Certificate | Purpose |
|---|---|
| CA Certificate | Root of trust |
| Server Certificate | RabbitMQ server identity |
| Client Certificate | Client authentication — required: the shipped broker config sets ssl_options.fail_if_no_peer_cert = true |
One rule, stated in three places and the same in all of them: the broker demands a client
certificate. The Ansible role renders it
(rabbitmq.conf.j2),
RabbitMQ Setup says what that means for Mandible and
Thorax, and Manual Installation builds the
broker by hand with the same setting.
Generate Certificates
Section titled “Generate Certificates”Create CA
Section titled “Create CA”# Create CA directorymkdir -p /etc/rabbitmq/certscd /etc/rabbitmq/certs
# Generate CA keyopenssl genrsa -out ca-key.pem 4096
# Generate CA certificateopenssl req -x509 -new -nodes \ -key ca-key.pem \ -sha256 -days 3650 \ -out ca-cert.pem \ -subj "/CN=Mantis RabbitMQ CA/O=Mantis"Create Server Certificate
Section titled “Create Server Certificate”# Generate server keyopenssl genrsa -out server-key.pem 2048
# Create certificate signing requestopenssl req -new \ -key server-key.pem \ -out server-cert.csr \ -subj "/CN=rabbitmq.example.com/O=Mantis"
# Create SAN extension filecat > server_san.ext << EOFsubjectAltName = @alt_names[alt_names]DNS.1 = rabbitmq.example.comDNS.2 = localhostIP.1 = 127.0.0.1EOF
# Sign with CAopenssl x509 -req \ -in server-cert.csr \ -CA ca-cert.pem \ -CAkey ca-key.pem \ -CAcreateserial \ -out server-cert.pem \ -days 365 \ -sha256 \ -extfile server_san.extCreate Client Certificate
Section titled “Create Client Certificate”# Generate client keyopenssl genrsa -out rabbitmq-client-key.pem 2048
# Create CSRopenssl req -new \ -key rabbitmq-client-key.pem \ -out rabbitmq-client.csr \ -subj "/CN=mantis-client/O=Mantis"
# Sign with CAopenssl x509 -req \ -in rabbitmq-client.csr \ -CA ca-cert.pem \ -CAkey ca-key.pem \ -CAcreateserial \ -out rabbitmq-client-cert.pem \ -days 365 \ -sha256Set Permissions
Section titled “Set Permissions”# Secure the keyschmod 600 /etc/rabbitmq/certs/*-key.pemchmod 644 /etc/rabbitmq/certs/*-cert.pemchown -R rabbitmq:rabbitmq /etc/rabbitmq/certsRabbitMQ TLS Configuration
Section titled “RabbitMQ TLS Configuration”Basic TLS
Section titled “Basic TLS”# Plain TCP is disabled -- Mantis requires TLS and has no option to use a# plain listener, and the shipped broker config hard-disables it.listeners.tcp = none
# Enable TLS listenerlisteners.ssl.default = 5671
# Certificate configurationssl_options.cacertfile = /etc/rabbitmq/certs/ca-cert.pemssl_options.certfile = /etc/rabbitmq/certs/server-cert.pemssl_options.keyfile = /etc/rabbitmq/certs/server-key.pem
# TLS version (require TLS 1.2+)ssl_options.versions.1 = tlsv1.2ssl_options.versions.2 = tlsv1.3
# Cipher suitesssl_options.ciphers.1 = TLS_AES_256_GCM_SHA384ssl_options.ciphers.2 = TLS_AES_128_GCM_SHA256ssl_options.ciphers.3 = ECDHE-RSA-AES256-GCM-SHA384ssl_options.ciphers.4 = ECDHE-RSA-AES128-GCM-SHA256
# Honor server cipher preferencessl_options.honor_cipher_order = truessl_options.honor_ecc_order = trueClient Certificate Verification
Section titled “Client Certificate Verification”# Require client certificatesssl_options.verify = verify_peerssl_options.fail_if_no_peer_cert = true
# Depth of certificate chain verificationssl_options.depth = 2TLS is mandatory
Section titled “TLS is mandatory”Mantis cannot use a plain-TCP listener: the queue client hard-requires TLS
(instinct/src/queue/config.rs, “TLS is mandatory… no option to disable
TLS”), and the shipped broker config disables the TCP listener. Do not enable a
plain listener for Mantis traffic.
Management UI TLS
Section titled “Management UI TLS”Enable HTTPS
Section titled “Enable HTTPS”# HTTPS only. The plain listener is simply not configured -- there is no# "disable" value for management.tcp.port, and 0 would request an ephemeral# port, i.e. an unpredictable open HTTP management port rather than none.
# Enable HTTPSmanagement.ssl.port = 15671management.ssl.cacertfile = /etc/rabbitmq/certs/ca-cert.pemmanagement.ssl.certfile = /etc/rabbitmq/certs/server-cert.pemmanagement.ssl.keyfile = /etc/rabbitmq/certs/server-key.pemThorax Configuration
Section titled “Thorax Configuration”TLS Connection
Section titled “TLS Connection”client_cert_path and client_key_path are not optional against the broker this
repo ships: it sets ssl_options.fail_if_no_peer_cert = true, so a connection
presenting no client certificate is rejected at the AMQPS handshake.
[queue]enabled = truehost = "rabbitmq.example.com"port = 5671vhost = "/mantis"username = "mantis"password = "<the mantis broker user's password>"ca_cert_path = "/etc/mantis/certs/ca-cert.pem"client_cert_path = "/etc/mantis/certs/rabbitmq-client-cert.pem"client_key_path = "/etc/mantis/certs/rabbitmq-client-key.pem"prefetch_count = 10Environment Variables
Section titled “Environment Variables”THORAX__QUEUE__HOST="rabbitmq.example.com"THORAX__QUEUE__PORT=5671THORAX__QUEUE__USERNAME="mantis"THORAX__QUEUE__CA_CERT_PATH="/etc/mantis/certs/ca-cert.pem"Mandible Configuration
Section titled “Mandible Configuration”Mandible publishes commands to RabbitMQ and uses the same [queue] settings block with the MANDIBLE__ env var prefix.
TLS Connection
Section titled “TLS Connection”The same rule applies here — both client-certificate paths must be set.
[queue]enabled = truehost = "rabbitmq.example.com"port = 5671vhost = "/mantis"username = "mantis"password = "<the mantis broker user's password>"ca_cert_path = "/etc/mantis/certs/ca-cert.pem"client_cert_path = "/etc/mantis/certs/rabbitmq-client-cert.pem"client_key_path = "/etc/mantis/certs/rabbitmq-client-key.pem"Environment Variables
Section titled “Environment Variables”MANDIBLE__QUEUE__HOST="rabbitmq.example.com"MANDIBLE__QUEUE__PORT=5671MANDIBLE__QUEUE__USERNAME="mantis"MANDIBLE__QUEUE__CA_CERT_PATH="/etc/mantis/certs/ca-cert.pem"Docker Configuration
Section titled “Docker Configuration”Docker Compose
Section titled “Docker Compose”services: rabbitmq: image: rabbitmq:4.3.6-management hostname: rabbitmq volumes: - ./certs/ca-cert.pem:/etc/rabbitmq/certs/ca-cert.pem:ro - ./certs/server-cert.pem:/etc/rabbitmq/certs/server-cert.pem:ro - ./certs/server-key.pem:/etc/rabbitmq/certs/server-key.pem:ro - ./rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf:ro # Its own uid, so the entrypoint does not start as root and drop privileges -- # that drop discards group_add and leaves the group-readable key unreadable. user: '999:999' group_add: - '${MANTIS_CERT_GID:-1000}' ports: - '5671:5671' # AMQPS - '15671:15671' # Management HTTPSKubernetes Secret
Section titled “Kubernetes Secret”apiVersion: v1kind: Secretmetadata: name: rabbitmq-tlstype: Opaquedata: ca-cert.pem: <base64-encoded-ca> server-cert.pem: <base64-encoded-cert> server-key.pem: <base64-encoded-key>Verification
Section titled “Verification”Test TLS Connection
Section titled “Test TLS Connection”# Using OpenSSL. The broker sets fail_if_no_peer_cert, so a client certificate# is required for the handshake to complete.openssl s_client -connect rabbitmq.example.com:5671 \ -CAfile /etc/mantis/certs/ca-cert.pem \ -cert /etc/mantis/certs/rabbitmq-client-cert.pem \ -key /etc/mantis/certs/rabbitmq-client-key.pem \ -showcerts
# Check certificateopenssl s_client -connect rabbitmq.example.com:5671 \ -CAfile /etc/mantis/certs/ca-cert.pem \ -cert /etc/mantis/certs/rabbitmq-client-cert.pem \ -key /etc/mantis/certs/rabbitmq-client-key.pem \ </dev/null 2>/dev/null | openssl x509 -text -nooutTest AMQPS Connection
Section titled “Test AMQPS Connection”# Using amqp-toolsamqp-declare-queue \ --url="amqps://mantis:password@rabbitmq.example.com:5671" \ --cacert=/etc/mantis/certs/ca-cert.pem \ --cert=/etc/mantis/certs/rabbitmq-client-cert.pem \ --key=/etc/mantis/certs/rabbitmq-client-key.pem \ --queue=test
# Using Pythonpython3 -c "import sslimport pika
context = ssl.create_default_context(cafile='/etc/mantis/certs/ca-cert.pem')context.load_cert_chain('/etc/mantis/certs/rabbitmq-client-cert.pem', '/etc/mantis/certs/rabbitmq-client-key.pem')params = pika.ConnectionParameters( host='rabbitmq.example.com', port=5671, credentials=pika.PlainCredentials('mantis', 'password'), ssl_options=pika.SSLOptions(context))connection = pika.BlockingConnection(params)print('Connected successfully')connection.close()"Check RabbitMQ TLS Status
Section titled “Check RabbitMQ TLS Status”# List TLS listenerssudo rabbitmqctl eval 'rabbit_networking:active_listeners().'
# Check connection TLS infosudo rabbitmqctl list_connections name ssl ssl_protocol ssl_cipherCertificate Renewal
Section titled “Certificate Renewal”Automated Renewal
Section titled “Automated Renewal”#!/bin/bashSSL_DIR="/etc/rabbitmq/certs"DAYS_BEFORE_EXPIRY=30
# Check if certificate needs renewalEXPIRY=$(openssl x509 -enddate -noout -in $SSL_DIR/server-cert.pem | cut -d= -f2)EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)NOW_EPOCH=$(date +%s)DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))
if [ $DAYS_LEFT -lt $DAYS_BEFORE_EXPIRY ]; then echo "Certificate expires in $DAYS_LEFT days, renewing..."
# Generate new certificate openssl req -new -key $SSL_DIR/server-key.pem -out $SSL_DIR/server-cert.csr \ -subj "/CN=rabbitmq.example.com/O=Mantis"
openssl x509 -req -in $SSL_DIR/server-cert.csr \ -CA $SSL_DIR/ca-cert.pem -CAkey $SSL_DIR/ca-key.pem \ -CAcreateserial -out $SSL_DIR/server-cert.pem \ -days 365 -sha256 -extfile $SSL_DIR/server_san.ext
# Reload RabbitMQ sudo systemctl reload rabbitmq-server
echo "Certificate renewed successfully"else echo "Certificate valid for $DAYS_LEFT more days"fiSchedule Renewal
Section titled “Schedule Renewal”# Weekly check0 0 * * 0 /opt/mantis/scripts/renew-rabbitmq-certs.sh >> /var/log/rabbitmq/cert-renewal.log 2>&1Troubleshooting
Section titled “Troubleshooting”TLS Handshake Failed
Section titled “TLS Handshake Failed”Error: TLS handshake failedCauses:
- Certificate hostname mismatch
- Expired certificate
- CA certificate not trusted
Solutions:
- Verify SAN includes hostname:
openssl x509 -in server-cert.pem -text | grep DNS - Check expiry:
openssl x509 -in server-cert.pem -enddate -noout - Verify CA is correct
Certificate Verification Failed
Section titled “Certificate Verification Failed”Error: certificate verify failedSolutions:
- Ensure CA certificate is correct
- Check certificate chain is complete
- Verify
verify_peersettings match on both sides
Connection Reset
Section titled “Connection Reset”Error: connection reset by peerCauses:
- TLS version mismatch
- Cipher suite incompatibility
Solutions:
- Check TLS versions match
- Verify cipher suites are compatible
Next Steps
Section titled “Next Steps”- Queue Topology - Queue configuration
- Monitoring - RabbitMQ monitoring
- RabbitMQ Setup - Initial setup
