Configurar a autenticação JWT com JWKS remotos

Com o Cloud Service Mesh, é possível proteger seus serviços validando JSON Web Tokens (JWT) usando o recurso personalizado RequestAuthentication do Istio. Uma parte fundamental dessa configuração é o campo jwksUri, que especifica o URI do provedor do conjunto de chaves da Web JSON (JWKS, na sigla em inglês). Esse JWKS contém as chaves públicas usadas para validar os JWTs recebidos.

Importante: no Cloud Service Mesh, o plano de dados (proxies do Envoy) é responsável por buscar as chaves JWKS diretamente do jwksUri. O plano de controle do Cloud Service Mesh (gerenciado pelo Traffic Director) não faz chamadas externas para buscar essas chaves. Isso significa que toda a comunicação de rede com provedores JWKS externos tem origem no proxy Envoy da sua carga de trabalho.

Pré-requisitos para acesso externo ao JWKS

Para seguir este guia, você precisa do seguinte:

  • Política organizacional para acesso à Internet: se o jwksUri apontar para um endpoint externo da Internet, a política organizacional do Google Cloud precisará permitir o acesso à Internet de saída das suas cargas de trabalho. Especificamente, verifique se a política da organização constraints/compute.disableInternetNetworkEndpointGroup não está sendo aplicada. Se essa política estiver ativada, a busca de JWKS de jwksUris externos vai falhar.

  • Uma carga de trabalho do Kubernetes rotulada: os recursos RequestAuthentication e AuthorizationPolicy usam um selector para segmentar cargas de trabalho específicas. Você precisa ter uma carga de trabalho, como uma implantação do Kubernetes, em execução no cluster com rótulos que as políticas possam corresponder. Por exemplo, a amostra httpbin está configurada para ser executada com o rótulo app: httpbin. Use a configuração com httpbin e curl do guia Token JWT do Istio.

Métodos para ativar a busca de JWKS

Há duas maneiras principais de configurar o Cloud Service Mesh para permitir que seus proxies Envoy busquem chaves JWKS de um jwksUri externo:

Essa é a abordagem recomendada para a maioria dos cenários de produção e é obrigatória para o Cloud Service Mesh com MCP. Esse método oferece controle explícito sobre como a malha interage com o provedor JWKS externo.

Definir o serviço externo com um ServiceEntry

Primeiro, crie um ServiceEntry do Istio para tornar o provedor JWKS externo um serviço conhecido na malha. Esse recurso permite a resolução de DNS e o roteamento adequado para os proxies Envoy no seu plano de dados.

Para uma política RequestAuthentication que usa jwksUri: "https://your-auth-provider.com/.well-known/jwks.json", você criaria o seguinte ServiceEntry:

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: "external-jwks-provider-se"
  namespace: your-namespace 
spec:
  hosts:
  - "your-auth-provider.com" # Hostname from your jwksUri
  location: MESH_EXTERNAL
  ports:
  - number: 443
    name: https
    protocol: TLS
  resolution: DNS

Configurar as definições de conexão com um DestinationRule

Em segundo lugar, talvez seja necessário um DestinationRule para especificar as configurações de TLS do lado do cliente para conexões com o provedor JWKS, principalmente se ele exigir uma configuração específica de TLS ou mTLS.

  • Para provedores que usam certificados confiáveis publicamente, crie um DestinationRule com tls.mode definido como SIMPLE para ativar a validação TLS padrão do lado do servidor.
  • Para provedores que exigem certificados de cliente (mTLS), defina tls.mode como MUTUAL e forneça os caminhos para os certificados e as chaves que o Envoy precisa apresentar.

Essa DestinationRule configura a política de conexão para o ServiceEntry definido na etapa anterior:

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: "external-jwks-provider-dr"
  namespace: your-namespace 
spec:
  host: "your-auth-provider.com" # Must match a host in the ServiceEntry
  trafficPolicy:
    tls:
      # Use SIMPLE for standard server-side TLS.
      mode: SIMPLE 
      
      # If the JWKS provider uses a custom CA, provide the CA cert bundle.
      # caCertificates: /path/to/provider-ca-cert.pem

      # For providers requiring mTLS from Envoy, uncomment the following:
      # mode: MUTUAL
      # clientCertificate: /path/to/client-cert.pem
      # privateKey: /path/to/client-key.pem
      # caCertificates: /path/to/provider-ca-cert.pem

Como processar o tráfego de aplicativos para o mesmo provedor de JWKS

Em alguns casos, o aplicativo pode precisar se comunicar diretamente com o mesmo serviço externo que fornece o jwksUri. Por exemplo, seu aplicativo pode precisar chamar um endpoint de autenticação em your-auth-provider.com enquanto o Cloud Service Mesh busca as chaves JWKS do mesmo host.

Se você seguir a configuração padrão DestinationRule com tls: mode: SIMPLE, todo o tráfego da sua malha para your-auth-provider.com terá TLS originado pelo proxy Envoy. Se o aplicativo também originar TLS para as solicitações ao mesmo host, isso poderá resultar em erros de conexão para o tráfego do aplicativo devido a um problema de criptografia "TLS duplo".

