Skip to content

Example: mTLS between RabbitMQ nodes #469

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Nov 19, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docs/examples/mtls-inter-node/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# mtls-inter-node Example

This example shows how to secure Erlang Distribution with TLS so that RabbitMQ cluster nodes communicate over secure channels.
In future, RabbitMQ Cluster Operator may make it easier to configure but it is already possible to achieve that with `envConfig` and `override` properties.

The most important parts of this example are:

* `rabbitmq.yaml` - `RabbitmqCluster` definition with all the necessary configuration
* `inter_node_tls.config` - Erlang Distribution configuration file that will be mounted as a volume

The other files serve as an example for setting up certificates with Cert Manager.

* `rabbitmq-ca.yaml` - defines an `Issuer` (CA)
* `rabbitmq-certificate.yaml` - defines a certificate that will be provisioned by Cert Manager and then mounted as a volume

`setup.sh` should perform all the necessary steps but may need to be adjusted to work on your system.

```shell
# install Cert Manager
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.0.4/cert-manager.yaml
# deploy the example
./setup.sh
```
24 changes: 24 additions & 0 deletions docs/examples/mtls-inter-node/inter_node_tls.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[
{server, [
{cacertfile, "/etc/rabbitmq/certs/ca.crt"},
{certfile, "/etc/rabbitmq/certs/tls.crt"},
{keyfile, "/etc/rabbitmq/certs/tls.key"},
{secure_renegotiate, true},
{fail_if_no_peer_cert, true},
{verify, verify_peer},
{customize_hostname_check, [
{match_fun, public_key:pkix_verify_hostname_match_fun(https)}
]}
]},
{client, [
{cacertfile, "/etc/rabbitmq/certs/ca.crt"},
{certfile, "/etc/rabbitmq/certs/tls.crt"},
{keyfile, "/etc/rabbitmq/certs/tls.key"},
{secure_renegotiate, true},
{fail_if_no_peer_cert, true},
{verify, verify_peer},
{customize_hostname_check, [
{match_fun, public_key:pkix_verify_hostname_match_fun(https)}
]}
Comment on lines +20 to +22
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why were these lines added?
They are not in the RabbitMQ docs example.
Is it to get over a certain problem you encountered?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taken from @lukebakken's example (https://github.com/lukebakken/erlang-inet-dist). As far as I tested, without this, Erlang would accept any name in the certificate.

]}
].
7 changes: 7 additions & 0 deletions docs/examples/mtls-inter-node/rabbitmq-ca.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: rabbitmq-ca
spec:
ca:
secretName: rabbitmq-ca
28 changes: 28 additions & 0 deletions docs/examples/mtls-inter-node/rabbitmq-certificate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: mtls-inter-node-nodes-tls
spec:
secretName: mtls-inter-node-nodes-tls
duration: 2160h # 90d
renewBefore: 360h # 15d
subject:
organizations:
- RabbitMQ
commonName: mtls-inter-node
isCA: false
privateKey:
algorithm: RSA
encoding: PKCS1
size: 2048
usages:
- server auth
- client auth
dnsNames:
- mtls-inter-node-server-0.mtls-inter-node-nodes.default
- mtls-inter-node-server-1.mtls-inter-node-nodes.default
- mtls-inter-node-server-2.mtls-inter-node-nodes.default
Comment on lines +22 to +24
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the RabbitMQ clustering ssl docs:

It is possible to reuse a single certificate/key pair for all nodes and CLI tools. The certificate can also use a wildcard Subject Alternative Name (SAN) or Common Name (CN) such as *.rabbitmq.example.local that would match every hostname in the cluster.

Do you think a wildcard name will work here too? I remember you had concerns around this approach if we were to scale up the cluster.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I tested the wildcard option shortly after submitting the PR. Wildcard would make it easier to add nodes to the cluster for example, but I know some companies don't like wildcard certs.

issuerRef:
name: rabbitmq-ca
kind: Issuer
group: cert-manager.io
42 changes: 42 additions & 0 deletions docs/examples/mtls-inter-node/rabbitmq.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
name: mtls-inter-node
spec:
rabbitmq:
envConfig: |
ERL_SSL_PATH="/usr/local/lib/erlang/lib/ssl-10.1/ebin"
SERVER_ADDITIONAL_ERL_ARGS="-pa /usr/local/lib/erlang/lib/ssl-10.1/ebin -proto_dist inet_tls -ssl_dist_optfile /etc/rabbitmq/inter-node-tls.config"
RABBITMQ_CTL_ERL_ARGS="-pa /usr/local/lib/erlang/lib/ssl-10.1/ebin -proto_dist inet_tls -ssl_dist_optfile /etc/rabbitmq/inter-node-tls.config"
replicas: 3
override:
statefulSet:
spec:
template:
spec:
containers:
- name: rabbitmq
volumeMounts:
- mountPath: /etc/rabbitmq/certs
name: mtls-inter-node-nodes-tls
- mountPath: /etc/rabbitmq/inter-node-tls.config
name: inter-node-config
subPath: inter_node_tls.config
volumes:
- configMap:
defaultMode: 420
name: mtls-inter-node-tls-config
name: inter-node-config
- name: mtls-inter-node-nodes-tls
secret:
secretName: mtls-inter-node-nodes-tls
items:
- key: ca.crt
mode: 416
path: ca.crt
- key: tls.crt
mode: 416
path: tls.crt
- key: tls.key
mode: 416
path: tls.key
30 changes: 30 additions & 0 deletions docs/examples/mtls-inter-node/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/bash

OPENSSL=${OPENSSL:-openssl}

# Generate CA certificate and key
#
# These commands do not work with LibreSSL which is shipped with MacOS. Please use openssl
#
if $OPENSSL version | grep -q LibreSSL; then
echo "Please do not use LibreSSL. Set OPENSSL variable to actual OpenSSL binary."
exit 1
fi

$OPENSSL genrsa -out rabbitmq-ca-key.pem 2048
$OPENSSL req -x509 -new -nodes -key rabbitmq-ca-key.pem -subj "/CN=mtls-inter-node" -days 3650 -reqexts v3_req -extensions v3_ca -out rabbitmq-ca.pem

# Create a CA secret
kubectl create secret tls rabbitmq-ca --cert=rabbitmq-ca.pem --key=rabbitmq-ca-key.pem

# Create an Issuer (Cert Manager CA)
kubectl apply -f rabbitmq-ca.yaml

# Create a certificate for the cluster
kubectl apply -f rabbitmq-certificate.yaml

# Create a configuration file for Erlang Distribution
kubectl create configmap mtls-inter-node-tls-config --from-file=inter_node_tls.config

# Deploy a RabbitMQ cluster
kubectl apply -f rabbitmq.yaml