Migrar para o Extensible Service Proxy V2

O Extensible Service Proxy V2 (ESPv2) é um proxy baseado em Envoy que permite que o Cloud Endpoints forneça recursos de gerenciamento de APIs. O ESPv2 substitui o Extensible Service Proxy (ESP) baseado em NGINX.

Neste documento, descrevemos como migrar uma implantação atual da API Endpoints do ESP para o ESPv2.

Antes de começar

Antes de iniciar a migração, considere os casos de uso não compatíveis e as alterações interruptivas da API descritas abaixo.

Casos de uso do ESPv2 não compatíveis

  • O ambiente flexível do App Engine não é compatível

    O ambiente flexível do App Engine conta com suporte integrado do Endpoints, que é ativado ao configurar endpoints_api_service no arquivo app.yaml do aplicativo. Esta implementação integrada do Endpoints aceita apenas o ESP. Não é possível migrá-lo para o ESPv2.

    Se você quiser usar o ESPv2 com o ambiente flexível do App Engine, desative endpoints_api_service em app.yaml. Implante o ESPv2 como um serviço separado do Cloud Run usado para gerenciar seu aplicativo no ambiente flexível do App Engine. Ela funciona da mesma forma que o ESPv2 é usado para suportar o ambiente padrão do App Engine.

  • A configuração personalizada do NGINX não é compatível

    O ESPv2 é um proxy baseado em Envoy. Ele não é compatível com a configuração personalizada do proxy NGINX. Se sua configuração do ESP usa as sinalizações -n ou --nginx_config, sua implementação pode depender de uma configuração personalizada do NGINX que não pode ser migrada facilmente para o ESPv2.

Alterações importantes

  • O formato de dados do cabeçalho X-Endpoint-API-UserInfo foi alterado. Se o aplicativo usar esse cabeçalho, ele deverá ser alterado para usar o novo formato. Consulte Como lidar com JWTs no serviço de back-end para mais detalhes.
  • Se uma chave de API for necessária para uma solicitação, o ESP enviará o cabeçalho do X-Endpoint-API-Project-ID com o ID do projeto do consumidor ao aplicativo de back-end. O ESPv2 usa dois cabeçalhos diferentes, X-Endpoint-API-Consumer-Type e X-Endpoint-API-Consumer-Number, para enviar os detalhes necessários. Consulte a documentação de referência do Service Infrastructure para mais detalhes sobre os Consumer-Type e Consumer-Number enviados com esses cabeçalhos.

  • Alteração no formato do corpo da resposta de erro HTTP. Quando o ESPv2 rejeita uma solicitação HTTP, ele gera um corpo de resposta de erro em um novo formato. Se sua implementação usar o código do cliente para processar o corpo da resposta JSON de erro HTTP, o código do cliente precisará ser atualizado. Consulte o corpo da resposta JSON de erro HTTP para mais detalhes.

  • Novas sinalizações de inicialização estão disponíveis e algumas sinalizações do ESP estão obsoletas ou foram substituídas no ESPv2. Consulte Alterações na sinalização de inicialização entre o ESP e o ESPv2.

Como migrar as APIs do Endpoints para usar o ESPv2

As etapas de migração necessárias para usar o ESPv2 com plataformas sem servidor (Cloud Run, Cloud Functions, App Engine) são diferentes das etapas necessárias para plataformas sem servidor (Google Kubernetes Engine, Compute Engine e Kubernetes).

Veja abaixo as etapas de migração necessárias para cada tipo de plataforma:

Plataformas sem servidor: GKE, Compute Engine e Kubernetes

O ESPv2 é uma substituição de drop-in para o ESP. Para a maioria das configurações, você só precisa atualizar para a tag de imagem do Docker.

No entanto, talvez seja necessário ajustar as sinalizações de inicialização se você tiver configurado o ESP com o seguinte:

  • Mais de uma porta por meio das sinalizações --http_port, http2_port e/ou --ssl_port.
  • SSL, DNS, Client IP ou outra sinalização raramente usada.

Novas sinalizações de inicialização estão disponíveis para o ESPv2 e algumas sinalizações do ESP estão obsoletas ou foram substituídas. Consulte Mudanças na sinalização de inicialização entre o ESP e o ESPv2 para mais detalhes.

GKE e Kubernetes

Para migrar as configurações do Endpoints para GKE e Kubernetes, altere a tag de imagem do ESP de :1 para :2 no arquivo yaml da implantação. Exemplo:

- name: esp
  image: gcr.io/endpoints-release/endpoints-runtime:2
  args: [
    "--http_port=8081",
    "--backend=127.0.0.1:8080",
    "--service=SERVICE_NAME",
    "--rollout_strategy=managed",
  ]

Compute Engine

