Debugging della connessione VerneMQ / problemi di autenticazione per la doppia autenticazione con webhooks e vmq_diversity

TL;DR

https://github.com/vernemq/vernemq/blob/master/apps/vmq_diversity/src/vmq_diversity_plugin.erl

include una dichiarazione che bloccherà l'autenticazione / autorizzazione attraverso qualsiasi altro canale se il vostro script Lua restituisce "false":

immagine

porterà a:

immagine

invece di provare altri plugin, come si potrebbe pensare!

Per evitare questo problema, semplicemente non restituire nulla dal tuo script Lua, se non vuoi gestire il messaggio!

immagine

Debugging

VerneMQ ha uno strumento di tracciamento integrato, che vi aiuterà a vedere quali problemi possono verificarsi. Per prima cosa, visualizzate le sessioni, per scoprire con quali dati i vostri client stanno cercando di connettersi:

vmq-admin mostra la sessione

immagine

Poi eseguire una traccia:

vmq-admin trace client client-id=000000007eaefc47 -mountpoint=5c61a59ba6b76f558d256f42

Si noti che il punto di mount predefinito è "" (il punto di mount predefinito per Verne) - se non si sta impostando un punto di mount personalizzato sugli ascoltatori (come me), allora si può omettere questo.

immagine

Inizialmente vmq-admin trace riporterà che non sono state trovate sessioni per questo client - se il vostro client non è attualmente connesso.

Collegate il vostro cliente, e ci saranno più uscite.

È anche utile aumentare il livello di verbosità nel logger per il debug (per vernemq.conf):

log.console.level = debug

immagine

econnrefused

Nel mio caso particolare, il mio endpoint webhook non era in esecuzione. Dopo averlo avviato, ora ottengo (più tentativi con output simili):

immagine

Come potete vedere, il client viene ora autenticato, ma non è autorizzato a pubblicare. Il client viene quindi disconnesso (come da specifiche MQTT 3.1.1).

E questo è l'output del log:

immagine

quello che sta succedendo qui, è che il client viene autenticato utilizzando un webhook, e poi cerca di diventare autorizzato utilizzando uno script Lua (autorizzazione MongoDB).

Non sono sicuro del perché auth_on_publish per il client non sia chiamato usando anche un webhook. Questo client in ogni caso dovrebbe essere autenticato completamente usando MongoDB.

Vedo anche solo richieste di registro auth-on:

immagine

Per mostrare quali webhooks sono registrati, si può eseguire

vmq-admin webhooks show

immagine

vedere: https://docs.vernemq.com/plugindevelopment/webhookplugins

Tutti i webhooks sono chiamati con il metodo POST, e devono ricevere una risposta con il codice HTTP 200 per essere considerati di successo.

Una richiesta per il server webhook

Ecco come apparirà una richiesta per il server Webhook:

immagine

vengono passate le intestazioni, con l'intestazione vernemq-hook impostata su auth_on_register in questo caso.

Il corpo del post includerà diverse informazioni sul client che cerca di connettersi.

Dopo aver usato "next" come risposta dal webhook, la pubblicazione funziona correttamente - il client viene autenticato contro il MongoDB, e poi la pubblicazione viene autorizzata, come desiderato.

Ecco come dovrebbe essere la risposta del webhook per passare l'autenticazione al prossimo plugin:

{"risultato": "next"}

Ed ecco come appare ora la traccia:

immagine

In basso potete vedere i keepalives per il client (PINGREQ, PINGRESP).

Quindi, un client funziona ora. Passiamo al prossimo client - che dovrebbe essere autenticato e autorizzato usando i webhooks!

Cliente webhook

immagine

Come potete vedere, tra l'altro, il mountpoint viene riscritto da "piclient" a un mountpoint diverso dallo script MongoDB Lua.

Fondamentalmente sto usando il mountpoint sugli ascoltatori per indicare quale metodo di autenticazione dovrebbe essere usato per questo client.

Nella versione 2 di VerneMQ, ci è stato promesso, ci sarà una separazione dei Plugin per Listener - quindi possiamo evitare questi controlli che aggiungono overhead ad ogni connessione.

immagine

apparentemente solo una traccia può essere eseguita alla volta. Provando di nuovo dopo aver chiuso l'altra traccia:

vmq-admin trace client client-id=my_clientid -mountpoint=jsclient

immagine

immagine

immagine

Notate che il messaggio auth_on_publish debug è stampato da una dichiarazione aggiuntiva che ho inserito nello script Lua:

immagine

in auth_commons.lua

Capire cosa restituire dallo script Lua

Quello che vogliamo è probabilmente ritornare dallo script Lua che il prossimo hook dovrebbe essere chiamato.

"Nel caso in cui il plugin non possa convalidare il messaggio di pubblicazione, è meglio restituire prossimo poiché questo permetterebbe ai plugin successivi nella catena di convalidare la richiesta".