Para resolver isso, use um DestinationRule com subconjuntos para aplicar políticas TLS diferentes para a busca de JWKS e para o tráfego do aplicativo.

  1. Crie um ServiceEntry como faria normalmente:

    apiVersion: networking.istio.io/v1beta1
    kind: ServiceEntry
    metadata:
      name: "external-jwks-provider-se"
      namespace: your-namespace
    spec:
      hosts:
      - "your-auth-provider.com" # Hostname from your jwksUri
      location: MESH_EXTERNAL
      ports:
      - number: 443
        name: https
        protocol: TLS
      resolution: DNS
    
  2. Crie um DestinationRule com uma política de tráfego para buscas de JWKS e um subconjunto para tráfego de aplicativos:

    • O trafficPolicy padrão ativa a início de TLS para buscas de JWKS do Cloud Service Mesh.
    • Um subset nomeado (por exemplo, app-traffic) desativa a início de TLS do Cloud Service Mesh, permitindo que o aplicativo processe o TLS por conta própria.
    apiVersion: networking.istio.io/v1beta1
    kind: DestinationRule
    metadata:
      name: "external-jwks-provider-dr"
      namespace: your-namespace
    spec:
      host: "your-auth-provider.com"
      trafficPolicy:
        tls:
          mode: SIMPLE
      subsets:
      - name: app-traffic
        trafficPolicy:
          tls:
            # Use DISABLE to prevent Envoy from originating TLS for the application's traffic
            mode: DISABLE
    
  3. Crie um VirtualService para rotear o tráfego de aplicativos para o subconjunto adequado:esse VirtualService garante que o tráfego do aplicativo para o host externo seja enviado ao subconjunto app-traffic, que ignora início de TLS da malha de serviço do Cloud.

    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: "route-for-app-to-jwks-provider"
      namespace: your-namespace # The namespace of your application
    spec:
      hosts:
      - "your-auth-provider.com"
      http:
      - route:
        - destination:
            host: "your-auth-provider.com"
            subset: app-traffic
    

Com essa configuração, é possível buscar chaves JWKS com segurança para autenticação JWT, permitindo que o aplicativo se comunique diretamente com o mesmo provedor externo sem conflitos.

2. Configuração automática pelo Cloud Service Mesh (somente Traffic Director)

Se o Cloud Service Mesh não encontrar um ServiceEntry definido pelo usuário que cubra o nome do host e a porta de um jwksUri HTTPS em uma política RequestAuthentication, ele vai configurar automaticamente a configuração necessária para o Envoy buscar as chaves JWKS. Essa automação simplifica a configuração para cenários comuns em que a conectividade padrão com o jwksUri (HTTPS, TLS padrão) é suficiente.

Condições para a configuração automática: esse comportamento automático se aplica se:

  • Você está usando o Cloud Service Mesh com o Traffic Director.
  • O jwksUri usa o esquema https.
  • O jwksUri aponta para um serviço externo que não é local do cluster.
  • Nenhum ServiceEntry visível (considerando o namespace da política RequestAuthentication e o campo exportTo de ServiceEntry) já gerencia o nome do host e a porta de jwksUri.

Se essas condições forem atendidas, seus proxies Envoy serão configurados para buscar os JWKS sem exigir que você crie recursos ServiceEntry ou DestinationRule explícitos para esse jwksUri.

Configurando RequestAuthentication

Independente do método usado para buscar JWKS, você define regras de validação de JWT usando uma política RequestAuthentication.

apiVersion: security.istio.io/v1
kind: RequestAuthentication
metadata:
  name: "jwt-example"
  namespace: your-namespace # Replace with your application's namespace
spec:
  selector:
    matchLabels:
      app: your-app # Replace with your application's label (e.g. httpbin)
  jwtRules:
  - issuer: "testing@secure.istio.io"
    jwksUri: "https://raw.githubusercontent.com/istio/istio/release-1.26/security/tools/jwt/samples/jwks.json"

Campos principais em jwtRules. Consulte a documentação do Istio RequestAuthentication para mais detalhes.

  • issuer: o emissor do JWT.
  • jwksUri: o URI HTTPS do conjunto de chaves públicas (JWKS) do provedor.
  • fromHeaders (opcional): especifica os locais de cabeçalho de onde o JWT é esperado.
  • fromParams (opcional): especifica os parâmetros de consulta de que o JWT é esperado.
  • forwardOriginalToken (opcional): se for "true", o token original será encaminhado ao serviço upstream.

Aplicar a autenticação JWT com AuthorizationPolicy

Para rejeitar solicitações sem um JWT válido, pareie sua política RequestAuthentication com um AuthorizationPolicy. A política a seguir permite solicitações para a carga de trabalho your-app somente se elas apresentarem um JWT válido do emissor e assunto especificados.

apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
 name: "require-jwt-for-your-app"
 namespace: your-namespace # Replace with your application's namespace
spec:
 selector:
   matchLabels:
     app: your-app # Replace with your application's label (e.g. httpbin)
 action: ALLOW
 rules:
 - from:
   - source:
       # This principal is typically in the format "issuer/subject"
       requestPrincipals: ["testing@secure.istio.io/sub-from-jwt"] # Replace with the expected principal

Para exemplos e casos de uso mais detalhados sobre como usar declarações JWT na autorização, consulte a tarefa de autorização do Istio para tokens JWT.

A seguir