O ESP e o ESPv2 são implantados no contêiner do Docker usando o comando docker run. Para migrar o Endpoints do Compute Engine para o ESPv2, atualize a tag da imagem do Docker de :1 para :2 no comando. Por exemplo:

sudo docker run \
    --detach \
    DOCKER_ARGUMENTS \
    gcr.io/endpoints-release/endpoints-runtime:2 \
    --service=SERVICE_NAME \
    --rollout_strategy=managed \
    --backend=YOUR_API_CONTAINER_NAME:8080

Plataformas sem servidor (Cloud Run, Cloud Functions e App Engine)

Para plataformas sem servidor, o ESPv2 é implantado como um serviço do Cloud Run para gerenciar o aplicativo em execução no Cloud Run, Cloud Function ou App Engine. Para migrar o Endpoints para o ESPv2, você precisa criar a configuração do serviço do Endpoints em uma nova imagem do Docker do ESPv2 e, em seguida, implantar a imagem no serviço Cloud Run do ESPv2.

As etapas de implantação para ESP e ESPv2 são idênticas, exceto pelos seguintes detalhes:

  • Ao implantar o ESPv2 no Cloud Run, a tag de imagem precisa ser alterada de :1 para :2 no ESPv2. Exemplo:

    gcloud run deploy CLOUD_RUN_SERVICE_NAME \
    --image="gcr.io/endpoints-release/endpoints-runtime-serverless:2" \
    --allow-unauthenticated \
    --platform managed \
    --project=ESP_PROJECT_ID  
  • O download do script gcloud_build_image é feito em um local diferente. Ele usa gcr.io/endpoints-release/endpoints-runtime-serverless:2 como a imagem base.

  • Uma variável de ambiente é usada para especificar sinalizações de inicialização. O nome da variável do ESP é ESP_ARGS. O nome do ESPv2 é ESPv2_ARGS. Consulte Opções de inicialização do Extensible Service Proxy V2 para mais informações sobre como definir ESPv2_ARGS e as sinalizações de inicialização disponíveis.

Mudanças na sinalização de inicialização entre o ESP e o ESPv2

Assim como o Extensible Service Proxy, é possível especificar sinalizações de configuração ao implantar serviços de ESPv2. Com a mudança do ESP baseado em NGINX para o ESPv2 baseado em Envoy, algumas sinalizações foram suspensas ou substituídas, e novas sinalizações foram adicionadas. Esta seção usa três tabelas para descrever as alterações:

  • A Tabela 1 descreve novas sinalizações que substituem as sinalizações obsoletas.
  • A Tabela 2 descreve novos sinalizadores.
  • A Tabela 3 descreve as sinalizações obsoletas.

Sinalizações substituídas

Novas sinalizações Sinalizações substituídas Descrição
--listener_port --http_port, --http2_port, --ssl_port Uma única porta do listener Envoy é compatível com http, http2 e ssl no ESPv2. Não é necessário especificar portas separadas.
--ssl_server_cert_path --ssl_port Quando --ssl_server_cert_path é usado, o ESPv2 usa certificados de arquivos server.key e server.crt. Com o ESPv2, é possível especificar caminhos de certificado do servidor diferentes de /etc/nginx/ssl. Essa sinalização substitui --ssl_port no ESP, que usa certificados dos caminhos de arquivo /etc/nginx/ssl/nginx.key e /etc/nginx/ssl/nginx.crt.
--ssl_backend_client_cert_path --tls_mutual_auth, --enable_grpc_backend_ssl, --grpc_backend_ssl_private_key_file, --grpc_backend_ssl_cert_chain_file Quando --ssl_backend_client_cert_path é usado, o ESPv2 usa certificados de arquivos client.key e client.crt. Com o ESPv2, é possível especificar caminhos de certificado do cliente diferentes de /etc/nginx/ssl. Essa sinalização substitui --tls_mutual_auth no ESP, que usa certificados dos caminhos de arquivo /etc/nginx/ssl/backend.key e /etc/nginx/ssl/backend.crt.
--ssl_backend_client_root_certs_file --grpc_backend_ssl_root_certs_file Com o ESPv2, --ssl_backend_client_root_certs_file funciona para todos os back-ends. Essa sinalização substitui --grpc_backend_ssl_root_certs_file no ESP, que só funciona para back-ends do gRPC.
--ssl_minimum_protocol,--ssl_maximum_protocol --ssl_protocols Ao usar --ssl_protocols no ESP, você precisa listar todos os protocolos ssl desejados. No ESPv2, é possível especificar um protocolo mínimo e máximo.
--envoy_use_remote_address,--envoy_xff_num_trusted_hops --xff_trusted_proxy_list,--client_ip_header,--client_ip_position O Envoy exige que use_remote_address e xff_num_trusted_hops configurem a extração de IP do cliente.
--dns_resolver_addresses --dns A sinalização de substituição tem o mesmo comportamento, mas um valor padrão diferente. O ESP usa 8.8.8.8 como um resolvedor de DNS. O ESPv2 usa o resolvedor de DNS configurado em /etc/resolv.conf.
--service_account_key --non_gcp, --service_account_key No ESP, a sinalização --service_account_key permite implicitamente a implantação em plataformas diferentes do GCP. Ela impede que o ESP chame o servidor de metadados da instância. No ESPv2, esse comportamento implícito é dividido em outra sinalização. Talvez seja necessário adicionar --non_gcp ao migrar. Caso contrário, o ESPv2 não será iniciado em plataformas diferentes do GCP.

