-
-
Notifications
You must be signed in to change notification settings - Fork 327
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
Support MQTT certificate and the key for the gateway backend #201
Changes from 6 commits
e7937d8
a3d9e5d
fd40a56
0ebc1f4
2f57c4b
aa84f53
35e026e
0fd156c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,8 @@ GLOBAL OPTIONS: | |
--mqtt-username value mqtt server username (optional) [$MQTT_USERNAME] | ||
--mqtt-password value mqtt server password (optional) [$MQTT_PASSWORD] | ||
--mqtt-ca-cert value mqtt CA certificate file used by the gateway backend (optional) [$MQTT_CA_CERT] | ||
--mqtt-tls-cert value mqtt certificate file used by the gateway backend (optional) [$MQTT_CERT] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
--mqtt-tls-key value mqtt key file of certificate used by the gateway backend (optional) [$MQTT_CERT_KEY] | ||
--as-public-server value ip:port of the application-server api (used by LoRa Server to connect back to LoRa App Server) (default: "localhost:8001") [$AS_PUBLIC_SERVER] | ||
--as-public-id value random uuid defining the id of the application-server installation (used by LoRa Server as routing-profile id) (default: "6d5db27e-4ce2-4b2b-b5d7-91f069397978") [$AS_PUBLIC_ID] | ||
--bind value ip:port to bind the api server (default: "0.0.0.0:8001") [$BIND] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,8 @@ import ( | |
|
||
log "github.com/sirupsen/logrus" | ||
|
||
"errors" | ||
|
||
"github.com/brocaar/lora-app-server/internal/common" | ||
"github.com/brocaar/lora-app-server/internal/handler" | ||
mqtt "github.com/eclipse/paho.mqtt.golang" | ||
|
@@ -36,7 +38,7 @@ type MQTTHandler struct { | |
} | ||
|
||
// NewHandler creates a new MQTTHandler. | ||
func NewHandler(server, username, password, cafile string) (handler.Handler, error) { | ||
func NewHandler(server, username, password, cafile, certFile, certKeyFile string) (handler.Handler, error) { | ||
h := MQTTHandler{ | ||
dataDownChan: make(chan handler.DataDownPayload), | ||
} | ||
|
@@ -48,13 +50,16 @@ func NewHandler(server, username, password, cafile string) (handler.Handler, err | |
opts.SetOnConnectHandler(h.onConnected) | ||
opts.SetConnectionLostHandler(h.onConnectionLost) | ||
|
||
if cafile != "" { | ||
tlsconfig, err := newTLSConfig(cafile) | ||
if err != nil { | ||
log.Fatalf("Error with the mqtt CA certificate: %s", err) | ||
} else { | ||
opts.SetTLSConfig(tlsconfig) | ||
} | ||
tlsconfig, err := newTLSConfig(cafile, certFile, certKeyFile) | ||
if err != nil { | ||
log.WithError(err).WithFields(log.Fields{ | ||
"ca_cert": cafile, | ||
"tls_cert": certFile, | ||
"tls_key": certKeyFile, | ||
}).Fatalf("error loading mqtt certificate files") | ||
} | ||
if tlsconfig != nil { | ||
opts.SetTLSConfig(tlsconfig) | ||
} | ||
|
||
log.WithField("server", server).Info("handler/mqtt: connecting to mqtt broker") | ||
|
@@ -70,23 +75,57 @@ func NewHandler(server, username, password, cafile string) (handler.Handler, err | |
return &h, nil | ||
} | ||
|
||
func newTLSConfig(cafile string) (*tls.Config, error) { | ||
func newTLSConfig(cafile, certFile, certKeyFile string) (*tls.Config, error) { | ||
// Here are three valid options: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry for commenting on this again, but maybe it is better to remove the whole check at all. E.g. when the user does only provide a tls cert or only a tls key, |
||
// - Only CA | ||
// - TLS cert + key | ||
// - CA, TLS cert + key | ||
// Ref: https://github.com/brocaar/lora-app-server/pull/201#discussion_r162909271 | ||
|
||
if (certFile == "" || certKeyFile == "") && (certFile != certKeyFile) { // check exclusive empty string (like XOR) | ||
log.WithFields(log.Fields{ | ||
"cafile": cafile, | ||
"certFile": certFile, | ||
"certKeyFile": certKeyFile, | ||
}).Error(`handler/mqtt: TLS config is invalid. Both certFile and certKeyFile must be specified. MQTT TLS configuration allows three patterns: | ||
1. Only CA | ||
2. TLS cert + key | ||
3. CA, TLS cert + key | ||
`) | ||
return nil, errors.New("handler/mqtt: TLS config is invalid. Both certFile and certKeyFile must be specified") | ||
} | ||
|
||
if cafile == "" && certFile == "" && certKeyFile == "" { | ||
log.Info("handler/mqtt: TLS config is empty") | ||
return nil, nil | ||
} | ||
|
||
tlsConfig := &tls.Config{} | ||
|
||
// Import trusted certificates from CAfile.pem. | ||
if cafile != "" { | ||
cacert, err := ioutil.ReadFile(cafile) | ||
if err != nil { | ||
log.Errorf("handler/mqtt: couldn't load cafile: %s", err) | ||
return nil, err | ||
} | ||
certpool := x509.NewCertPool() | ||
certpool.AppendCertsFromPEM(cacert) | ||
|
||
cert, err := ioutil.ReadFile(cafile) | ||
if err != nil { | ||
log.Errorf("backend: couldn't load cafile: %s", err) | ||
return nil, err | ||
tlsConfig.RootCAs = certpool // RootCAs = certs used to verify server cert. | ||
} | ||
|
||
certpool := x509.NewCertPool() | ||
certpool.AppendCertsFromPEM(cert) | ||
// Import certificate and the key | ||
if certFile != "" && certKeyFile != "" { | ||
kp, err := tls.LoadX509KeyPair(certFile, certKeyFile) | ||
if err != nil { | ||
log.Errorf("handler/mqtt: couldn't load MQTT TLS key pair: %s", err) | ||
return nil, err | ||
} | ||
tlsConfig.Certificates = []tls.Certificate{kp} | ||
} | ||
|
||
// Create tls.Config with desired tls properties | ||
return &tls.Config{ | ||
// RootCAs = certs used to verify server cert. | ||
RootCAs: certpool, | ||
}, nil | ||
return tlsConfig, nil | ||
} | ||
|
||
// Close stops the handler. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
-----BEGIN CERTIFICATE REQUEST----- | ||
MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx | ||
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN | ||
AQEBBQADggEPADCCAQoCggEBAN7nJ2aEeOJRMjT5Gevrlu37thYfn9nz5M/YXD3x | ||
CYoeUKToRTPF8L8QlsQxTzIV9DOYr6BCUQPtymwJxae+rEc8bbtxcSq+3fI/dBAR | ||
u3CJei1SGR8Zv/X5jM8pWYdNoeNUGO5sxzWJLODNycANn9Bkb9pVtGVi0tysPIdF | ||
TLV8HqoA3vvPRENWpYq9YCvFVWCdOB8ZgwhceBhdmsvyQ3UNzUAKXTOwMLMgfo85 | ||
n3vZ7XFrmaUKUrfi02kEkrCkIf18lKY6nleKczZFasDMukqvOUR9PCGKLDM8Zizi | ||
B7Z53MU+L88FGTimrwBt/zIj78ByGBdIMcCInHE96SxgFzkCAwEAAaAAMA0GCSqG | ||
SIb3DQEBCwUAA4IBAQB8S5AjJ6gBqgnyl21exumJ6yq01GRtFPSBETS5ZtePg2XS | ||
Un00AWBcQvR8wo9Ul4Oyg/BlUzhSLV8vy3dRN/ssiM+UyLCDftvcthsdgve3baQ9 | ||
EX5gw5EYwE6rJs5WERkuoEamLgqaFzZOohMkPPbtqk5aLXOHRNmIUXRmz+Muqkgg | ||
a7vUvlrnZqX2Tk6RTIaQyo8y4u1/nJPXqTd7bfipam2j3+N34+ssFr0Q/GgaEEuS | ||
Cs5OxniMbSKRPzcyEGf8wu8mkTSaxVCOnPjywdV7ld/UMhc+nCmzd34ffzahR5DS | ||
bwiH9uAGL8hoSeaT+iZA9usLHuuutuPM/hVb28jo | ||
-----END CERTIFICATE REQUEST----- |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
-----BEGIN CERTIFICATE----- | ||
MIIDBjCCAe4CCQCHfd3pnzIMRzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB | ||
VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 | ||
cyBQdHkgTHRkMB4XDTE4MDEyMzA3NDIxOFoXDTE4MDIyMjA3NDIxOFowRTELMAkG | ||
A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 | ||
IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB | ||
AN7nJ2aEeOJRMjT5Gevrlu37thYfn9nz5M/YXD3xCYoeUKToRTPF8L8QlsQxTzIV | ||
9DOYr6BCUQPtymwJxae+rEc8bbtxcSq+3fI/dBARu3CJei1SGR8Zv/X5jM8pWYdN | ||
oeNUGO5sxzWJLODNycANn9Bkb9pVtGVi0tysPIdFTLV8HqoA3vvPRENWpYq9YCvF | ||
VWCdOB8ZgwhceBhdmsvyQ3UNzUAKXTOwMLMgfo85n3vZ7XFrmaUKUrfi02kEkrCk | ||
If18lKY6nleKczZFasDMukqvOUR9PCGKLDM8ZiziB7Z53MU+L88FGTimrwBt/zIj | ||
78ByGBdIMcCInHE96SxgFzkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAiHFpOL81 | ||
IjcEhifBZnJJvGjskU8Tb9+cMncUhZh7jLYRI6c1OHcSdF3KF7YdDoCTqV5BCHkV | ||
+ogqGRVwZ/2CYToK8tR1oXVIVpd72sKvvtncSkplLVpqThwmq5JOB+wPGXe5eQKa | ||
4uljcoRB5Nf+0qhomuqoO4izqWQNSQFtW7cEnXoEgM2rZolYLTHQMPN1UKMKcTkD | ||
5/1RA4hHoDjFBd9dCUWzZJE4uyzF5HcAS5K4FOCXwvdrA93VSzPxP0ksnQo0rHkG | ||
RiZfEYaLd6rCcuHJJWG45XIRXQK24HvB5R79XnRVt0Uvzq9sW2+t38gKc3KvmIbH | ||
fTSaOkfzXm+l8w== | ||
-----END CERTIFICATE----- |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
-----BEGIN RSA PRIVATE KEY----- | ||
MIIEpgIBAAKCAQEA3ucnZoR44lEyNPkZ6+uW7fu2Fh+f2fPkz9hcPfEJih5QpOhF | ||
M8XwvxCWxDFPMhX0M5ivoEJRA+3KbAnFp76sRzxtu3FxKr7d8j90EBG7cIl6LVIZ | ||
Hxm/9fmMzylZh02h41QY7mzHNYks4M3JwA2f0GRv2lW0ZWLS3Kw8h0VMtXweqgDe | ||
+89EQ1alir1gK8VVYJ04HxmDCFx4GF2ay/JDdQ3NQApdM7AwsyB+jzmfe9ntcWuZ | ||
pQpSt+LTaQSSsKQh/XyUpjqeV4pzNkVqwMy6Sq85RH08IYosMzxmLOIHtnncxT4v | ||
zwUZOKavAG3/MiPvwHIYF0gxwIiccT3pLGAXOQIDAQABAoIBAQDEt5/QG+1LXnk+ | ||
wvCbgskqslBaagJ7KYGv5LRTfhv7JxHo14vrSy9Sj+Netl28SB/CQWgNuTkijINu | ||
oZksl1wXaj81g8JqBRR/LHzTibKweMO4p5HAHsuI23nnggifHmZW5+sw0BNnLe7L | ||
XxJESkHWei00tRqFt5d8ZQzuHLy8FG4zaQpc1O957W91uIj4yjC6Z+NApSRy7Qtw | ||
co/2cIo2a53pxbsyWHs12Wm/OE21cKMZvWtxNprVDlISY41JL6/Qgi8j89DijFst | ||
TueKx+FB80BtlAM7+dRyvt7aGbyhRhC8+irBA8vMqxiz0XjDUV/oc6xzpXTemhyu | ||
878CarnZAoGBAPnTp3iG+rIQ0zMnGyTtBLSvQg+RQVNWkru8J1plLUAVt509oiaN | ||
/BpiekD5CH6NGar0UJcq9oHFIFrV90zsi7e7OAFTmtmRzG3nnvRp1zpeic5LBbVb | ||
KTmELpZrfaUk4nUHQTGcq+SKK8RzZoeJb5juWMQJFrWCKfP/7G5p9LXnAoGBAORp | ||
L5U5RCl2OIPFH86oJJcTmKgs7XilZaQdsCMhmq/4dLMxy4p8t/vxSh3JUFQ00wq8 | ||
M9XOKA1pO+Ad5KaUmTGu0J7f2YIxTRxXqVprvyxCj2eo+IuZd1nvQ0W+XK4ndT5+ | ||
npEImTjbmK4zXQN6TxJ2wzxRCZp3FQlV2P/u0uXfAoGBAMt5EEBBJ3PZ8joKUrhb | ||
dua2i0ZkluEKdM4Eq8Sa/SThyz99EFD4eWj/5fR/H+T6hPpQrEbCzizZYcW52QZE | ||
7nLBQBcMgeVMM0UcTcFhZtN6ZiCnx8lyqvvWZZ9LgvT7Opn4Q6flo7aqtoT1PH+N | ||
d2AGWDOp913z2rmJKoavM4jnAoGBAM8ga5vgcGVA5YLosS1P4M53YMmw5C+xnPg0 | ||
S9Ov13yXzAvrre4JpzX62wEj24pg1Lg5brAF4OA4e6mCsiQ1QK6DHn/T8oRTfN+k | ||
xthOOPBD85NG8Qx2wHp3tAN82sK62WEwpU5UA85BpLTjswdCVI4j0GvT+Odv8U2j | ||
4cJEqk71AoGBAKqvwZ/QXcxsLqF5QBb2wBrleiezci3eLM0h2t7BYZWgAQ7jP3rx | ||
Lv0LVfBFwDF63QA5IekwaWjBBL2LVJF8i4tLC0r6yYdXAfeWtiZnmDNlsJMY3vML | ||
vqemBbFZNqvxwI0DEHMBTqrnjJaf76elPz388jreHfnJMzymEjQcjm6Y | ||
-----END RSA PRIVATE KEY----- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
c.String("mqtt-cert"), c.String("mqtt-cert-key")
That should be
mqtt-tls-cert
anmqtt-tls-key
I think?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uh oh, I missed... Sorry.