Controlar o ESP8266 sem redirecionamento de portas: um caminho MQTT de saída
Um broker acessível pela internet permite controlar um dispositivo doméstico através de uma ligação que ele próprio abriu. O que isso muda para a memória TLS, os tópicos e a repetição.
O dispositivo está atrás de um router doméstico sem redirecionamento de portas e sem endereço público, e ainda assim tem de receber a configuração em segundos. O truque não é um buraco na firewall. É uma ligação que o dispositivo abre para fora em direção a um broker que consegue alcançar, e que depois devolve as mensagens pelo mesmo caminho já estabelecido. Todas as propriedades que se apreciam neste desenho, e todas as armadilhas que contém, vêm dessa inversão.
O que atravessa realmente o NAT
Quando o dispositivo abre uma ligação TCP ao broker, o router de casa cria um mapeamento e mantém-no vivo enquanto durar o fluxo. As respostas nesse fluxo regressam ao dispositivo porque o mapeamento já existe. O broker nunca inicia nada em direção à casa, por isso não há nenhum pacote de entrada não solicitado que o router tenha de rejeitar. É todo o argumento de rede, e é por isso que a abordagem funciona em redes que não controla.
O dispositivo tem de manter a ligação viva ou restabelecê-la, o que se torna a questão de fiabilidade depois de a arquitetura estar definida.
O broker encaminha tópicos, não faz de proxy HTTP
O MQTT define trocas de publicação e subscrição: o dispositivo subscreve um filtro de tópicos que lhe é permitido ler, e um controlador autorizado publica num tópico correspondente. O broker emparelha as publicações com as subscrições e entrega cópias. Não sabe o que é um pedido de navegador e não reencaminhará um HTTP GET para o servidor web do dispositivo. Se o firmware existente só fala HTTP, o desenho com broker exige uma alteração da aplicação ou um componente de tradução deliberado.
Os nomes dos tópicos também não são autorização. A maioria dos brokers suporta listas de controlo de acesso por cliente, e os dispositivos devem ficar restritos às suas próprias árvores de publicação e subscrição em vez de partilharem um único espaço de nomes global.
Os recursos do dispositivo decidem a forma do TLS
O ESP8266 tem RAM limitada, e o handshake TLS é a coisa mais cara que faz. O núcleo Arduino fornece o BearSSL precisamente por causa desta restrição, e a escolha entre verificar uma CA e fixar uma impressão digital altera tanto o consumo de memória como aquilo que um atacante com um certificado válido para outro nome pode fazer. Verificar a CA do broker é a opção mais forte quando a heap o permite. O tamanho da carga útil também importa: o cliente MQTT mantém um buffer, e as mensagens maiores são truncadas em silêncio a menos que o buffer seja aumentado deliberadamente.
O keepalive e os tempos limite do socket fazem parte do mesmo orçamento, porque um cliente que nunca nota uma ligação morta deixa de receber comandos sem reportar um erro.
A semântica das mensagens que morde
Uma mensagem retida é guardada pelo broker e entregue a subscritores correspondentes posteriores, o que é excelente para o estado atual e perigoso para comandos de uso único: um dispositivo que se reconecta pode receber o comando de ontem como se fosse novo. O QoS 1 garante entrega pelo menos uma vez, por isso as duplicações são normais e a aplicação tem de ser segura face a repetições, idealmente com um identificador ou um timestamp que possa rejeitar. O último testamento dá-lhe um sinal de estado quando o dispositivo cai, mas apenas se a ligação falhar mesmo em vez de ficar pendurada.
O comportamento de sessão limpa decide se o broker mantém as suas subscrições enquanto está fora, e errar nisso é a razão pela qual alguns dispositivos perdem a primeira mensagem após cada reconexão.
O TLS protege o troço até ao broker. Não é cifra da carga útil de ponta a ponta contra o operador do broker, que pode ler tudo o que publica através dele.
Limite o ciclo de vida e teste-o com dados inofensivos
Planeie a reconexão com recuo em vez de um ciclo de tentativas apertado, volte a subscrever explicitamente se a sessão não for persistente, e registe o resultado da ligação para que um dispositivo offline e silencioso deixe provas. Teste o caminho de reconexão com cargas de exemplo que não fazem nada, porque o primeiro teste de produção de um canal de comandos não deve ser um comando real. Depois confirme o que faz uma mensagem retida obsoleta na reconexão, e decida se esse comportamento é aceitável para cada tópico.
Feito assim, o desenho remove um requisito de rede de entrada e deixa o software do dispositivo, a política do broker e a semântica das mensagens como trabalho visível em vez de suposições escondidas.