O Alibaba Cloud Service Mesh (ASM) gerencia a autenticação JWT por meio de dois recursos do Istio que atuam em conjunto:
RequestAuthentication: define como validar tokens, especificando emissores e chaves de assinatura confiáveis. Este recurso rejeita requisições com tokens inválidos, mas permite aquelas sem token.
AuthorizationPolicy: aplica decisões de acesso para permitir ou negar requisições com base na presença do token, nas claims ou nos caminhos da requisição.
O RequestAuthentication isolado não bloqueia requisições não autenticadas. Para exigir tokens, associe-o a uma AuthorizationPolicy.
Quais algoritmos JWT o ASM suporta?
Os algoritmos suportados variam conforme a versão da instância do ASM:
Antes da v1.13: apenas RSA
v1.13 e posteriores: todos os algoritmos padrão listados abaixo
|
Família de algoritmos |
Algoritmos suportados |
|
RSA |
RS256, RS384, RS512 |
|
RSA-PSS |
PS256, PS384, PS512 |
|
ECDSA |
ES256, ES384, ES512 |
|
HMAC |
HS256, HS384, HS512 |
|
Edwards-curve |
EdDSA |
Como usar o parâmetro jwksUri?
Nota: O uso de jwksUri requer o ASM v1.13 ou superior.
O campo jwksUri em um recurso RequestAuthentication indica ao ASM onde buscar as chaves públicas para verificar JWTs. A configuração depende do local de hospedagem do endpoint do JSON Web Key Set (JWKS):
Dentro do cluster gerenciado: aponte o
jwksUridiretamente para o endereço do serviço no cluster.Fora do cluster gerenciado: crie primeiro um ServiceEntry para que o ASM acesse o endpoint externo.
Os exemplos abaixo usam o JWT de exemplo e o JWKS de exemplo do projeto Istio.
Endpoint JWKS dentro do cluster gerenciado
Neste cenário, o serviço nginx-proxy no cluster do Container Service for Kubernetes (ACK) fornece o JWKS em /get_jwks na porta 80. O jwksUri completo é http://nginx-proxy.{Namespace}.svc.cluster.local:80/get_jwks.
-
Verifique se o endpoint JWKS está acessível:
curl nginx-proxy/get_jwksSaída esperada:
{ "keys":[ {"e":"AQAB","kid":"DHFbpoIUqrY8t2zpA2qXfCmr5VO5ZEr4RzHU_-e****","kty":"RSA","n":"xAE7eB6qugXyCAG3yhh7pkDkT65p****-P7KfIupjf59vsdo91bSP9C8H07pSAGQ****_xFj9VswgsCg4R6otmg5PV2He95lZdHtOcU5****_pbhLdKXbi66GlVeK6ABZOUW3WYt****-91gVuoeJT_DwtGGcp4ignkgXfkiE****-4sfb4qdt5oLbyVpmW6x9cfa7vs2WTfURiCrBoU****_-4WTiULmmHSGZHOjzwa8WtrtOQGsAFjIbno85jp6MnGGGZPYZ****_b3y5u-YpW7ypZrvD8BgtKVjgtQgZhLAGezMt0ua3DRrWnKqT****_EyxOGuHJrLsn00****"}]}Se o retorno for um conjunto de chaves JSON válido, o endpoint funciona corretamente.
-
Crie um recurso RequestAuthentication no console do ASM.
Faça login no console do ASM.
No painel de navegação à esquerda, escolha Service Mesh > Mesh Management.
Na página Mesh Management, localize a instância do ASM desejada. Clique em no nome da instância ou em Manage na coluna Actions.
No painel de navegação à esquerda, escolha Mesh Security Center > RequestAuthentication.
-
Na página RequestAuthentication, clique em Create from YAML. Selecione um Namespace e um Template, cole o YAML a seguir e clique em Create.
apiVersion: security.istio.io/v1beta1 kind: RequestAuthentication metadata: name: jwt-example namespace: foo spec: jwtRules: - issuer: testing@secure.istio.io jwksUri: 'http://nginx-proxy/get_jwks' selector: matchLabels: app: httpbin
-
Teste a configuração enviando uma requisição com um JWT do Pod
sleeppara o serviçohttpbin:# Retrieve and decode the sample JWT TOKEN=$(curl https://raw.githubusercontent.com/istio/istio/release-1.14/security/tools/jwt/samples/demo.jwt -s) && echo "$TOKEN" | cut -d '.' -f2 - | base64 --decode - # Send a request with the JWT kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" \ -c sleep -n foo -- \ curl "http://httpbin.foo:8000/headers" -sS -o /dev/null \ -H "Authorization: Bearer $TOKEN" -w "%{http_code}\n"O código de status
200confirma o funcionamento da autenticação JWT.
Endpoint JWKS fora do cluster gerenciado
Se o endpoint JWKS estiver hospedado fora do cluster ACK gerenciado pelo ASM, crie um ServiceEntry para que o mesh possa acessá-lo. Este exemplo usa HTTP. Para HTTPS, adicione uma DestinationRule conforme mostrado na etapa opcional.
-
Crie um ServiceEntry para o endpoint JWKS externo.
-
Crie um arquivo chamado service-entry.yaml:
apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: external-svc-https namespace: foo spec: addresses: - 11.11.XX.XX # Replace with the IP address of your JWKS endpoint. endpoints: - address: 11.11.XX.XX # Replace with the IP address of your JWKS endpoint. hosts: - 11.11.XX.XX # Replace with the IP address of your JWKS endpoint. location: MESH_EXTERNAL ports: - name: http number: 80 protocol: HTTP - name: https number: 443 protocol: HTTPS resolution: STATIC -
Aplique o ServiceEntry:
kubectl apply -f service-entry.yaml
-
-
(Opcional) Para buscar o JWKS via HTTPS, crie uma DestinationRule que habilite o TLS:
apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: external-svc-https namespace: foo spec: host: ${The host where ServiceEntry resides} trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 443 tls: mode: SIMPLE -
Crie um recurso RequestAuthentication.
Faça login no console do ASM.
No painel de navegação à esquerda, escolha Service Mesh > Mesh Management.
Na página Mesh Management, localize a instância do ASM desejada. Clique em no nome da instância ou em Manage na coluna Actions.
No painel de navegação à esquerda, escolha Mesh Security Center > RequestAuthentication.
-
Na página RequestAuthentication, clique em Create from YAML. Selecione um Namespace e um Template, cole o YAML a seguir e clique em Create.
apiVersion: security.istio.io/v1beta1 kind: RequestAuthentication metadata: name: jwt-example namespace: foo spec: jwtRules: - issuer: tes****@secure.istio.io jwksUri: '${Your jwksUri}' selector: matchLabels: app: httpbin
-
Teste a configuração:
# Send a request with a JWT from the sleep Pod to httpbin kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" \ -c sleep -n foo -- \ curl "http://httpbin.foo:8000/headers" -sS -o /dev/null \ -H "Authorization: Bearer $TOKEN" -w "%{http_code}\n"O código de status
200confirma o funcionamento da autenticação JWT.
Como ignorar a autenticação JWT para caminhos específicos?
Combine um recurso RequestAuthentication com uma AuthorizationPolicy que use action: DENY e notPaths. O RequestAuthentication valida os tokens no gateway de entrada, enquanto a AuthorizationPolicy nega requisições não autenticadas para todos os caminhos, exceto os isentos.
O exemplo a seguir isenta /productpage da autenticação JWT e exige JWTs válidos para /api/v1/products/0 e /api/v1/products/1.
-
Implante a aplicação de exemplo Bookinfo e verifique o acesso.
Implante a aplicação Bookinfo no cluster ACK adicionado à instância do ASM. Para mais informações, consulte Implantar uma aplicação em um cluster ACK adicionado a uma instância do ASM.
Verifique se todos os caminhos estão acessíveis:
curl "http://<ingress-gateway-ip>/productpage" -sS -o /dev/null -w "%{http_code}\n" curl "http://<ingress-gateway-ip>/api/v1/products/0" -sS -o /dev/null -w "%{http_code}\n" curl "http://<ingress-gateway-ip>/api/v1/products/1" -sS -o /dev/null -w "%{http_code}\n"Cada comando deve retornar
200. -
Crie um recurso RequestAuthentication aplicável ao gateway de entrada.
Faça login no console do ASM.
No painel de navegação à esquerda, escolha Service Mesh > Mesh Management.
Na página Mesh Management, localize a instância do ASM desejada. Clique em no nome da instância ou em Manage na coluna Actions.
No painel de navegação à esquerda, escolha Mesh Security Center > RequestAuthentication.
-
Na página RequestAuthentication, clique em Create from YAML. Selecione um Namespace e um Template, cole o YAML a seguir e clique em Create.
apiVersion: security.istio.io/v1beta1 kind: RequestAuthentication metadata: name: jwt-example namespace: istio-system spec: jwtRules: - issuer: testing@secure.istio.io jwks: >- { "keys":[ {"e":"AQAB","kid":"DHFbpoIUqrY8t2zpA2qXfCmr5VO5ZEr4RzHU_-e****","kty":"RSA","n":"xAE7eB6qugXyCAG3yhh7pkDkT65pHymX-P7KfIupjf59vsdo91bSP9C8H07pSAGQ****_xFj9VswgsCg4R6otmg5PV2He95lZdHtOcU5****_pbhLdKXbi66GlVeK6ABZOUW3WYtnNHD-91gVu****_DwtGGcp4ignkgXfkiEm4sw-4sfb4qdt5oLbyVpmW6x9cfa7vs2WTfURiCrBoU****_-4WTiULmmHSGZHOjzwa8WtrtOQGsAFjIbno85jp6MnGGGZPYZ****_b3y5u-YpW7ypZrvD8BgtKVjgtQgZhLAGezMt0ua3DRrWnKqT****_EyxOGuHJrLsn00****"}]} selector: matchLabels: app: istio-ingressgateway
Este RequestAuthentication aplica-se ao gateway de entrada. Ele valida as assinaturas JWT, mas não bloqueia requisições sem tokens — essa função cabe à AuthorizationPolicy.
-
Crie uma AuthorizationPolicy que exija JWTs em todos os caminhos, exceto em
/productpage.Faça login no console do ASM.
No painel de navegação à esquerda, escolha Service Mesh > Mesh Management.
Na página Mesh Management, localize a instância do ASM desejada. Clique em no nome da instância ou em Manage na coluna Actions.
No painel de navegação à esquerda, escolha Mesh Security Center > AuthorizationPolicy.
-
Na página AuthorizationPolicy, clique em Create from YAML. Selecione um Namespace e um Template, cole o YAML a seguir e clique em Create.
apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: test-exclude namespace: istio-system spec: action: DENY rules: - from: - source: notRequestPrincipals: - '*' to: - operation: notPaths: - /productpage selector: matchLabels: app: istio-ingressgateway
Funcionamento desta política: a regra DENY atua sobre requisições que atendem a duas condições simultaneamente: (1) ausência de identidade JWT válida (
notRequestPrincipals: ['*']) e (2) alvo diferente de/productpage(notPaths: [/productpage]). Consequentemente, requisições não autenticadas para/productpagesão permitidas, enquanto requisições não autenticadas para todos os outros caminhos são negadas com o código de status403. -
Verifique a configuração.
Defina o JWT de exemplo como variável de ambiente:
export TOKEN=eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1****.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5p****.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9****-LS9qd_vpdLG4Tn1A15NxfCjp5f7Q****-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZz****__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCg****_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3Uc1MI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvH****_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8****Teste requisições sem JWT:
curl "http://<ingress-gateway-ip>/productpage" -sS -o /dev/null -w "%{http_code}\n" # Expected: 200 (exempted path) curl "http://<ingress-gateway-ip>/api/v1/products/0" -sS -o /dev/null -w "%{http_code}\n" # Expected: 403 (no JWT, access denied) curl "http://<ingress-gateway-ip>/api/v1/products/1" -sS -o /dev/null -w "%{http_code}\n" # Expected: 403 (no JWT, access denied)Teste requisições com JWT válido:
curl "http://<ingress-gateway-ip>/productpage" -H "Authorization: Bearer $TOKEN" -sS -o /dev/null -w "%{http_code}\n" # Expected: 200 curl "http://<ingress-gateway-ip>/api/v1/products/0" -H "Authorization: Bearer $TOKEN" -sS -o /dev/null -w "%{http_code}\n" # Expected: 200 curl "http://<ingress-gateway-ip>/api/v1/products/1" -H "Authorization: Bearer $TOKEN" -sS -o /dev/null -w "%{http_code}\n" # Expected: 200Caminho
Sem JWT
Com JWT válido
/productpage200(isento)200/api/v1/products/0403(negado)200/api/v1/products/1403(negado)200