Novas sinalizações

Novas sinalizações Descrição
--http_request_timeout_s Define o tempo limite para todas as chamadas remotas http/https, exceto para chamadas de back-end e chamadas do Google Service Control, em segundos.
--service_control_check_timeout_ms Define o tempo limite para as chamadas de Verificação de controle dos Serviços do Google em milissegundos.
--service_control_report_timeout_ms Define o tempo limite para chamadas de Relatório de controle dos Serviços do Google.
--service_control_quota_timeout_ms Define o tempo limite para chamadas de Cota de controle dos Serviços do Google.
--service_control_check_retries Especifica o número de repetição de chamadas de Verificação de controle dos Serviços do Google.
--service_control_report_retries Especifica o número de repetição de chamadas do Relatório de controle dos Serviços do Google.
--service_control_quota_retries Especifica o número de repetição de chamadas de Cota de controle dos Serviços do Google.
--backend_dns_lookup_family Configuração específica do Envoy usada para definir a família da busca DNS de todos os back-ends.
--disable_tracing Uma sinalização geral usada para desativar todos os traces.
--tracing_project_id Usado para definir o ID do projeto que tem os dados de rastreamento.
--tracing_incoming_context Usado para especificar o contexto de trace de entrada.
--tracing_outgoing_context Usado para especificar o contexto de saída.

Sinalizações obsoletas

Sinalizações obsoletas Descrição
--enable_websocket O Websocket é ativado por padrão no Envoy.
--experimental_proxy_backend_host_header Incompatível.
--allow_invalid_headers Incompatível. Esta é uma configuração do NGINX: ignore_invalid_headers. Se uma solicitação HTTP tiver nomes de cabeçalho inválidos, ela será rejeitada pelo ESPv2. Nomes de cabeçalho válidos são compostos de letras em inglês, dígitos, hífens e possivelmente sublinhados. No ESPv2, a sinalização --underscores_in_headers determina se sublinhados são permitidos em cabeçalhos.
--client_max_body_size A configuração do NGINX é incompatível.
--client_body_buffer_size A configuração do NGINX é incompatível.
--large_client_header_buffers A configuração do NGINX é incompatível.
--keepalive_timeout A configuração do NGINX é incompatível.
--client_body_timeout A configuração do NGINX é incompatível.
--rewrite Incompatível.
--experimental_enable_multiple_api_configs Incompatível.
--enable_backend_routing Desnecessário. O roteamento de back-end é ativado automaticamente nas plataformas sem servidor.
--rollout_fetch_throttle_window_in_s Desnecessário.
--nginx_config Incompatível.

Consulte as opções de inicialização do Extensible Service Proxy V2 para saber mais detalhes sobre as sinalizações de inicialização do ESPv2. Outros exemplos genéricos e textos de ajuda para sinalizações podem ser encontrados no repositório do GitHub.

Locais padrão do JWT

Por padrão, um JWT é transmitido no cabeçalho Authorization (prefixado por "Bearer "), no cabeçalho X-Goog-Iap-Jwt-Assertion ou no parâmetro de consulta access_token. Esses locais são aceitos pelo ESP e pelo ESPv2. Também é possível transmitir um JWT no cabeçalho Authorization (sem prefixo) ao usar o ESP. No entanto, esse local não é compatível com ESPv2.

Se você quiser continuar transmitindo JWTs usando o cabeçalho Authorization (sem prefixo) depois de migrar para o ESPv2, poderá:

x-google-jwt-locations:
- header: "Authorization"
jwt_locations:
- header: Authorization

Gerenciar os JWTs no serviço de back-end

Ao usar JWTs para realizar a autenticação, o ESPv2 e o ESP enviam o resultado da autenticação no cabeçalho X-Endpoint-API-UserInfo para a API de back-end. Recomendamos usar esse cabeçalho em vez do cabeçalho Authorization original, porque o Authorization pode ser modificado em plataformas sem servidor.