(vedere https://docs.vernemq.com/plugindevelopment/publishflow )

Ho pensato che il ritorno falso implicherebbe questo, ma a quanto pare no?

Guardiamo nel sorgente Erlang di vernemq

https://github.com/vernemq/vernemq

Questa è una suite di test per l'auth_cache per vmq_diversity (dove vivono gli script Lua):

https://github.com/vernemq/vernemq/blob/c8b92f398e76d6ce4b8cca5e438e8ae1e717d71c/apps/vmq_diversity/test/vmq_diversity_auth_cache_SUITE.erl

immagine

vmq-admin trace client client-id=my_clientid -mountpoint=jsclient

immagine

Aggiungendo un po' di debug aggiuntivo per il messaggio in Lua:

funzione auth_on_publish(pub)
     print("***auth_on_publish debug*** (LUA)")
     per k,v in coppie(pub) fare
         stampa(k .. " " .. v)
     fine
     stampa(pub)
     restituire falso
fine

immagine

Si noti che il codice sembra essere difettoso (i falsi apparentemente non possono essere concatenati usando .. in Lua - OK.)

In ogni caso, nella tabella Lua, che viene passata come "pub", abbiamo i seguenti parametri:

  • client_id
  • punto di montaggio
  • carico utile
  • qos

ora potremmo controllare che il mountpoint sia "jsclient" (che dovrebbe essere autenticato usando webhooks), e per ora forzare true:

funzione auth_on_publish(pub)
     print("***auth_on_publish debug*** (LUA)")
     se pub["mountpoint"] == "jsclient" allora
         ritorna vero
     else
         restituire falso
     fine
fine

Ecco come appare una traccia per questa condizione artificiale:

immagine

Torna a Erlang

https://github.com/vernemq/vernemq/blob/master/apps/vmq_diversity/src/vmq_diversity_plugin.erl

immagine

quando auth_on_publish è chiamato per il vmq_diversity_plugin.erl il valore del risultato sarà ottenuto così:

  • se vmq_diversity_cache:match_publish_acl restituirà true, sarà "ok".
  • se restituisce false, lancerà un errore
  • se restituisce no_cache, il risultato dipenderà dalla funzione all_till_ok (chiamata con auth_on_publish)

come potete vedere qui ci sono i valori passati al nostro script Lua, incluso il punto di montaggio

conv_res modificherà il risultato restituito:

immagine

Vi consiglio vivamente, se non avete familiarità con Erlang, di leggere il mio articolo precedente, https://pi3g.com/2019/05/12/understanding-erlang-lua-luerl-for-vernemq-mongodb-auth_on_register-hook/

Fondamentalmente se {errore, lua_script_returned_false} non è abbinato all'interno dei risultati, per qualsiasi nome (_) e qualsiasi Altro, il risultato sarà Altro - semplicemente passando i risultati di all_till_ok alla funzione chiamante.

Per il nome lua_script_returned_falsel'errore sarà not_authorized.

Non sono del tutto sicuro che questo vmq_plugin_helper.erl sia dove si trova la principale logica di controllo (del passaggio al prossimo):

immagine

in ogni caso, probabilmente ci si aspetta che venga restituito "next".

Qui, in vmq_diversity_plugin.erl è definito all_till_ok:

https://github.com/vernemq/vernemq/blob/master/apps/vmq_diversity/src/vmq_diversity_plugin.erl

immagine

Come potete vedere, se lo script restituisce "true", il valore di ritorno è impostato su "ok".

Se viene restituito "false" dallo script, viene restituito l'errore precedentemente menzionato, e l'esecuzione si ferma -> non autorizzato.

immagine

Questo significa che se si restituisce false negli script Lua, nessun altro plugin sarà chiamato!

in alternativa possono essere restituiti dei modificatori.

Il trucco è di non restituire nulla, nel caso in cui non si voglia gestire la richiesta:

funzione auth_on_publish(pub)
     print("***auth_on_publish debug*** (LUA)")
     se pub["mountpoint"] == "jsclient" allora
         print("*** jsclient rilevato ***")
         print("non restituisce nulla")
         - ritorna vero
    else
         print("+++ altro client rilevato +++")
         restituire falso
     fine
fine

Notate che - (due trattini) è un commento in Lua.

immagine

In questo caso, l'hook auth_on_publish viene chiamato usando i webhooks:

immagine

immagine

immagine

Bonus

Errore nel generare la configurazione con cuttlefish:

Questo può essere debuggato ulteriormente impostando il comando in docker-compose.yml a:

comando: "vernemq config generate -l debug /vernemq/etc/vernemq.conf.local"

e portando su il contenitore (si noti che ho creato un file .local, quindi certe impostazioni non vengono più sovrascritte).

Il messaggio di errore che ottengo è:

jalpine_morpheus | escript: errore di eccezione: nessuna clausola di funzione corrispondente
jalpine_morpheus | lists:unzip([[ws,ws],
jalpine_morpheus | {["log", "console", "file"],"./log/console.log"},

apparentemente questo è legato alle seppie che soffocano sulle linee che contengono solo uno spazio:

https://github.com/basho/cuttlefish/issues/222

premendo Alt + P in nano abiliterà la visualizzazione degli spazi bianchi - buono per il debug di questo particolare problema.

La sezione problematica nella mia configurazione assomiglia a questa:

immagine

qui ci sono due schede (?) dove non dovrebbe esserci nulla.

Rimuovendo la linea problematica, VerneMQ potrà ripartire.

Ulteriori letture

Anche questo potrebbe essere utile:

http://www.steves-internet-guide.com/mqtt-protocol-messages-overview/

Changelog di VerneMQ:

https://github.com/vernemq/vernemq/blob/fe514561cbeebb2ac4f7c98a87c64d766587c1d7/changelog.md

NB: nella versione 1.8 un nuovo plugin interessante è il plugin vmq_pulse, che spingerà le informazioni del cluster a un backend pulse via HTTP(S).

https://github.com/vernemq/vernemq/blob/c8b92f398e76d6ce4b8cca5e438e8ae1e717d71c/apps/vmq_diversity/test/cache_test.lua

Mostra alcuni script Lua aggiuntivi per la diversità di VerneMQ.