O NGINX Plus Release 10 introduziu suporte para descarregar autenticação de serviços da Web e API com JSON Web Tokens (JWTs, pronunciado “jots”). Desde o lançamento do R10, continuamos a aumentar a funcionalidade em cada nova versão.
A partir do NGINX Plus R14 , o NGINX Plus oferece suporte a JWTs que contêm declarações aninhadas e dados de matriz. Quando usado em um cenário de gateway de API, o NGINX Plus pode usar JWTs para autenticar clientes que estão solicitando conexões com serviços de backend e destinos de API.
Ocasionalmente, me pediram para fornecer uma configuração básica que usa o NGINX Plus para autenticar JWTs e, em seguida, tomar decisões de balanceamento de carga mais avançadas com base nas informações do JWT. A solução mais direta é simplesmente permitir o acesso a um serviço se a autenticação for bem-sucedida e bloquear ou redirecionar a conexão se não for bem-sucedida.
O passo a passo neste post é uma prova de conceito completa para autenticação JWT e roteamento baseado em conteúdo usando o NGINX Plus. Para cobrir a mais ampla gama de possibilidades e reduzir a necessidade de conhecimento prévio ou experiência com JWTs, criei um passo a passo “JWT 101”, permitindo que você implante esta solução (com exemplos e histórico) sem nenhum conhecimento prévio de JWTs.
Se você já tem experiência com JWT ou JWTs existentes em seu ambiente, pode pular as duas primeiras seções e adaptar os snippets de configuração do NGINX Plus fornecidos para se adequarem ao seu ambiente e começar a tomar decisões avançadas de balanceamento de carga com base nos dados de declarações do JWT.
Este documento pressupõe uma nova instalação do NGINX Plus, com arquivos de configuração padrão nos seguintes locais:
Para obter mais informações sobre como instalar e começar a usar o NGINX Plus, consulte o Guia de administração do NGINX Plus .
Todos os comandos CLI assumem privilégios de root
, portanto, usuários não root
devem ter permissões sudo
em seu ambiente.
Para obter informações básicas adicionais e outros casos de uso para JWTs com NGINX Plus, consulte os seguintes links:
As instruções abaixo mostram como criar um JWT do zero com dados de carga específicos para o nosso exemplo, como uma ilustração de como configurar o NGINX Plus para processamento básico de declarações JWT. Se você usar um JWT existente em vez do de exemplo, precisará certificar-se de que seu arquivo “secrets” contenha a string codificada em Base64URL que corresponde à chave de assinatura usada para criar o JWT. Provavelmente você também precisará modificar as declarações na carga útil do JWT.
Observação: Não importa como você gera seu JWT, você deve usar a codificação Base64URL, que manipula corretamente o preenchimento (feito com o caractere =
), bem como outros caracteres não compatíveis com HTTP normalmente usados na codificação Base64. Muitas ferramentas lidam com isso automaticamente, mas codificadores Base64 manuais baseados em CLI e algumas ferramentas de criação de JWT não o fazem. Para mais informações sobre codificação Base64URL, consulte codificação base64url de Brock Allen e RFC 4648 .
Neste exemplo, estamos usando a GUI em jwt.io (que faz corretamente a codificação Base64URL) para criar um JWT HS256 simétrico. A captura de tela a seguir mostra a aparência da GUI depois que você insere os valores especificados nas instruções abaixo e a assinatura é verificada.
Trabalhando na GUI em jwt.io , gere um JWT HS256 verificando ou inserindo os valores indicados nos campos da coluna Decodificado à direita:
Verifique se o seguinte valor padrão aparece no campo HEADER , modificando o conteúdo para corresponder, se necessário:
{ "alg": "HS256",
"típico": "JWT"
}
No campo VERIFICAR ASSINATURA , substitua o valor na caixa (por padrão, secret
) por nginx123
. (Faça essa alteração antes de inserir dados no campo PAYLOAD para evitar um problema que ocorre se você inverter as duas etapas.)
Substitua o conteúdo do campo PAYLOAD pelo seguinte:
{ "exp": 1545091200,
"nome": "Criar novo usuário",
"sub": "cuser",
"gname": "wheel",
"guid": "10",
"nomecompleto": "John Doe", "uname": "jdoe", "uid": "222",
"sudo": verdadeiro,
"dept": "TI",
"url": "http://secure.example.com"
}
Observação: A declaração exp
define a data e a hora de expiração do JWT, representando-o como um horário de época UNIX (o número de segundos desde a meia-noite UTC de 1º de janeiro de 1970 ). O valor da amostra representa meia-noite UTC em 18 de dezembro de 2018 . Para ajustar a data de expiração, altere o tempo de época.
Verifique se a barra abaixo dos campos está azul e diz Assinatura verificada .
Copie o valor na coluna Codificada à esquerda em um arquivo ou buffer. É o texto completo do JWT que o usuário jdoe precisa apresentar para acessar http://secure.example.com , e o usaremos em nossos testes abaixo . Mostramos o JWT com quebras de linha aqui para fins de exibição, mas ele deve ser apresentado ao NGINX Plus como uma sequência de caracteres de linha única.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDAsIm5hbWUiOi
JDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciImduYW1lIjoid2hlZWwiLCJndWlkI
joiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMjIy
Iiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGx
lLmNvbSJ9.YYQCNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4
Trabalhando no host NGINX Plus, siga estas etapas para criar o arquivo de chave que o NGINX Plus usa para verificar JWTs assinados com nginx123
:
Execute este comando para gerar a string codificada em Base64URL correspondente à string de assinatura. (Os comandos tr
fazem as substituições de caracteres necessárias para a codificação Base64URL.)
# eco -n nginx123 | base64 | tr '+/' '-_' | tr -d '=' bmdpbngxMjM
No diretório /etc/nginx/ , crie o arquivo de chave chamado api_secret.jwk para ser usado pelo NGINX Plus para verificar assinaturas JWT. Insira o seguinte conteúdo. O valor no campo k
é a forma codificada em Base64URL de nginx123
, que geramos na etapa anterior.
{"chaves": [{
"k":"bmdpbngxMjM",
"kty":"outubro"
}]
}
As instruções nesta seção configuram o NGINX Plus para validar o JWT incluído em uma solicitação e apresentar um recurso protegido se o cliente estiver autorizado (em vez da página padrão vista por clientes não autorizados). Também definimos um novo formato de log que captura informações relacionadas ao JWT.
Nestas instruções, estamos seguindo a prática recomendada padrão de renomear o arquivo de configuração default.conf para que o NGINX Plus não o leia e criando uma nova configuração especificamente para testes. Isso permite que você restaure facilmente a configuração padrão quando terminar o teste ou se houver um problema durante o teste.
Renomear default.conf :
# mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak
Crie um novo arquivo de configuração chamado jwt-test.conf em /etc/nginx/conf.d/ , com o seguinte conteúdo. Eles configuram o registro específico do JWT, a validação do JWT e o roteamento baseado em conteúdo (uma análise completa segue o snippet).
servidor {
ouvir 80;
log_de_acesso /var/log/nginx/host.access.log jwt;
localização / {
raiz /usr/share/nginx/html;
índice index.html index.htm;
# Validação JWT
auth_jwt "Reino de teste JWT" token=$arg_myjwt;
auth_jwt_key_file /etc/nginx/api_secret.jwk;
log_de_erro /var/log/nginx/host.jwt.error.log debug;
if ( $jwt_claim_uid = 222 ) {
add_header X-jwt-claim-uid "$jwt_claim_uid" sempre;
add_header X-jwt-status "Redirecionar para $jwt_claim_url" sempre;
return 301 $jwt_claim_url;
}
if ( $jwt_claim_uid != 222 ) {
add_header X-jwt-claim-uid "$jwt_claim_uid" sempre;
add_header X-jwt-status "Usuário inválido, sem redirecionamento" sempre;
}
}
}
As diretivas no bloco de localização
informam ao NGINX Plus como lidar com solicitações HTTP que incluem um JWT. (Para obter informações sobre a configuração de registro definida pela diretiva access_log
, consulte a próxima seção .) O NGINX Plus executa estas etapas:
Extrai o JWT do argumento myjwt na string de solicitação (conforme especificado pelo argumento token
para a diretiva auth_jwt
).
Decodifica o JWT usando a chave de assinatura especificada pela diretiva auth_jwt_key-file
(aqui, api_secret.jwk ). Ele atua na carga útil da seguinte maneira (essas ações são inerentes ao processamento JWT e não têm diretivas NGINX Plus correspondentes):
exp
na carga útil não está no passado.$ jwt_claim_claim-name
(por exemplo, $jwt_claim_uid
para a reivindicação uid
). Registra quaisquer erros em /var/log/nginx/host.jwt.error.log no nível de depuração
.
Testa se o valor de $jwt_claim_uid
é222
(conforme especificado pelas duas diretivas if
) e envia a resposta apropriada ao cliente. É assim que as informações no JWT são usadas para executar o roteamento baseado em conteúdo.
222
, o NGINX Plus envia uma resposta que redireciona o cliente (a diretiva return
) para a URL especificada na reivindicação url
do JWt. Para fins de depuração, ele adiciona dois cabeçalhos à resposta (as diretivas add_header
): o primeiro captura o valor da declaração uid
e o segundo registra o fato de que o cliente foi redirecionado.222
, o NGINX Plus exibe a página de índice padrão (conforme definido pelas diretivas root
e index
no mesmo bloco de localização
). Novamente, para fins de depuração, ele adiciona cabeçalhos que capturam o valor da declaração uid
e registram o fato de que o cliente não obteve acesso à URL especificada no JWT.Observação: Usar a diretiva if
para avaliar variáveis geralmente não é considerado uma prática recomendada , e geralmente recomendamos usar a diretiva map
. Para os propósitos deste exemplo simples, porém, a diretiva if
funciona conforme o esperado.
Efetivamente, a configuração fornece acesso a recursos protegidos apenas para usuários autorizados. Ou seja, usuários com um JWT válido obtêm acesso à URL especificada no JWT, enquanto usuários sem um JWT válido obtêm acesso a uma página padrão.
Concluímos a configuração do tratamento JWT para roteamento baseado em conteúdo definindo um formato de registro chamado jwt , que é referenciado pela diretiva access_log
em jwt-test.conf . Ele captura dados JWT no log de acesso.
Adicione a seguinte diretiva log_format
ao /etc/nginx/nginx.conf :
log_format jwt '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'$jwt_header_alg $jwt_claim_uid $jwt_claim_url';
Este formato inclui as duas declarações JWT usadas neste passo a passo ( uid
e url
), mas você pode registrar quaisquer dados de declaração JWT com o nome da variável correspondente à declaração, no formato $jwt_claim_claim ‑name
.
Salve nginx.conf e execute o comando a seguir para testar a configuração completa (incluindo o novo arquivo jwt-test.conf ) quanto à validade sintática. Corrija quaisquer erros relatados.
# nginx -t
Recarregue o NGINX Plus.
# nginx -s recarregar
Usando um navegador ou uma ferramenta CLI como curl
, podemos testar se o NGINX Plus está validando corretamente o JWT, autenticando o cliente que o apresenta e executando o roteamento baseado em conteúdo. (Para testar apenas a autenticação e a validação, mas não o roteamento baseado em conteúdo, comente os dois blocos if
em jwt-test.conf .)
Para executar o teste, incluímos o argumento myjwt na URL da solicitação, fornecendo o texto completo do JWT no qual a reivindicação da URL
está222
. Novamente adicionamos quebras de linha para fins de exibição.
http://example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiO
jE1NDUwOTEyMDasIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW
1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9
lIiwidWlkIjoiMjIyIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5le
GFtcGxlLmNvbSJ9.YYQCNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4
Aqui está o comando curl
correspondente (sem quebras de linha, então você pode copiar e colar se desejar):
# curl -v example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDasIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmd WxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMjIyIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ9.YY QCNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4
Porque o valor da reivindicação uid
no JWT é222
, esperamos que o NGINX Plus exiba o conteúdo da página restrita, http://secure.example.com .
Agora testamos para verificar se quando a reivindicação de url
no JWT não é222
, O NGINX Plus não exibe o conteúdo da página restrita, mas apresenta a página index.html do servidor local, neste caso http://example.com/index.html .
Começamos gerando outro JWT em jwt.io com uma reivindicação uid
diferente de222
; por uma questão de exemplo, fazemos isso111
. Aqui está a URL da solicitação com esse JWT:
http://example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiO
jE1NDUwOTEyMDasIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW
1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9
lIiwidWlkIjoiMTExIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5l
eGFtcGxlLmNvbSJ9.Ch9xqsGzB8fRVX-3CBuCxP1Ia3oGKB1OnO6qwi_oBgg
O comando curl
é:
# curl -v example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDasIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmd WxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMTExIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ9.Ch9xqsGzB8fRVX-3CBuCxP1Ia3oGKB1OnO6qwi_oBgg
Neste caso, esperamos que o NGINX Plus atenda http://example.com/index.html .
Em ambas as condições de teste, você pode usar uma ferramenta de inspeção de cabeçalho (como curl
ou as ferramentas de desenvolvedor fornecidas com alguns navegadores) para verificar se os novos cabeçalhos, X-jwt-claim-uid
e X-jwt-status
, foram adicionados à resposta.
Se você tiver algum problema durante o teste, verifique os logs de acesso e erro em /var/log/nginx/host.jwt* . O log de erros, em particular, revela problemas com verificação, acesso ao arquivo de verificação e assim por diante.
Em nosso exemplo básico, o NGINX Plus extrai o JWT do argumento myjwt na URL da solicitação. O NGINX Plus também oferece suporte à passagem do JWT em um cookie (para obter detalhes, consulte a documentação de referência do NGINX JWT ). Em jwt-test.conf , altere a diretiva auth_jwt
para que o primeiro elemento no parâmetro do token
seja $cookie
em vez de $arg
:
auth_jwt "Reino de teste JWT" token=$cookie_myjwt;
Para fornecer o JWT em um cookie chamado myjwt , o comando curl
apropriado é:
# curl -v --cookie myjwt= JWT-text exemplo.com/index.html
Experimente você mesmo o roteamento baseado em conteúdo com JWTs: comece seu teste gratuito de 30 dias do NGINX hoje mesmo ou entre em contato conosco para discutir seus casos de uso .
"Esta postagem do blog pode fazer referência a produtos que não estão mais disponíveis e/ou não têm mais suporte. Para obter as informações mais atualizadas sobre os produtos e soluções F5 NGINX disponíveis, explore nossa família de produtos NGINX . O NGINX agora faz parte do F5. Todos os links anteriores do NGINX.com redirecionarão para conteúdo semelhante do NGINX no F5.com."