Encrypted Mosquitto broker in Kubernetes
Encrypted Mosquitto broker in Kubernetes
Note: an updated version of this article has been posted to Medium
Mosquitto can usually be installed on an Ubuntu server fairly easily using the APT package manager. By Default, the broker handles unencrypted MQTT connections but it can be configured to use SSL certificates obtained, for example, using Certbot and thus enable MQTTs connections. This configuration is usually achieved by editing the Mosquitto configuration file in /etc/mosquitto so as to point to certificates obtained independently. However, when deploying Mosquitto to Kubernetes, one would prefer not to edit configuration files manually after install. Moreover, in Kubernetes, one can use Cert-manager to obtain SSL certificates. Thus, this article presents an efficient method to deploy a secure MQTTs broker in Kubernetes.
Deployment
Let's begin by creating a deployment for the broker. This can be done easily with the following manifest.
apiVersion: apps/v1
kind: Deployment
metadata:
name: mosquitto
spec:
replicas: 1
selector:
matchLabels:
app: mosquitto
template:
metadata:
labels:
app: mosquitto
spec:
containers:
- name: mosquitto
image: eclipse-mosquitto
ports:
- containerPort: 8883
- containerPort: 9001
volumeMounts:
- mountPath: /etc/mosquitto/
name: config
- mountPath: /mosquitto/certs/
name: certs
- mountPath: /mosquitto/data/
name: data
volumes:
- name: config
configMap:
name: mosquitto-config
- name: certs
secret:
secretName: mosquitto-certs
- name: data
persistentVolumeClaim:
claimName: mosquitto-data
The volumeMounts are the essential part to pay attention to. Here, we have 3 volumes mounted:
/mosquitto/data: which holds the Mosquitto persistent data, mapped to a PVC
/mosquitto/certs: which will hold SSL certificates, mapped to a secret
/etc/mosquitto/: which is normally where the Mosquitto configuration file resides, mapped to a configmap
PVC for Persistent data
The Mosquitto persistent data should survive even when pods are deleted or recreated. Consequently, the persistent data is stored in a PV, for which this would be a typical PVC:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mosquitto-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
Secret for SSL certificates
The Mosquitto deployment specifies that /mosquitto/certs is to be mounted from a secret. This secret is in fact that created automatically by Cert-manager when creating an Ingress for our Broker:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mosquitto
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- mqtt.example.com
secretName: mosquitto-certs
rules:
- host: mqtt.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: mosquitto-clusterip
port:
number: 8883
Configmap for Mosquitto configuration
The last volume to take care of is that of the Mosquitto configuration. The Mosquitto configuration is usually achieved by editing a text file but here, the file actually mounted as a configmap. The configuration specifies the path to the SSL certificates which have been mounted as a secret:
apiVersion: v1
kind: ConfigMap
metadata:
name: mosquitto-config
data:
mosquitto.conf: |
persistence true
persistence_location /mosquitto/data/
log_dest stdout
# MQTT with TLS (MQTTS)
listener 8883
protocol mqtt
cafile /etc/ssl/certs/ca-certificates.crt
keyfile /mosquitto/certs/tls.key
certfile /mosquitto/certs/tls.crt
Services
Finally, we add a service to connect the ingress to the deployment:
apiVersion: v1
kind: Service
metadata:
name: mosquitto-mqtts
spec:
type: ClusterIP
selector:
app: mosquitto
ports:
- port: 8883