O blog da AWS

Autenticação Customizada do AWS IoT Core

Por Gerson Itiro Hidaka atualmente, Enterprise Solution Architect na AWS

 

Introdução

O broker MQTT (Message Queue and Telemetry Transport) é um message broker amplamente utilizado pelas empresas de automação residencial, rastreamento veicular, monitoração industrial, e vários outros ramos da indústria para controlar a entrega de mensagens entre os dispositivos ou para transportar mensagens para um sistema centralizado. Várias dessas empresas criaram, no passado, seus sistemas de IoT (Internet of Things) no ambiente on premises para atender seus clientes e atualmente estudam formas de migrar o message broker para a nuvem.

Quando iniciamos a configuração do broker MQTT na AWS (serviço AWS IoT Core), criamos as Things e geramos os certificados e chaves para a autenticação mTLS (mutual TLS), ou seja, a autenticação tanto do servidor quanto do cliente. Esse é o modo padrão de autenticação, implementado pela AWS no serviço AWS IoT Core, desde a concepção do serviço e exige a cópia de arquivos (certificado, chave privada e root CA) para o dispositivo final. Algumas empresas já operam com brokers MQTT no ambiente on premises mas utilizam o modo user/password para a autenticação. A troca do modo de autenticação em alguns casos pode ser um grande blocker para a migração deste tipo de workload para a nuvem.

Pensando nisso, a AWS lançou uma funcionalidade do AWS IoT Core, que permite a definição de workflows de autenticação e autorização customizados, chamados de Custom Authorizers, para chamar serviços externos de gerenciamento de identidade e assim autenticar dispositivos e autorizar suas operações no message broker. Como resultado, os clientes podem usar credenciais de dispositivo, como JSON Web Tokens (JWT) ou combinações de nome de usuário e senha MQTT, geradas por seu próprio serviço de provisionamento, para conectar seus dispositivos ao AWS IoT Core. Isso elimina a necessidade de provisionar novas credenciais para frotas de dispositivos já em campo, proporcionando aos clientes flexibilidade e facilidades adicionais ao conectar seus dispositivos ao AWS IoT Core.

O objetivo deste AWS Blog Post é compartilhar uma configuração simples do Custom Authorizer com o Lambda e que poderá ser adaptado por cada empresa para atingir o estado desejado.

O diagrama abaixo representa o sistema que iremos criar para testar o Custom Authorizer do AWS IoT Core e é composto de 4 principais serviços / componentes:

 

Figure 1 – Workflow do Custom Authorizer

 

  1. O AWS IoT Core permite que você conecte os dispositivos de IoT à nuvem da AWS sem a necessidade de provisionar ou gerenciar servidores. O AWS IoT Core pode comportar bilhões de dispositivos e trilhões de mensagens, bem como processar e rotear essas mensagens para endpoints da AWS e para outros dispositivos de forma confiável e segura.
  2. O AWS Lambda permite que você execute um código sem provisionar ou gerenciar servidores. Utilizaremos a Lambda para realizar a validação das credenciais do dispositivo e enviar ao AWS IoT Core a política de acesso (JSON).
  3. O Amazon Timestream é um serviço de banco de dados de séries temporais rápido, escalável e sem servidor para aplicações operacionais e de IoT. O serviço facilita o armazenamento e a análise de trilhões de eventos por dia com velocidade até mil vezes maior e um décimo do custo dos bancos de dados relacionais. O Amazon Timestream reduz o tempo e o custo do gerenciamento do ciclo de vida de dados de séries temporais mantendo os dados recentes na memória e transferindo dados históricos para um nível de armazenamento otimizado para custo de acordo com políticas definidas pelo usuário.
  4. O Node-RED é uma ferramenta de desenvolvimento baseada em fluxo para programação visual (flow based programming) desenvolvido para conectar dispositivos de hardware, APIs, e serviços online como parte da Internet das Coisas. O Node-RED fornece um editor de fluxo baseado em navegador web, que pode ser usado para criar funções JavaScript e os elementos dos aplicativos podem ser salvos ou compartilhados para reutilização. O runtime é construído em Node.js e os fluxos criados no Node-Red são armazenados usando JSON. Para fins de demonstração criamos um simples protótipo utilizando o Node-Red.

 

Mão na Massa 1: Criando o Lambda Custom Authorizer