O cabeçalho X-Endpoint-API-UserInfo contém um objeto JSON codificado em Base64Url. No entanto, o formato foi alterado de ESP para ESPv2.

Para o ESPv2, o cabeçalho X-Endpoint-API-UserInfo contém o payload original do JWT, sem nenhuma modificação.

No ESP, o cabeçalho X-Endpoint-API-UserInfo contém o payload do JWT e alguns campos específicos adicionados pelo ESP. O ESP adiciona os campos id, issuer, email e audiences ao objeto JSON. Ele também adiciona o campo claims para incluir o payload original do JWT.

# ESPv1 X-Endpoint-API-UserInfo header value
{
  "id": "extracted from 'sub' field",
  "issuer": "extracted from 'iss' field",
  "email": "extracted from 'email' field",
  # The following "audiences" is extracted from 'aud' field.
  # The 'aud' field may have multiple audiences delimited by coma. e.g. "aud: aud1,aud2".
  # but the following "audiences" is always a JSON array.
  "audiences": ["aud1", "aud2"],
  "claims": {
     Original JWT payload
   }
}

O exemplo a seguir ilustra as diferenças. Todos eles foram decodificados em base64url.

# This is an example of the original JWT payload:
{
  &quotiss&quot: &quothttps://accounts.google.com&quot,
  &quotemail&quot: &quotabcdefg123456@gmail.com&quot,
  &quotsub&quot: &quot1234567890123456789&quot,
  &quotaud&quot: &quotxyz1.example.com,xyz2.example.com&quot,
  &quotfoo&quot: &quotfoo.foo.foo.foo&quot,
  &quotbar&quot: &quotbar.bar.bar.bar&quot,
  &quotazp&quot: &quot98765432109876543210&quot,
  &quotexp&quot: &quot1642809446&quot,
  &quotiat&quot: &quot1642805846&quot
}

# This is an example of the `X-Endpoint-API-UserInfo` header from ESPv2
# extracted from above JWT payload.
{
  &quotiss&quot: &quothttps://accounts.google.com&quot,
  &quotemail&quot: &quotabcdefg123456@gmail.com&quot,
  &quotsub&quot: &quot1234567890123456789&quot,
  &quotaud&quot: &quotxyz1.example.com,xyz2.example.com&quot,
  &quotfoo&quot: &quotfoo.foo.foo.foo&quot,
  &quotbar&quot: &quotbar.bar.bar.bar&quot,
  &quotazp&quot: &quot98765432109876543210&quot,
  &quotexp&quot: &quot1642809446&quot,
  &quotiat&quot: &quot1642805846&quot
}

# This is an example of the `X-Endpoint-API-UserInfo` header from ESP
# extracted from above JWT payload.
{
  &quotid&quot:&quot1234567890123456789&quot,
  &quotissuer&quot: &quothttps://accounts.google.com&quot,
  &quotemail&quot: &quotabcdefg123456@gmail.com&quot,
  &quotaudiences&quot: [
    &quotxyz1.example.com&quot
    &quotxyz2.example.com&quot
  ],
  &quotclaims&quot: {
    &quotiss&quot: &quothttps://accounts.google.com&quot,
    &quotemail&quot: &quotabcdefg123456@gmail.com&quot,
    &quotsub&quot: &quot1234567890123456789&quot,
    &quotaud&quot: &quotxyz1.example.com,xyz2.example.com&quot,
    &quotfoo&quot: &quotfoo.foo.foo.foo&quot,
    &quotbar&quot: &quotbar.bar.bar.bar&quot,
    &quotazp&quot: &quot98765432109876543210&quot,
    &quotexp&quot: &quot1642809446&quot,
    &quotiat&quot: &quot1642805846&quot
  }
}

Consulte Como usar um método personalizado para autenticar usuários e Como autenticar entre serviços, para saber mais sobre como usar JWTs com uma autenticação.

Formato de corpo de resposta JSON de erro

Quando uma solicitação HTTP é rejeitada pelo ESP ou ESPv2, o corpo da resposta contém um código de status e uma mensagem de erro no formato JSON. O formato do corpo da resposta foi alterado no ESPv2, conforme mostrado nos exemplos abaixo:

Corpo da resposta de erro do ESP

{
 "code": 5,
 "message": "Method does not exist.",
 "details": [
  {
   "@type": "type.googleapis.com/google.rpc.DebugInfo",
   "stackEntries": [],
   "detail": "service_control"
  }
 ]
}

O corpo da resposta de erro do ESPv2

{
 "code": 400,
 "message": "Method does not exist.",
}

Há duas diferenças principais:

  • No ESPv2, o campo code contém um código de status HTTP, em vez do código de status RPC encontrado no ESP.
  • O corpo da resposta de erro no ESPv2 não contém um campo details.

A seguir

Saiba mais sobre: