Migrer vers Extensible Service Proxy V2

Extensible Service Proxy v2 (ESPv2) est un proxy basé sur Envoy qui permet à Cloud Endpoints de fournir des fonctionnalités de gestion des API. ESPv2 remplace le proxy Extensible Service Proxy (ESP) basé sur NGINX.

Ce document explique comment migrer un déploiement d'API Endpoints existant d'ESP vers ESPv2.

Avant de commencer

Avant de commencer la migration, tenez compte des cas d'utilisation non compatibles et des modifications majeures de l'API décrites ci-dessous.

Cas d'utilisation non compatibles avec ESPv2

  • L'environnement flexible App Engine n'est pas compatible

    L'environnement flexible App Engine est doté d'une compatibilité avec Endpoints intégrée et activée en définissant endpoints_api_service dans le fichier app.yaml de l'application. Cette compatibilité avec Endpoints intégrée ne prend en charge qu'ESP ; il n'est pas possible de la faire migrer vers ESPv2.

    Si vous souhaitez utiliser ESPv2 avec l'environnement flexible App Engine, désactivez endpoints_api_service dans app.yaml. Vous pouvez déployer ESPv2 en tant que service Cloud Run distinct utilisé pour gérer votre application dans l'environnement flexible App Engine. Le déploiement fonctionne de la même manière que l'utilisation d'ESPv2 avec l'environnement standard App Engine.

  • La configuration NGINX personnalisée n'est pas compatible

    ESPv2 est un proxy basé sur Envoy. Il n'est pas compatible avec la configuration de proxy NGINX personnalisée. Si votre configuration ESP utilise les options -n ou --nginx_config, votre mise en œuvre peut reposer sur une configuration NGINX personnalisée et difficile à migrer vers ESPv2.

Modifications importantes

  • Le format de données d'en-tête X-Endpoint-API-UserInfo a été modifié. Si votre application utilise cet en-tête, vous devez le modifier pour utiliser le nouveau format. Pour en savoir plus, consultez la section Gérer les jetons JWT dans le service de backend.
  • Si une clé API est requise pour une requête, ESP envoie l'en-tête X-Endpoint-API-Project-ID avec l'ID du projet client à l'application backend. ESPv2 utilise deux en-têtes différents, X-Endpoint-API-Consumer-Type et X-Endpoint-API-Consumer-Number, pour envoyer les détails requis. Pour en savoir plus sur les Consumer-Type et les Consumer-Number envoyés avec ces en-têtes, consultez la documentation de référence de l'infrastructure de service.

  • Le format du corps de la réponse d'erreur HTTP a été modifié. Lorsque ESPv2 rejette une requête HTTP, il génère un corps de réponse d'erreur dans un nouveau format. Si votre mise en œuvre utilise du code client pour traiter le corps de la réponse JSON de l'erreur HTTP, ce code client doit être mis à jour. Pour en savoir plus, consultez la section Corps de réponse JSON d'une erreur HTTP.

  • De nouvelles options de démarrage sont disponibles, et certaines options d'ESP ont été abandonnées ou remplacées dans ESPv2. Consultez la section Différences entre les options de démarrage d'ESP et d'ESPv2.

Migrer vos API Endpoints pour utiliser ESPv2

La procédure de migration requise pour utiliser ESPv2 avec des plates-formes sans serveur (Cloud Run, fonctions Cloud Run et App Engine) diffère de celle qui est requise pour les plates-formes autres que sans serveur (Google Kubernetes Engine, Compute Engine et Kubernetes).

La procédure de migration requise pour chaque type de plate-forme est décrite ci-dessous :

Plates-formes autres que sans serveur : GKE, Compute Engine, Kubernetes

ESPv2 êta est une option de remplacement pour ESP. Pour la plupart des configurations, il vous suffit de passer au tag d'image Docker.

Toutefois, vous devrez peut-être ajuster vos options de démarrage si vous avez configuré ESP avec les éléments suivants :

  • plusieurs ports via les options --http_port, http2_port et/ou --ssl_port ;
  • SSL, DNS, Client IP ou une autre option rarement utilisée.

De nouveaux indicateurs de démarrage sont disponibles pour ESPv2, et certaines options d'ESP ont été abandonnées ou remplacées. Pour en savoir plus, consultez la section Différences entre les options de démarrage d'ESP et d'ESPv2.

GKE et Kubernetes

Pour migrer les configurations Endpoints pour GKE et Kubernetes, remplacez le tag d'image ESP :1 par :2 dans le fichier de déploiement yaml. Exemple :

- 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",
  ]

Instance

ESP et ESPv2 sont déployés dans le conteneur Docker à l'aide de la commande docker run. Pour migrer des points de terminaison Endpoints pour Compute Engine vers ESPv2, mettez à jour le tag d'image Docker de :1 par :2 dans la commande. Exemple :

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

Plates-formes sans serveur (Cloud Run, Cloud Functions, App Engine)