O primeiro passo será a criação do autorizador e para isso utilizaremos uma função no AWS Lambda.

  1. Após efetuar a autenticação na AWS Management Console, procurar pelo serviço Lambda no campo Search.
  2. Selecionar o botão Create Function
  3. Na sessão Basic information preencher os seguintes campos:
  • Function Name: myLambdaAuthorizer
  • Runtime: Node.js 14.x

OBS: Manter os demais campos com os valores padrão.

  1. Na sessão Code Source clicar no arquivo index.js e substituir o código padrão pelo exemplo abaixo. Note que alguns trechos do código, assinalados em verde, deverão ser substituídos pelas informações da sua AWS Account.

OBS Utilizamos o mesmo código apresentado na documentação oficial do AWS IoT Core.

 

// A simple Lambda function for an authorizer. It demonstrates
// how to parse an MQTT password and generate a response.

exports.handler = function(event, context, callback) {
    var uname = event.protocolData.mqtt.username;
    var pwd = event.protocolData.mqtt.password;
    var buff = new Buffer.from(pwd, 'base64');
    var passwd = buff.toString('ascii');
    switch (passwd) {
        case 'test':
            callback(null, generateAuthResponse(passwd, 'Allow'));
        default:
            callback(null, generateAuthResponse(passwd, 'Deny')); 
    }
};

// Helper function to generate the authorization response.
var generateAuthResponse = function(token, effect) {
    var authResponse = {};
    authResponse.isAuthenticated = true;
    authResponse.principalId = 'TEST123';
    var policyDocument = {};
    policyDocument.Version = '2012-10-17';
    policyDocument.Statement = [];
    var publishStatement = {};
    var connectStatement = {};
    connectStatement.Action = ["iot:Connect"];
    connectStatement.Effect = effect;
    connectStatement.Resource = ["arn:aws:iot:<region>:<account_id>:client/myClientName"];
    publishStatement.Action = ["iot:Publish"];
    publishStatement.Effect = effect;
    publishStatement.Resource = ["arn:aws:iot:<region>:<account_id>:topic/telemetry"];
    policyDocument.Statement[0] = connectStatement;
    policyDocument.Statement[1] = publishStatement;
    authResponse.policyDocuments = [policyDocument];
    authResponse.disconnectAfterInSeconds = 3600;
    authResponse.refreshAfterInSeconds = 300;

    return authResponse;
}

 

OBS: Esta função Lambda faz a autenticação da conexão MQTT e deverá ser modificada para contemplar a o workflow de autenticação do seu sistema.

O principal ID é utilizado para identificar os Logs no Amazon CloudWatch Logs e poderá ser substituído por qualquer string. Neste exemplo estamos utilizando o Client ID “myClientName” e o tópico “telemetry”. As partes em verde no código deverão ser substituídas de acordo com o seu projeto.

  1. Selecionar o botão “Deploy”. Pronto, sua função básica de autorização já está criada. Vamos para o próximo passo que será a criação do Custom Authorizer no AWS IoT Core.

Mão na Massa 2: Configurando o Custom Authorizer no AWS IoT Core

  1. Para a configuração do AWS IoT Core utilizaremos a linha de comando (CLI). Através do terminal digitar o seguinte comando para criar o custom authorizer. Substituir a <region> pela região que irá utilizar e substituir o <account-id> pelo número da sua conta AWS.
aws iot create-authorizer \
--authorizer-name my-authorizer \
--authorizer-function-arn arn:aws:lambda:<region>:<account-id>:function:my-lambda \
--status ACTIVE \
--signing-disabled

  1. O próximo passo é adicionar a permissão para que o AWS IoT Core possa invocar a função Lambda. Você poderá utilizar a AWS Management Console para realizar essa configuração, porém utilizaremos o terminal neste exemplo através do comando abaixo.

 

aws lambda add-permission \
--function-name myLambdaAuthorizer \
--principal iot.amazonaws.com \
--source-arn arn:aws:iot:<region>:<account-id>:authorizer/my-authorizer \
--statement-id statid123 \
--action "lambda:InvokeFunction"

OBS: O parâmetro statement-id deverá ser um identificador único do tipo string e poderá ser utilizado para track das políticas.

 

Mão na Massa 3: Criando um Banco de Dados no Amazon Timestream

  1. Abrir a console de gerenciamento do Amazon Timestream. Selecionar o botão Create Database. Efetuar a seguinte seleção:
  • Database Configuration: Standard database
  • Name: blogpost

OBS: Manter os demais campos com valores padrão.

  1. Selecionar o botão Create Database.
  2. Selecionar o banco de dados que acabamos de criar. Selecionar a aba Tables e selecionar o botão Create Table. Efetuar a seguinte configuração:
  • Table Name: myTable
  • Memory store retention: 1 Hour(s)
  • Magnetic store retention: 1 Day(s)
  1. Selecionar o botão Create Table (Figura 2 – Processo de criação da tabela).

 

Figure 2 – Timestream Create Table

 

Mão na Massa 4: Configurando a Rule no AWS IoT Core

  1. Abrir a console de gerenciamento do AWS IoT Core. Selecionar Act, Rules e Create. Efetuar a seguinte configuração:
  • Name: iot2timestream
  • Description: Rule to send IoT Sensor Data to TimeStream blogpost Database
  • Rule query statement: SELECT * FROM ‘telemetry’
  1. Selecionar o botão Add Action, Write a message into a Timestream table e Configure Action. Efetuar a seguinte configuração:
  • Database Name: blogpost
  • Table Name: myTable
  • Dimension Name: DeviceName
  • Dimension Value: Device1
  • Timestamp Value: ${timestamp()}
  • Unit: MILLISECONDS
  1. Selecionar Create role, determinar um nome para a Role, Create Role e Add action.
  1. Na console de gerenciamento do AWS IoT Core selecionar o botão Create Rule.

 

Mão na Massa 5: Configurando o Node-Red para o Acesso ao AWS IoT Core

Você poderá realizar o passo a passo da configuração do Node-Red para criar o protótipo.

  1. O primeiro passo para a configuração é descobrirmos o endpoint do AWS IoT Core. Para isso digite o seguinte comando utilizando o terminal:

aws iot describe-endpoint --output text --endpoint-type iot:Data-ATS

  1. Criaremos um novo flow para enviar um JSON para o AWS IoT Core utilizando o Injection Node e o MQTT Out Node do Node-Red. No meu exemplo, estou utilizando o Node-Red como um container docker. Faço a inicialização com o seguinte comando no meu laptop:

docker run -d -p 1880:1880 nodered/node-red

  1. Abrir o navegador e digitar: http://localhost:1880 no campo de endereço. Arrastar o Inject Node e o MQTT Node e fazer a conexão entre eles conforme Figura 3:

 

Figure 3 – Fluxo inicial do NodeRed

 

  1. Vamos agora editar as configurações do MQTT out node. Utilizaremos as seguintes configurações:
  • Topic: telemetry
  • QoS: 0
  • Retain: false
  1. Clicar no botão Edit ao lado do campo Server, conforme Figura 4:

 

Figure 4 – Configuração do MQTT Out Node

 

  1. Utilizar as seguintes configurações:
  • Server: Endpoint do AWS IoT Core
  • Port: Para utilizar o custom authorizer a porta deverá ser 443.
  • Client ID: No meu exemplo estou utilizando myClientName
  • Use TLS: Selecionado.
  1. Clicar no botão Edit ao lado do campo TLS Configuration, conforme Figura 5:

 

Figure 5 – Configuração do MQTT Out Node

 

  1. Selecionar as seguintes configurações, conforme Figura 6:
  • Verify Server Certificate: habilitado
  • Server Name: Digitar o endpoint do AWS IoT Core
  • ALPN Protocol: mqtt

 

Figure 6 – Configuração do TLS

 

  1. Selecionar o botão Update.
  2. Selecionar a aba Security, conforme Figura 7. No campo Username você deve utilizar o seguinte formato:

<username>?x-amz-customauthorizer-name=<authorizer_name>

  1. No meu exemplo ficou assim:

username123?x-amz-customauthorizer-name=my-authorizer

  1. No campo Password, digitar a senha. No nosso exemplo utilizamos a senha “test”.

 

Figure 7 – Username

 

  1. Selecionar o botão Update e depois Done. Selecionar o botão Deploy na tela principal para aplicar as modificações.

Pronto o seu Node-Red já está configurado e pronto para realizarmos os testes iniciais.

 

