mProxy is an MQTT proxy.
It is deployed in front of an MQTT broker and can be used for authorization, packet inspection and modification, logging and debugging and various other purposes.
git clone https://github.com/absmach/mproxy.git
cd mproxy
make
./build/mproxy
mProxy starts TCP and WS servers, offering connections to devices. Upon the connection, it establishes a session with a remote MQTT broker. It then pipes packets from devices to the MQTT broker, inspecting or modifying them as they flow through the proxy.
Here is the flow in more detail:
- The Device connects to mProxy's TCP server
- mProxy accepts the inbound (IN) connection and establishes a new session with the remote MQTT broker (i.e. it dials out to the MQTT broker only once it accepts a new connection from a device. This way one device-mProxy connection corresponds to one mProxy-MQTT broker connection.)
- mProxy then spawns 2 goroutines: one that will read incoming packets from the device-mProxy socket (INBOUND or UPLINK), inspect them (calling event handlers) and write them to mProxy-broker socket (forwarding them towards the broker) and other that will be reading MQTT broker responses from mProxy-broker socket and writing them towards device, in device-mProxy socket (OUTBOUND or DOWNLINK).
mProxy can parse and understand MQTT packages, and upon their detection, it calls external event handlers. Event handlers should implement the following interface defined in pkg/mqtt/events.go:
// Handler is an interface for mProxy hooks
type Handler interface {
// Authorization on client `CONNECT`
// Each of the params are passed by reference, so that it can be changed
AuthConnect(ctx context.Context) error
// Authorization on client `PUBLISH`
// Topic is passed by reference, so that it can be modified
AuthPublish(ctx context.Context, topic *string, payload *[]byte) error
// Authorization on client `SUBSCRIBE`
// Topics are passed by reference, so that they can be modified
AuthSubscribe(ctx context.Context, topics *[]string) error
// After client successfully connected
Connect(ctx context.Context)
// After client successfully published
Publish(ctx context.Context, topic *string, payload *[]byte)
// After client successfully subscribed
Subscribe(ctx context.Context, topics *[]string)
// After client unsubscribed
Unsubscribe(ctx context.Context, topics *[]string)
// Disconnect on connection with client lost
Disconnect(ctx context.Context)
}
An example of implementation is given here, alongside with it's main()
function.
mProxy does not do load balancing - just pure and simple proxying with TLS termination. This is why it should be deployed right in front of it's corresponding MQTT broker instance: one mProxy for each MQTT broker instance in the MQTT cluster.
Usually, this is done by deploying mProxy as a side-car in the same Kubernetes pod alongside with MQTT broker instance (MQTT cluster node).
LB tasks can be offloaded to a standard ingress proxy - for example, NginX.
- Golang
- Mosquitto MQTT Server
- Mosquitto Publisher and Subscriber Client
mProxy is used to proxy requests to a backend server. For the example setup, we will use Mosquitto server as the backend for MQTT, and MQTT over Websocket and an HTTP echo server for HTTP.
-
Start the Mosquitto MQTT Server with the following command. This bash script will initiate the Mosquitto MQTT server with WebSocket support. The Mosquitto Server will listen for MQTT connections on port 1883 and MQTT over WebSocket connections on port 8000.
examples/server/mosquitto/server.sh
-
Start the HTTP Echo Server:
go run examples/server/http-echo/main.go
-
Start the OCSP/CRL Mock responder:
go run examples/ocsp-crl-responder/main.go
-
Start the example mProxy servers for various protocols:
go run cmd/main.go
The
cmd/main.go
Go program initializes mProxy servers for the following protocols:- mProxy server for
MQTT
protocolwithout TLS
on port1884
- mProxy server for
MQTT
protocolwith TLS
on port8883
- mProxy server for
MQTT
protocolwith mTLS
on port8884
- mProxy server for
MQTT over WebSocket without TLS
on port8083
- mProxy server for
MQTT over WebSocket with TLS
on port8084
- mProxy server for
MQTT over WebSocket with mTLS
on port8085
with prefix path/mqtt
- mProxy server for
HTTP protocol without TLS
on port8086
with prefix path/messages
- mProxy server for
HTTP protocol with TLS
on port8087
with prefix path/messages
- mProxy server for
HTTP protocol with mTLS
on port8088
with prefix path/messages
- mProxy server for
Bash scripts available in examples/client/mqtt
directory help to test the mProxy servers running for MQTT protocols
-
Script to test mProxy server running at port 1884 for MQTT without TLS
examples/client/mqtt/without_tls.sh
-
Script to test mProxy server running at port 8883 for MQTT with TLS
examples/client/mqtt/with_tls.sh
-
Script to test mProxy server running at port 8884 for MQTT with mTLS
examples/client/mqtt/with_mtls.sh
Go programs available in examples/client/websocket/*/main.go
directory helps to test the mProxy servers running for MQTT over WebSocket protocols
-
Go program to test mProxy server running at port 8083 for MQTT over WebSocket without TLS
go run examples/client/websocket/without_tls/main.go
-
Go program to test mProxy server running at port 8084 for MQTT over WebSocket with TLS
go run examples/client/websocket/with_tls/main.go
-
Go program to test mProxy server running at port 8085 for MQTT over Websocket with mTLS
go run examples/client/websocket/with_mtls/main.go
Bash scripts available in examples/client/http
directory help to test the mProxy servers running for HTTP protocols
-
Script to test mProxy server running at port 8086 for HTTP without TLS
examples/client/http/without_tls.sh
-
Script to test mProxy server running at port 8087 for HTTP with TLS
examples/client/http/with_tls.sh
-
Script to test mProxy server running at port 8088 for HTTP with mTLS
examples/client/http/with_mtls.sh
The service is configured using the environment variables presented in the following table. Note that any unset variables will be replaced with their default values.
Variable | Description | Default |
---|---|---|
MPROXY_MQTT_WITHOUT_TLS_ADDRESS | MQTT without TLS inbound (IN) connection listening address | :1884 |
MPROXY_MQTT_WITHOUT_TLS_TARGET | MQTT without TLS outbound (OUT) connection address | localhost:1883 |
MPROXY_MQTT_WITH_TLS_ADDRESS | MQTT with TLS inbound (IN) connection listening address | :8883 |
MPROXY_MQTT_WITH_TLS_TARGET | MQTT with TLS outbound (OUT) connection address | localhost:1883 |
MPROXY_MQTT_WITH_TLS_CERT_FILE | MQTT with TLS certificate file path | ssl/certs/server.crt |
MPROXY_MQTT_WITH_TLS_KEY_FILE | MQTT with TLS key file path | ssl/certs/server.key |
MPROXY_MQTT_WITH_TLS_SERVER_CA_FILE | MQTT with TLS server CA file path | ssl/certs/ca.crt |
MPROXY_MQTT_WITH_MTLS_ADDRESS | MQTT with mTLS inbound (IN) connection listening address | :8884 |
MPROXY_MQTT_WITH_MTLS_TARGET | MQTT with mTLS outbound (OUT) connection address | localhost:1883 |
MPROXY_MQTT_WITH_MTLS_CERT_FILE | MQTT with mTLS certificate file path | ssl/certs/server.crt |
MPROXY_MQTT_WITH_MTLS_KEY_FILE | MQTT with mTLS key file path | ssl/certs/server.key |
MPROXY_MQTT_WITH_MTLS_SERVER_CA_FILE | MQTT with mTLS server CA file path | ssl/certs/ca.crt |
MPROXY_MQTT_WITH_MTLS_CLIENT_CA_FILE | MQTT with mTLS client CA file path | ssl/certs/ca.crt |
MPROXY_MQTT_WITH_MTLS_CERT_VERIFICATION_METHODS | MQTT with mTLS certificate verification methods, if no value or unset then mProxy server will not do client validation | ocsp |
MPROXY_MQTT_WITH_MTLS_OCSP_RESPONDER_URL | MQTT with mTLS OCSP responder URL, it is used if OCSP responder URL is not available in client certificate AIA | http://localhost:8080/ocsp |
MPROXY_MQTT_WS_WITHOUT_TLS_ADDRESS | MQTT over Websocket without TLS inbound (IN) connection listening address | :8083 |
MPROXY_MQTT_WS_WITHOUT_TLS_TARGET | MQTT over Websocket without TLS outbound (OUT) connection address | ws://localhost:8000/ |
MPROXY_MQTT_WS_WITH_TLS_ADDRESS | MQTT over Websocket with TLS inbound (IN) connection listening address | :8084 |
MPROXY_MQTT_WS_WITH_TLS_TARGET | MQTT over Websocket with TLS outbound (OUT) connection address | ws://localhost:8000/ |
MPROXY_MQTT_WS_WITH_TLS_CERT_FILE | MQTT over Websocket with TLS certificate file path | ssl/certs/server.crt |
MPROXY_MQTT_WS_WITH_TLS_KEY_FILE | MQTT over Websocket with TLS key file path | ssl/certs/server.key |
MPROXY_MQTT_WS_WITH_TLS_SERVER_CA_FILE | MQTT over Websocket with TLS server CA file path | ssl/certs/ca.crt |
MPROXY_MQTT_WS_WITH_MTLS_ADDRESS | MQTT over Websocket with mTLS inbound (IN) connection listening address | :8085 |
MPROXY_MQTT_WS_WITH_MTLS_PATH_PREFIX | MQTT over Websocket with mTLS inbound (IN) connection path | /mqtt |
MPROXY_MQTT_WS_WITH_MTLS_TARGET | MQTT over Websocket with mTLS outbound (OUT) connection address | ws://localhost:8000/ |
MPROXY_MQTT_WS_WITH_MTLS_CERT_FILE | MQTT over Websocket with mTLS certificate file path | ssl/certs/server.crt |
MPROXY_MQTT_WS_WITH_MTLS_KEY_FILE | MQTT over Websocket with mTLS key file path | ssl/certs/server.key |
MPROXY_MQTT_WS_WITH_MTLS_SERVER_CA_FILE | MQTT over Websocket with mTLS server CA file path | ssl/certs/ca.crt |
MPROXY_MQTT_WS_WITH_MTLS_CLIENT_CA_FILE | MQTT over Websocket with mTLS client CA file path | ssl/certs/ca.crt |
MPROXY_MQTT_WS_WITH_MTLS_CERT_VERIFICATION_METHODS | MQTT over Websocket with mTLS certificate verification methods, if no value or unset then mProxy server will not do client validation | ocsp |
MPROXY_MQTT_WS_WITH_MTLS_OCSP_RESPONDER_URL | MQTT over Websocket with mTLS OCSP responder URL, it is used if OCSP responder URL is not available in client certificate AIA | http://localhost:8080/ocsp |
MPROXY_HTTP_WITHOUT_TLS_ADDRESS | HTTP without TLS inbound (IN) connection listening address | :8086 |
MPROXY_HTTP_WITHOUT_TLS_PATH_PREFIX | HTTP without TLS inbound (IN) connection path | /messages |
MPROXY_HTTP_WITHOUT_TLS_TARGET | HTTP without TLS outbound (OUT) connection address | http://localhost:8888/ |
MPROXY_HTTP_WITH_TLS_ADDRESS | HTTP with TLS inbound (IN) connection listening address | :8087 |
MPROXY_HTTP_WITH_TLS_PATH_PREFIX | HTTP with TLS inbound (IN) connection path | /messages |
MPROXY_HTTP_WITH_TLS_TARGET | HTTP with TLS outbound (OUT) connection address | http://localhost:8888/ |
MPROXY_HTTP_WITH_TLS_CERT_FILE | HTTP with TLS certificate file path | ssl/certs/server.crt |
MPROXY_HTTP_WITH_TLS_KEY_FILE | HTTP with TLS key file path | ssl/certs/server.key |
MPROXY_HTTP_WITH_TLS_SERVER_CA_FILE | HTTP with TLS server CA file path | ssl/certs/ca.crt |
MPROXY_HTTP_WITH_MTLS_ADDRESS | HTTP with mTLS inbound (IN) connection listening address | :8088 |
MPROXY_HTTP_WITH_MTLS_PATH_PREFIX | HTTP with mTLS inbound (IN) connection path | /messages |
MPROXY_HTTP_WITH_MTLS_TARGET | HTTP with mTLS outbound (OUT) connection address | http://localhost:8888/ |
MPROXY_HTTP_WITH_MTLS_CERT_FILE | HTTP with mTLS certificate file path | ssl/certs/server.crt |
MPROXY_HTTP_WITH_MTLS_KEY_FILE | HTTP with mTLS key file path | ssl/certs/server.key |
MPROXY_HTTP_WITH_MTLS_SERVER_CA_FILE | HTTP with mTLS server CA file path | ssl/certs/ca.crt |
MPROXY_HTTP_WITH_MTLS_CLIENT_CA_FILE | HTTP with mTLS client CA file path | ssl/certs/ca.crt |
MPROXY_HTTP_WITH_MTLS_CERT_VERIFICATION_METHODS | HTTP with mTLS certificate verification methods, if no value or unset then mProxy server will not do client validation | ocsp |
MPROXY_HTTP_WITH_MTLS_OCSP_RESPONDER_URL | HTTP with mTLS OCSP responder URL, it is used if OCSP responder URL is not available in client certificate AIA | http://localhost:8080/ocsp |
ADDRESS
: Specifies the address at which mProxy will listen. Supports MQTT, MQTT over WebSocket, and HTTP proxy connections.PATH_PREFIX
: Defines the path prefix when listening for MQTT over WebSocket or HTTP connections.TARGET
: Specifies the address of the target server, including any prefix path if available. The target server can be an MQTT server, MQTT over WebSocket, or an HTTP server.
CERT_FILE
: Path to the TLS certificate file.KEY_FILE
: Path to the TLS certificate key file.SERVER_CA_FILE
: Path to the Server CA certificate file.CLIENT_CA_FILE
: Path to the Client CA certificate file.CERT_VERIFICATION_METHODS
: Methods for validating certificates. Accepted values areocsp
orcrl
. For theocsp
value, thetls.Config
attempts to retrieve the OCSP responder/server URL from the Authority Information Access (AIA) section of the client certificate. If the client certificate lacks an OCSP responder URL or if an alternative URL is preferred, you can override it using the environmental variableOCSP_RESPONDER_URL
.
For thecrl
value, thetls.Config
attempts to obtain the Certificate Revocation List (CRL) file from the CRL Distribution Point section in the client certificate. If the client certificate lacks a CRL distribution point section, or if you prefer to override it, you can use the environmental variablesCRL_DISTRIBUTION_POINTS
andCRL_DISTRIBUTION_POINTS_ISSUER_CERT_FILE
. If no CRL distribution point server is available, you can specify an offline CRL file using the environmental variablesOFFLINE_CRL_FILE
andOFFLINE_CRL_ISSUER_CERT_FILE
.
OCSP_DEPTH
: Depth of client certificate verification in the OCSP method. The default value is 0, meaning there is no limit, and all certificates are verified.OCSP_RESPONDER_URL
: Override value for the OCSP responder URL present in the Authority Information Access (AIA) section of the client certificate. If left empty, it expects the OCSP responder URL from the AIA section of the client certificate.
CRL_DEPTH
: Depth of client certificate verification in the CRL method. The default value is 1, meaning only the leaf certificate is verified.CRL_DISTRIBUTION_POINTS
: Override for the CRL Distribution Point value present in the certificate's CRL Distribution Point section.CRL_DISTRIBUTION_POINTS_ISSUER_CERT_FILE
: Path to the issuer certificate file for verifying the CRL retrieved fromCRL_DISTRIBUTION_POINTS
.OFFLINE_CRL_FILE
: Path to the offline CRL file, which can be used if the CRL Distribution point is not available in either the environmental variable or the certificate's CRL Distribution Point section.OFFLINE_CRL_ISSUER_CERT_FILE
: Location of the issuer certificate file for verifying the offline CRL file specified inOFFLINE_CRL_FILE
.
mProxy relies on the caarlos0/env package to load environmental variables into its configuration.
You can control how these variables are loaded by passing env.Options
to the config.EnvParse
function.
To add a prefix to environmental variables, use env.Options{Prefix: "MPROXY_"}
from the caarlos0/env package. For example:
package main
import (
"github.com/caarlos0/env/v11"
"github.com/absmach/mproxy"
)
mqttConfig := mproxy.Config{}
if err := mqttConfig.EnvParse(env.Options{Prefix: "MPROXY_" }); err != nil {
panic(err)
}
fmt.Printf("%+v\n")
In the above snippet, mqttConfig.EnvParse
expects all environmental variables with the prefix MPROXY_
.
For instance:
- MPROXY_ADDRESS
- MPROXY_PATH_PREFIX
- MPROXY_TARGET
- MPROXY_CERT_FILE
- MPROXY_KEY_FILE
- MPROXY_SERVER_CA_FILE
- MPROXY_CLIENT_CA_FILE
- MPROXY_CERT_VERIFICATION_METHODS
- MPROXY_OCSP_DEPTH
- MPROXY_OCSP_RESPONDER_URL
- MPROXY_CRL_DEPTH
- MPROXY_CRL_DISTRIBUTION_POINTS
- MPROXY_CRL_DISTRIBUTION_POINTS_ISSUER_CERT_FILE
- MPROXY_OFFLINE_CRL_FILE
- MPROXY_OFFLINE_CRL_ISSUER_CERT_FILE