Dans le cas des plates-formes sans serveur, ESPv2 est déployé en tant que service Cloud Run pour gérer une application s'exécutant sur Cloud Run, Cloud Functions ou App Engine. Pour migrer Endpoints vers ESPv2, vous devez créer la configuration de votre service Endpoints existant dans une nouvelle image Docker ESPv2 bêta, puis déployer cette image sur votre service ESPv2 Cloud Run.

Les étapes de déploiement d'ESP et d'ESPv2 sont identiques, à l'exception des détails suivants :

  • Le tag d'image doit passer de :1 à :2 dans ESPv2 lorsque vous déployez ESPv2 dans Cloud Run. Exemple :

    gcloud run deploy CLOUD_RUN_SERVICE_NAME \
    --image="gcr.io/endpoints-release/endpoints-runtime-serverless:2" \
    --allow-unauthenticated \
    --platform managed \
    --project=ESP_PROJECT_ID  
  • Le script gcloud_build_image est téléchargé à partir d'un autre emplacement. Il utilise gcr.io/endpoints-release/endpoints-runtime-serverless:2 comme image de base.

  • Une variable d'environnement permet de spécifier des options de démarrage. Pour ESP, le nom de cette variable est ESP_ARGS. Le nom d'ESPv2 est ESPv2_ARGS. Pour en savoir plus sur la définition de ESPv2_ARGS et sur les options de démarrage disponibles, consultez la page Options de démarrage d'Extensible Service Proxy v2.

Différences entre les options de démarrage d'ESP et d'ESPv2

Comme pour Extensible Service Proxy, vous pouvez spécifier des options de configuration lors du déploiement des services ESPv2. Avec le passage d'ESP basé sur NGINX à ESPv2 basé sur Envoy, certaines options sont désormais obsolètes ou remplacées, et de nouvelles options ont été ajoutées. Cette section présente ces modifications en trois tableaux :

  • Le tableau 1 présente les nouvelles options qui remplacent les options obsolètes.
  • Le tableau 2 présente les nouvelles options.
  • Le tableau 3 présente les options obsolètes.

Options remplacées

Nouvelles options Options remplacées Description
--listener_port --http_port, --http2_port, --ssl_port Un seul port d'écoute Envoy est compatible avec http, http2 et ssl dans ESPv2. Il est inutile de spécifier des ports distincts.
--ssl_server_cert_path --ssl_port Lorsque --ssl_server_cert_path est utilisé, ESPv2 utilise des certificats issus des fichiers server.key et server.crt. Avec ESPv2, vous pouvez spécifier des chemins de certificats de serveur autres que /etc/nginx/ssl. Cette option remplace --ssl_port dans ESP, qui utilise des certificats ayant pour chemins d'accès /etc/nginx/ssl/nginx.key et /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 Lorsque --ssl_backend_client_cert_path est utilisé, ESPv2 utilise des certificats issus des fichiers client.key et client.crt. Avec ESPv2, vous pouvez spécifier des chemins de certificats clients autres que /etc/nginx/ssl. Cette option remplace --tls_mutual_auth dans ESP, qui utilise des certificats ayant pour chemins d'accès /etc/nginx/ssl/backend.key et /etc/nginx/ssl/backend.crt.
--ssl_backend_client_root_certs_file --grpc_backend_ssl_root_certs_file Avec ESPv2 bêta, --ssl_backend_client_root_certs_file fonctionne pour tous les backends. Cette option remplace --grpc_backend_ssl_root_certs_file dans ESP, qui ne fonctionne que pour les backends gRPC.
--ssl_minimum_protocol,--ssl_maximum_protocol --ssl_protocols Lorsque vous utilisez --ssl_protocols dans ESP, vous devez répertorier tous les protocoles SSL souhaités. Dans ESPv2, vous pouvez spécifier un protocole minimal et maximal.
--envoy_use_remote_address,--envoy_xff_num_trusted_hops --xff_trusted_proxy_list,--client_ip_header,--client_ip_position Envoy nécessite use_remote_address et xff_num_trusted_hops pour configurer l'extraction d'adresse IP clientes.
--dns_resolver_addresses --dns L'option de remplacement suit le même comportement, mais possède une valeur par défaut différente. ESP utilise 8.8.8.8 comme résolveur DNS. ESPv2 utilise le résolveur DNS configuré dans /etc/resolv.conf.
--service_account_key --non_gcp, --service_account_key Dans ESP, l'option --service_account_key autorise implicitement le déploiement sur des plates-formes autres que GCP. Elle empêche ESP d'appeler le serveur de métadonnées d'instance. Dans ESPv2, ce comportement implicite est divisé en une autre option. Vous devrez peut-être ajouter --non_gcp lors de la migration, sinon ESPv2 ne démarrera pas sur des plates-formes autres que GCP.

Nouvelles options

Nouvelles options Description
--http_request_timeout_s Définit le délai en secondes avant expiration de tous les appels distants HTTP/HTTPS, à l'exception des appels backend et des appels Google Service Control.
--service_control_check_timeout_ms Définit le délai en millisecondes avant expiration des appels Google Service Control Check.
--service_control_report_timeout_ms Définit le délai avant expiration des appels de Google Service Control Report.
--service_control_quota_timeout_ms Définit le délai avant expiration des appels de Google Service Control Quota.
--service_control_check_retries Spécifie le nombre de nouvelles tentatives d'appel de Google Service Control Check.
--service_control_report_retries Spécifie le nombre de nouvelles tentatives d'appel de Google Service Control Report.
--service_control_quota_retries Spécifie le nombre de nouvelles tentatives d'appel de Google Service Control Quota.
--backend_dns_lookup_family Configuration spécifique à Envoy utilisée pour définir la famille de résolution DNS de tous les backends.
--disable_tracing Option globale utilisée pour désactiver toutes les traces.
--tracing_project_id Permet de définir l'ID du projet qui possède les données de trace.
--tracing_incoming_context Permet de spécifier le contexte de trace entrant.
--tracing_outgoing_context Permet de spécifier le contexte de trace sortant.

Options obsolètes

Options obsolètes Description
--enable_websocket Websocket est activé par défaut dans Envoy.
--experimental_proxy_backend_host_header Non compatible.
--allow_invalid_headers Non compatible. Voici une configuration NGINX : ignore_invalid_headers. Si une requête HTTP comporte des noms d'en-tête non valides, celle-ci sera rejetée par ESPv2. Les noms d'en-tête valides se composent de lettres de l'alphabet latin, de chiffres, de tirets et de traits de soulignement. Dans ESPv2, l'option --underscores_in_headers détermine si les traits de soulignement sont autorisés dans les en-têtes.
--client_max_body_size Configuration NGINX non compatible.
--client_body_buffer_size Configuration NGINX non compatible.
--large_client_header_buffers Configuration NGINX non compatible.
--keepalive_timeout Configuration NGINX non compatible.
--client_body_timeout Configuration NGINX non compatible.
--rewrite Non compatible.
--experimental_enable_multiple_api_configs Non compatible.
--enable_backend_routing Non requis. Le routage du backend est automatiquement activé pour les plates-formes sans serveur.
--rollout_fetch_throttle_window_in_s Non requis.
--nginx_config Non compatible.

Pour en savoir plus sur les options de démarrage ESPv2, consultez la page Options de démarrage d'Extensible Service Proxy V2. Des exemples génériques supplémentaires et du texte d'aide pour les options sont disponibles sur le dépôt GitHub.

Emplacements JWT par défaut

Par défaut, un jeton JWT est transmis dans l'en-tête Authorization (préfixé par "Bearer"), l'en-tête X-Goog-Iap-Jwt-Assertion ou le paramètre de requête access_token. Ces emplacements sont compatibles avec ESP et ESPv2. Vous pouvez également transmettre un jeton JWT dans l'en-tête Authorization (aucun préfixe) lorsque vous utilisez ESP. Toutefois, cet emplacement n'est pas compatible avec ESPv2.

Si vous souhaitez continuer à transmettre des jetons JWT à l'aide de l'en-tête Authorization (aucun préfixe) après la migration vers ESPv2, vous pouvez :

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

Gérer les jetons JWT dans le service de backend

Lorsque vous utilisez des jetons JWT pour effectuer une authentification, ESPv2 et ESP envoient le résultat d'authentification dans l'en-tête X-Endpoint-API-UserInfo à l'API backend. Nous vous recommandons d'utiliser cet en-tête à la place de l'en-tête d'origine Authorization, car l'en-tête Authorization peut être modifié sur les plates-formes sans serveur.

L'en-tête X-Endpoint-API-UserInfo contient un objet JSON encodé en Base64Url. Cependant, son format a été modifié d'ESP en ESPv2.

Pour ESPv2, l'en-tête X-Endpoint-API-UserInfo contient la charge utile JWT d'origine, sans aucune modification.

Dans ESP, l'en-tête X-Endpoint-API-UserInfo contient la charge utile JWT et quelques champs spécifiques ajoutés par ESP. ESP ajoute les champs id, issuer, email et audiences à l'objet JSON. Il ajoute également le champ claims pour inclure la charge utile JWT d'origine.

# 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
   }
}

L'exemple suivant illustre les différences. Tous ont été décodés en 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
  }
}

Pour en savoir plus sur l'utilisation des jetons JWT pour l'authentification, consultez les pages Utiliser une méthode personnalisée pour authentifier les utilisateurs et Authentification entre les services.

Format du corps de la réponse JSON d'erreur

Si une requête HTTP est rejetée par ESP ou ESPv2, le corps de la réponse contient un code d'état et un message d'erreur au format JSON. Le format du corps de la réponse a été modifié dans ESPv2, comme indiqué dans les exemples ci-dessous :

Corps de réponse d'erreur d'ESP

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

Corps de la réponse d'erreur d'ESPv2

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

Il y a deux différences principales :

  • Dans ESPv2, le champ code contient un code d'état HTTP au lieu du code d'état RPC utilisé par ESP.
  • Le corps de la réponse d'erreur dans ESPv2 ne contient pas de champ details.

Étape suivante

Apprenez-en davantage sur les points suivants :