Smoke Test

No AWS IoT Core verificar as mensagens através da função MQTT Test. Abrir a console de gerenciamento do AWS IoT Core, selecionar o menu Test e selecionar o item MQTT test client. No campo Topic filter digitar o nome do tópico utilizado nas configurações anteriores. No meu exemplo utilizo telemetry. Selecionar o botão Subscribe, conforme Figura 8.

 

Figure 8 – MQTT Test

 

No Node-Red selecionar o botão Inject, conforme Figura 9. Isso irá simular um sensor enviando uma mensagem para o MQTT Out node e consequentemente para o AWS IoT Core.

 

Figure 9 – Teste do NodeRed

 

Retornando a console do AWS IoT Core você poderá verificar que as mensagens enviadas pelo NodeRed foram registradas no tópico telemetry, conforme a Figura 10.

 

Figure 10 – Recebendo Mensagens no Topico

 

O próximo teste é validarmos se o dado emitido pelo sensor chegou até a camada de persistência (Amazon Timestream). Abrir a console de gerenciamento do Amazon Timestream e selecionar Query editor (menu de três linhas do lado esquerdo).

Selecionar o Banco de Dados criado na sessão anterior e clicar no botão ao lado do nome da tabela (botão de três pontos). Selecionar Preview data e selecionar o botão Run. Após alguns segundos você conseguirá verificar os dados dos sensores que enviamos para o Timestream através das Rules do AWS IoT Core, conforme Figura 11.

 

Figure 11 – Query no Banco de Dados do Timestream

 

Conclusão

 Embora a forma padrão de autenticação de dispositivos no message broker seja realizado através da distribuição de Certificados e Chaves (mTLS), verificamos que nem todo cenário poderá ser configurado desta maneira. Muitos cenários de migração de message brokers MQTT para a nuvem requerem outras formas de autenticação e autorização. O Custom Authorizer do AWS IoT Core implementa a flexibilidade exigida para estes cenários e viabiliza a migração desse tipo de carga de trabalho para a nuvem. Um cenário recomendado é realizar o Replataforming do message broker, conseguindo assim os benefícios de um serviço gerenciado, e gradativamente migrar os dispositivos da ponta para o uso de métodos mais seguros de autenticação como por exemplo o uso de mTLS.

Não faz parte do escopo de estudo deste blog post explorar o uso de signing tokens na autenticação do message broker, porém, essa técnica é recomendada para o uso em ambientes produtivos e para evitar que alguns requests inválidos acionem o Lambda Function do custom authorizer e gere custos adicionais desnecessários.

O intuito principal deste blog post é compartilhar informações sobre o processo de autenticação e autorização customizada do AWS IoT Core, porém pudemos explorar também a facilidade da configuração das Rules e o armazemento de informações no Banco de Dados de série temporais, o Amazon Timestream, de maneira fácil e sem nenhum componente intermediário.

Convido você a nos enviar as dúvidas, comentários e feedbacks utilizando o formulário abaixo. Até o nosso próximo Blog Post!

 

Referências

Estamos listando aqui algumas referências que foram utilizadas durante a elaboração deste AWS Blog Post para que você possa se aprofundar no assunto:

https://thinkwithwp.com/about-aws/whats-new/2020/08/aws-iot-core-expands-custom-authentication-options/

https://docs.thinkwithwp.com/iot/latest/developerguide/custom-authorizer.html

https://pt.wikipedia.org/wiki/MQTT


Sobre o Autor

Gerson Itiro Hidaka atualmente trabalha como Enterprise Solution Architect na AWS e atua no atendimento a clientes na área de Mid-Enterprise no Brasil. Entusiasta de tecnologias como Internet das Coisas (IoT), Drones, Devops e especialista em tecnologias como virtualização, serverless, container e Kubernetes. Trabalha com soluções de TI a mais de 24 anos, tendo experiência em inúmeros projetos de otimização de infraestrutura, redes, migração, disaster recovery e DevOps em seu portifólio.

 

 

Sobre os revisores

Luiz Yanai é Arquiteto de Soluções na AWS.

 

 

 

 

 

Jose Maria é Arquiteto de Soluções com foco em parceiros na AWS

 

 

 

 

 

Giovani Volpato Bassan é Arquiteto de Soluções com foco em empresas na AWS.