The following example configuration that accepts TLSv1.2 connections passes key
testssl.sh tests on Erlang 26.2:
listeners.ssl.default = 5671
ssl_options.cacertfile = /path/to/ca_certificate.pem
ssl_options.certfile = /path/to/server_certificate.pem
ssl_options.keyfile = /path/to/server_key.pem
ssl_options.versions.1 = tlsv1.2
ssl_options.verify = verify_peer
ssl_options.fail_if_no_peer_cert = false
ssl_options.honor_cipher_order = true
ssl_options.honor_ecc_order = true
# These are highly recommended for TLSv1.2 but cannot be used
# with TLSv1.3. If TLSv1.3 is enabled, these lines MUST be removed.
ssl_options.client_renegotiation = false
ssl_options.secure_renegotiate = true
ssl_options.ciphers.1 = ECDHE-ECDSA-AES256-GCM-SHA384
ssl_options.ciphers.2 = ECDHE-RSA-AES256-GCM-SHA384
ssl_options.ciphers.3 = ECDH-ECDSA-AES256-GCM-SHA384
ssl_options.ciphers.4 = ECDH-RSA-AES256-GCM-SHA384
ssl_options.ciphers.5 = DHE-RSA-AES256-GCM-SHA384
ssl_options.ciphers.6 = DHE-DSS-AES256-GCM-SHA384
ssl_options.ciphers.7 = ECDHE-ECDSA-AES128-GCM-SHA256
ssl_options.ciphers.8 = ECDHE-RSA-AES128-GCM-SHA256
ssl_options.ciphers.9 = ECDH-ECDSA-AES128-GCM-SHA256
ssl_options.ciphers.10 = ECDH-RSA-AES128-GCM-SHA256
ssl_options.ciphers.11 = DHE-RSA-AES128-GCM-SHA256
ssl_options.ciphers.12 = DHE-DSS-AES128-GCM-SHA256
This TLSv1.2-enabled setup is reported as not vulnerable to a set of known high profile vulnerabilities:
Using "OpenSSL 3.3.1 4 Jun 2024 (Library: OpenSSL 3.3.1 4 Jun 2024)" [~94 ciphers]
on [redacted]:/opt/homebrew/bin/openssl
(built: "Jun 4 12:53:04 2024", platform: "darwin64-arm64-cc")
Start 2024年08月08日 13:42:36 -->> 127.0.0.1:5671 (localhost) <<--
A record via: /etc/hosts
rDNS (127.0.0.1): localhost.
Service detected: certificate-based authentication without providing client certificate and private key => skipping all HTTP checks
Testing protocols via sockets except NPN+ALPN
SSLv2 not offered (OK)
SSLv3 not offered (OK)
TLS 1 not offered
TLS 1.1 not offered
TLS 1.2 offered (OK)
TLS 1.3 not offered and downgraded to a weaker protocol
NPN/SPDY not offered
ALPN/HTTP2 not offered
Testing cipher categories
NULL ciphers (no encryption) not offered (OK)
Anonymous NULL Ciphers (no authentication) not offered (OK)
Export ciphers (w/o ADH+NULL) not offered (OK)
LOW: 64 Bit + DES, RC[2,4], MD5 (w/o export) not offered (OK)
Triple DES Ciphers / IDEA not offered
Obsoleted CBC ciphers (AES, ARIA etc.) not offered
Strong encryption (AEAD ciphers) with no FS not offered
Forward Secrecy strong encryption (AEAD ciphers) offered (OK)
Testing server's cipher preferences
Hexcode Cipher Suite Name (OpenSSL) KeyExch. Encryption Bits Cipher Suite Name (IANA/RFC)
-----------------------------------------------------------------------------------------------------------------------------
SSLv2
-
SSLv3
-
TLSv1
-
TLSv1.1
-
TLSv1.2 (server order)
xc030 ECDHE-RSA-AES256-GCM-SHA384 ECDH 253 AESGCM 256 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
x9f DHE-RSA-AES256-GCM-SHA384 DH 2048 AESGCM 256 TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
xc02f ECDHE-RSA-AES128-GCM-SHA256 ECDH 253 AESGCM 128 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
x9e DHE-RSA-AES128-GCM-SHA256 DH 2048 AESGCM 128 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
TLSv1.3
-
Has server cipher order? yes (OK)
Testing robust forward secrecy (FS) -- omitting Null Authentication/Encryption, 3DES, RC4
FS is offered (OK) ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-GCM-SHA256
Elliptic curves offered: prime256v1 secp384r1 secp521r1 brainpoolP256r1 brainpoolP384r1 brainpoolP512r1 X25519 X448
DH group offered: RFC3526/Oakley Group 14 (2048 bits)
TLS 1.2 sig_algs offered: RSA+SHA256 RSA+SHA384 RSA+SHA512 RSA-PSS-RSAE+SHA256
Testing server defaults (Server Hello)
TLS extensions (standard) "renegotiation info/#65281" "EC point formats/#11" "max fragment length/#1"
Session Ticket RFC 5077 hint no -- no lifetime advertised
SSL Session ID support yes
Session Resumption Tickets no, Client Auth: ID resumption test not supported
TLS clock skew -1 sec from localtime
Client Authentication required
CA List for Client Auth L=$$$,ドルCN=TLSGenSelfSignedtRootCA 2022年03月22日T11:27:45.010198
Signature Algorithm SHA256 with RSA
Server key size RSA 2048 bits (exponent is 65537)
Server key usage Digital Signature, Key Encipherment
Server extended key usage TLS Web Server Authentication
Serial 01 (OK: length 1)
Fingerprints SHA1 A4346FA6FDC61FCD4C0199EA14B8AE0F5D5121B1
SHA256 C81025DA6F9BB646239659420D58E73F62CEB7D2AD5AC13FF12A9DE057394953
Common Name (CN) [redacted]
subjectAltName (SAN) [redacted] localhost
Trust (hostname) Ok via SAN (same w/o SNI)
Chain of trust NOT ok (self signed CA in chain)
EV cert (experimental) no
Certificate Validity (UTC) 2779>= 60 days (2022年03月22日 07:27 --> 2032年03月19日 07:27)
>= 10 years is way too long
ETS/"eTLS", visibility info not present
Certificate Revocation List --
OCSP URI --
NOT ok -- neither CRL nor OCSP URI provided
OCSP stapling not offered
OCSP must staple extension --
DNS CAA RR (experimental) not offered
Certificate Transparency --
Certificates provided 2
Issuer TLSGenSelfSignedtRootCA 2022年03月22日T11:27:45.010198
Intermediate cert validity #1: ok> 40 days (2032年03月19日 07:27). $$$$ <-- $$$$
Intermediate Bad OCSP (exp.) Ok
Testing vulnerabilities
Heartbleed (CVE-2014-0160) not vulnerable (OK), no heartbeat extension
CCS (CVE-2014-0224) not vulnerable (OK)
Ticketbleed (CVE-2016-9244), experiment. not vulnerable (OK), no session ticket extension
ROBOT Server does not support any cipher suites that use RSA key transport
Secure Renegotiation (RFC 5746) supported (OK)
Secure Client-Initiated Renegotiation not having provided client certificate and private key file, the client x509-based authentication prevents this from being tested
CRIME, TLS (CVE-2012-4929) not vulnerable (OK)
BREACH (CVE-2013-3587) not having provided client certificate and private key file, the client x509-based authentication prevents this from being tested
POODLE, SSL (CVE-2014-3566) not vulnerable (OK), no SSLv3 support
TLS_FALLBACK_SCSV (RFC 7507) No fallback possible (OK), no protocol below TLS 1.2 offered
SWEET32 (CVE-2016-2183, CVE-2016-6329) not vulnerable (OK)
FREAK (CVE-2015-0204) not vulnerable (OK)
DROWN (CVE-2016-0800, CVE-2016-0703) not vulnerable on this host and port (OK)
make sure you don't use this certificate elsewhere with SSLv2 enabled services, see
https://search.censys.io/search?resource=hosts&virtual_hosts=INCLUDE&q=C81025DA6F9BB646239659420D58E73F62CEB7D2AD5AC13FF12A9DE057394953
LOGJAM (CVE-2015-4000), experimental common prime with 2048 bits detected: RFC3526/Oakley Group 14 (2048 bits),
but no DH EXPORT ciphers
BEAST (CVE-2011-3389) not vulnerable (OK), no SSL3 or TLS1
LUCKY13 (CVE-2013-0169), experimental not vulnerable (OK)
Winshock (CVE-2014-6321), experimental not vulnerable (OK) - CAMELLIA or ECDHE_RSA GCM ciphers found
RC4 (CVE-2013-2566, CVE-2015-2808) no RC4 ciphers detected (OK)
Could not determine the protocol, only simulating generic clients.
Running client simulations via sockets
Browser Protocol Cipher Suite Name (OpenSSL) Forward Secrecy
------------------------------------------------------------------------------------------------
Android 8.1 (native) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 253 bit ECDH (X25519)
Android 9.0 (native) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 253 bit ECDH (X25519)
Android 10.0 (native) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 253 bit ECDH (X25519)
Android 11 (native) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 253 bit ECDH (X25519)
Android 12 (native) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 253 bit ECDH (X25519)
Java 7u25 No connection
Java 8u161 TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 521 bit ECDH (P-521)
Java 11.0.2 (OpenJDK) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 521 bit ECDH (P-521)
Java 17.0.3 (OpenJDK) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 253 bit ECDH (X25519)
go 1.17.8 TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 253 bit ECDH (X25519)
LibreSSL 2.8.3 (Apple) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 253 bit ECDH (X25519)
OpenSSL 1.0.2e TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 521 bit ECDH (P-521)
OpenSSL 1.1.0l (Debian) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 253 bit ECDH (X25519)
OpenSSL 1.1.1d (Debian) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 253 bit ECDH (X25519)
OpenSSL 3.0.3 (git) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 253 bit ECDH (X25519)
Server TLS certificates (public keys) and private keys have expiration dates and will need to be replaced (rotated) every so often.
The replacement process involves the following steps:
Without the second step, the new certificate/key pair will be used by the node after a period of time, as the TLS implementation in the runtimes purges its certificate store cache.
Simply replace the server certificate, server private key and (if needed) the certificate authority bundle files with their new versions.
rabbitmqctl eval-n[target-node@hostname]'ssl:clear_pem_cache().'
rabbitmqctl.bat eval -n [target-node@hostname]'ssl:clear_pem_cache().'
rabbitmqctl.bat eval -n [target-node@hostname] "ssl:clear_pem_cache()."
In some environments, there's a set of leaf (client) trusted certificates that must be trusted and that's it, the chain is not traversed and the traditional trust roots (CAs) are not used.
This approach is often used in environments where client certificates are also used as identities, must be unique, and churn (change: some are added, others removed) often.
rabbitmq_trust_store is a plugin that
overrides the peer verification algorithm to do just that: verify that the connected client's certificate
belongs to a set (a whitelist).
The whitelist comes from either a local filesystem directory or an HTTP API endpoint that follows a small set of conventions. The list is refreshed at a configurable interval, allowing certificates to be added or removed without restarting the node or affecting existing connections.
The trust store supports two sources (providers) of trusted leaf client certificates:
To use the filesystem provider, configure a directory that contains the trusted client certificates in the PEM format:
# will monitor `/path/to/trust-store/whitelist` for files additions and deletion
trust_store.directory = /path/to/trust-store/whitelist
# scan the above directory every 30 seconds
trust_store.refresh_interval = 30
Setting refresh_interval to 0 will disable automatic reloading.
To retrieve certificates from a remote HTTPS endpoint that follows certain convention:
trust_store.providers.1 = http
trust_store.url = https://certs.example.com/trusted
trust_store.refresh_interval = 30
The remote server must expose an HTTP API that lists certificates and allows for fetching individual certificates.
GET <url> must respond with a 200 OK and the following body:
{
"certificates":[
{"id":"certificate-1","path":"/certificates/1.pem"},
{"id":"certificate-2","path":"/certificates/2.pem"}
// , ...
]
}
Certificate IDs must be valid filenames and be unique.
GET <url>/<relative-url>, such as "/certificates/1.pem" in the example above,
must respond with a 200 OK and return a PEM-encoded certificate in its body.
The provider uses the If-Modified-Since header to
avoid unnecessary re-downloads.
If the HTTPS endpoint itself authenticates clients using a x.509 certificate, configure its CA certificate bundle, public and private keys:
trust_store.ssl_options.certfile = /path/to/client/client_certificate.pem
trust_store.ssl_options.keyfile = /path/to/client/client_key.pem
trust_store.ssl_options.cacertfile = /path/to/ca/trusted_ca_bundle.pem
Finally, a request timeout can be set with trust_store.https_request_timeout.
The aforementioned Trust Store plugin and the
rabbitmq_auth_mechanism_ssl plugin
serve two complementary roles:
rabbitmq_trust_store handles certificate validation: verifies if the client certificate is on the trusted whitelistrabbitmq_auth_mechanism_ssl handles client authentication: extracts an identity from the certificate and maps it to a RabbitMQ userCombined with the EXTERNAL authentication mechanism, they allow clients to authenticate with just their x.509 certificate.
This setup requires two plugins to be enabled:
rabbitmq-plugins enable rabbitmq_trust_store
rabbitmq-plugins enable rabbitmq_auth_mechanism_ssl
Then configure TLS, the trust store, and the authentication mechanism in rabbitmq.conf:
# TLS listener
listeners.ssl.default = 5671
ssl_options.cacertfile = /path/to/ca_certificate.pem
ssl_options.certfile = /path/to/server_certificate.pem
ssl_options.keyfile = /path/to/server_key.pem
ssl_options.verify = verify_peer
ssl_options.fail_if_no_peer_cert = true
# Trust store: directory containing whitelisted client certificates
trust_store.directory = /path/to/trust-store/whitelist
trust_store.refresh_interval = 30
# Enable the EXTERNAL mechanism so clients can authenticate with a certificate
auth_mechanisms.1 = EXTERNAL
auth_mechanisms.2 = PLAIN
# Extract the username from the certificate's Common Name (CN) field.
# Other supported options: distinguished_name (default), subject_alternative_name
ssl_cert_login_from = common_name
The ssl_cert_login_from setting controls which field of the client certificate is used as the RabbitMQ username:
distinguished_name (default): uses the full subject DN in RFC 4514 format (for example, CN=guest,O=client,L=Paris,ST=France,C=FR)common_name: uses only the CN field (for example, guest)subject_alternative_name: uses a SAN entry, configured with ssl_cert_login_san_type (for example, dns, email) and an ssl_cert_login_san_index
to pick a specific entry from a listA RabbitMQ user matching the extracted name must exist in the configured authentication and authorisation backend(s).
When the EXTERNAL mechanism is used, the client-provided password is ignored.
To list currently loaded certificates:
rabbitmq-diagnostics list_trust_store_certificates
To manually trigger a whitelist refresh:
rabbitmqctl refresh_trust_store
TLS session caching bypasses trust store certificate validation. When a client resumes a cached TLS session, the trust store is not consulted. To ensure that removed certificates are immediately rejected, disable TLS session caching:
ssl_options.reuse_sessions = false
Please refer to the plugin README for additional details and advanced configuration options.
Enabling TLS in the RabbitMQ Erlang client is similar to configuring other
settings related to networking. The #amqp_params_network record
provides a field, ssl_options, for all the standard Erlang TLS options.
The three important options which must be supplied are:
cacertfile option specifies the certificates of the root
Certificate Authorities that we wish to implicitly trust.certfile is the client's own certificate in PEM formatkeyfile is the client's private key file in PEM formatserver_name_indication - set this option to the host name of the server
to which a TLS connection will be made to enable "Server Name Indication" verification
of the certificate presented by the server. This ensures that the server certificate's
CN= value will be verified during TLS connection establishment. You can
override this behavior by setting server_name_indication to a different
host name or to the special value disable to disable this
verification. Note that, by default, SNI is not enabled. This default
will change in a future RabbitMQ Erlang client release.
verify - set this option to verify_peer to enable X509
certificate chain verification. The depth option configures certificate
verification depth. Note that, by default, verify is set to
verify_none, which disables certificate chain verification. This default
will change in a future RabbitMQ Erlang client release.
SslOpts=[{cacertfile,"/path/to/ca_certificate.pem"},
{certfile,"/path/to/client/certificate.pem"},
{keyfile,"/path/to/client/private_key.pem"},
%% only necessary with intermediate CAs
%% {depth, 2},
%% Note: it is recommended to set 'verify' to
%% to 'verify_peer' to ensure that X509
%% certificate chain validation is enabled
%%
%% Do not set 'verify' or set it to verify_none
%% if x509 certificate chain validation is
%% not desired
{verify,verify_peer},
%% If Server Name Indication validation is desired,
%% set the following option to the host name to which
%% the connection is made. If necessary, this option
%% may be set to another host name to match the server
%% certificate's CN= value.
%% Do not set this option or set it to the atom 'disable'
%% to disable SNI validation
{server_name_indication,"my.rmq-server.net"}],
Params=#amqp_params_network{host="my.rmq-server.net",
port=5671,
ssl_options=SslOpts}
{ok,Conn}=amqp_connection:start(Params),
You can now go ahead and use Conn as a normal connection.
This section of the guide explains how to generate a Certificate Authority and use it to generate and sign two certificate/key pairs, one for the server and one for client libraries. Note that the process can be automated using existing tools, which is recommended. This section is intended for those who would like to improve their understanding of the process, OpenSSL command line tools and some important aspects of OpenSSL configuration.
This guide assumes a UNIX-like operating system (Linux, MacOS, a BSD variant and so on)
and a recent version of OpenSSL available in PATH.
First let's create a directory for our test Certificate Authority:
mkdir testca
cd testca
mkdir certs private
chmod700 private
echo 01 > serial
touch index.txt
Now add the following OpenSSL configuration file, openssl.cnf, within the newly created testca
directory:
[ ca ]
default_ca = testca
[ testca ]
dir = .
certificate = $dir/ca_certificate.pem
database = $dir/index.txt
new_certs_dir = $dir/certs
private_key = $dir/private/ca_private_key.pem
serial = $dir/serial
default_crl_days = 7
default_days = 365
default_md = sha256
policy = testca_policy
x509_extensions = certificate_extensions
[ testca_policy ]
commonName = supplied
stateOrProvinceName = optional
countryName = optional
emailAddress = optional
organizationName = optional
organizationalUnitName = optional
domainComponent = optional
[ certificate_extensions ]
basicConstraints = CA:false
[ req ]
default_bits = 2048
default_keyfile = ./private/ca_private_key.pem
default_md = sha256
prompt = yes
distinguished_name = root_ca_distinguished_name
x509_extensions = root_ca_extensions
[ root_ca_distinguished_name ]
commonName = hostname
[ root_ca_extensions ]
basicConstraints = CA:true
keyUsage = keyCertSign, cRLSign
[ client_ca_extensions ]
basicConstraints = CA:false
keyUsage = digitalSignature,keyEncipherment
extendedKeyUsage = 1.3.6.1.5.5.7.3.2
[ server_ca_extensions ]
basicConstraints = CA:false
keyUsage = digitalSignature,keyEncipherment
extendedKeyUsage = 1.3.6.1.5.5.7.3.1
Next we need to generate the key and certificates that our test
Certificate Authority will use. Still within the testca
directory:
openssl req -x509-config openssl.cnf -newkey rsa:2048 -days365\
-out ca_certificate.pem -outform PEM -subj /CN=MyTestCA/ -nodes
openssl x509 -in ca_certificate.pem -out ca_certificate.cer -outform DER
This is all that is needed to generate a test Certificate
Authority. The root certificate is in ca_certificate.pem
and is also in testca/ca_certificate.cer. These two files contain the
same information, but in different formats, PEM and DER.
Most software uses the former but some tools require the latter.
Having set up our Certificate Authority, we now need to generate private keys and certificates for the clients and the server. RabbitMQ broker uses certificates and private keys in the PEM format. Some client libraries use the PEM format, others will require conversion to a different format (e.g. PKCS#12).
Java and .NET clients use a certificate format called PKCS#12 and custom certificate stores. Certificate store contains both the client's certificate and key. The PKCS store is usually password protected, and so that a password must be provided.
The process for creating server and client certificates is very similar. First the server:
cd..
ls
# => testca
mkdir server
cd server
openssl genrsa -out private_key.pem 2048
openssl req -new-key private_key.pem -out req.pem -outform PEM \
-subj /CN=$(hostname)/O=server/ -nodes
cd../testca
openssl ca -config openssl.cnf -in../server/req.pem -out\
../server/server_certificate.pem -notext-batch-extensions server_ca_extensions
cd../server
openssl pkcs12 -export-out server_certificate.p12 -in server_certificate.pem -inkey private_key.pem \
-passout pass:MySecretPassword
And now the client:
cd..
ls
# => server testca
mkdir client
cd client
openssl genrsa -out private_key.pem 2048
openssl req -new-key private_key.pem -out req.pem -outform PEM \
-subj /CN=$(hostname)/O=client/ -nodes
cd../testca
openssl ca -config openssl.cnf -in../client/req.pem -out\
../client/client_certificate.pem -notext-batch-extensions client_ca_extensions
cd../client
openssl pkcs12 -export-out client_certificate.p12 -in client_certificate.pem -inkey private_key.pem \
-passout pass:MySecretPassword
The two examples above generate private keys that are 2048 bits in size.
It is possible to use longer (and thus more secure but also slower to generate)
keys by providing a different value to openssl genrsa, e.g.:
openssl genrsa -out private_key.pem 4096
Another option would be to generate a key using Elliptic Curve Cryptography. Instead of openssl genrsa use
openssl ecparam like so:
openssl ecparam -out private_key.pem -genkey-name prime256v1
prime256v1 in the example above is an Elliptic curve name.
Different versions of OpenSSL will have a different set of curves available,
list them with openssl ecparam -list_curves.