Mochi Broker mTLS #447
-
Hello, First of all, amazing project! Use caseI have a usecase where multiple devices are connecting to the mochi broker using mTLS. How to do itThough about creating a hook when a message is published to check if the device who is sending it really is him according to the SAN field of his TLS certificate. ProblemNo way to access the mqtt client TLS info using the default lib provided by the hooks, or just couldn't figure out how to do it. Open to suggestions and alternatives. If that's a limitation of the library I'm also willing to help with. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
Hey @leandrofars I have a hook that provides Here is a sample implementation of our OnConnectAuthenticate function: func (ah *ACLHook) OnConnectAuthenticates(cl *mqtt.Client, pk packets.Packet) bool {
var flag bool
var deviceInfo *DeviceInfos
var parseError error
tlsConn, ok := cl.Net.Conn.(*tls.Conn)
if !ok {
slog.Error("Error while getting tls connection")
return false
}
// check that clientid and certificate common name match
for _, cert := range tlsConn.ConnectionState().PeerCertificates {
if cl.ID == cert.Subject.CommonName {
deviceInfo, parseError := GetDeviceInfoFromCert(cert)
if parseError != nil {
continue
}
slog.Debug("Device info from cert", "deviceInfo", deviceInfo)
slog.Debug("Client ID", "clientID", cl.ID)
flag = true
}
}
if !flag {
// if the clientid and certificate common name do not match, disconnect the client
if parseError != nil {
slog.Error("Error while parsing device info from cert", "error", parseError)
}
// if not, disconnect the client
slog.Error("Invalid clientID, no such device/service registered", "clientID", cl.ID)
cl.Stop(mqtt.ErrInvalidConfigType)
return false
}
return true The function that is used to extract information from the certificate can be customised based on the data you're storing in the certifcate, here is a sample for the type DeviceInfo struct {
DeviceID string
ProjectID string
FleetID string
OrgID string
DeviceName string
}
// Extracts device info from a certificate
func GetDeviceInfoFromCert(cert *x509.Certificate) (*DeviceInfo, error) {
deviceName := cert.Subject.CommonName
if deviceName == "" {
return nil, errors.New("missing commonName (device name) in certificate")
}
deviceId := cert.Subject.SerialNumber
if (deviceId == "") || (len(deviceId) == 0) {
return nil, errors.New("missing serialNumber (device id) in certificate")
}
if (cert.Subject.Organization == nil) || (len(cert.Subject.Organization) == 0) {
return nil, errors.New("missing organization in certificate")
}
orgId := cert.Subject.Organization[0]
if (cert.Subject.OrganizationalUnit == nil) || (len(cert.Subject.OrganizationalUnit) < 1) {
return nil, errors.New("missing organizational units (projectId/fleetId) in certificate")
}
fleetAndProjectId := strings.Split(cert.Subject.OrganizationalUnit[0], ";")
return &DeviceInfo{
DeviceID: deviceId,
FleetID: fleetAndProjectId[0],
ProjectID: fleetAndProjectId[1],
OrgID: orgId,
DeviceName: deviceName,
}, nil
} The key piece you're looking for is getting the |
Beta Was this translation helpful? Give feedback.
-
Also look at this discussion : https://github.com/orgs/mochi-mqtt/discussions/87 |
Beta Was this translation helpful? Give feedback.
Hey @leandrofars
Here is how we're doing this in production today:
I have a hook that provides
mqtt.OnConnectAuthenticate
andmqtt.OnACLCheck
Here is a sample implementation of our OnConnectAuthenticate function: