En plus de l'authentification des utilisateurs, vous devrez peut-être autoriser d'autres services à interagir avec l'API. Bien que les applications clientes puissent fournir aux utilisateurs une invite de connexion Web pour soumettre leurs identifiants, vous avez besoin d'une autre approche pour une communication de service à service sécurisée. Cette page présente l'approche recommandée pour la mise en œuvre de l'authentification entre services et fournit un exemple de code.
Présentation
Pour identifier un service qui envoie des requêtes à l'API, vous utilisez un compte de service. Le service appelant utilise la clé privée du compte de service pour signer un jeton Web JSON (JWT) sécurisé et envoie le jeton JWT signé dans la requête à l'API.
Pour mettre en œuvre l'authentification de service à service dans l'API et le service appelant :
- Créez un compte de service et une clé pour le service appelant à utiliser.
- Ajoutez la compatibilité pour l'authentification dans le document OpenAPI pour le service Cloud Endpoints.
Ajoutez du code au service appelant qui :
- crée un jeton JWT et le signe avec la clé privée du compte de service ;
- envoie le jeton JWT signé dans une requête à l'API.
Le proxy ESP vérifie que les revendications du jeton JWT correspondent à la configuration du document OpenAPI avant de transférer la requête à l'API. Il ne vérifie pas les autorisations Cloud Identity accordées sur le compte de service.
Prérequis
Cette page suppose que vous avez déjà :
Créer un compte de service avec une clé
Vous devez disposer d'un compte de service contenant un fichier de clé privée que le service appelant utilise pour signer le jeton JWT. Si plusieurs services envoient des requêtes à l'API, vous pouvez créer un compte de service représentant tous les services appelants. Si vous devez différencier les services (ils peuvent, par exemple, disposer d'autorisations différentes), vous pouvez créer un compte de service et une clé pour chaque service appelant.
Cette section explique comment utiliser la console Google Cloud et l'outil de ligne de commande gcloud
pour créer le compte de service et le fichier de clé privée, et comment attribuer au compte de service le rôle Créateur de jetons du compte de service. Pour en savoir plus sur l'utilisation d'une API pour effectuer cette tâche, consultez la section Créer et gérer des comptes de service.
Créez un compte de service et une clé :
Console Google Cloud
Créez un compte de service :
Dans la console Google Cloud, accédez à la page Créer un compte de service.
Sélectionnez le projet que vous souhaitez utiliser.
Dans le champ Nom du compte de service, saisissez un nom.
Facultatif : Dans le champ Description du compte de service, saisissez une description.
Cliquez sur Create (Créer).
Cliquez sur le champ Sélectionner un rôle. Sous Tous les rôles, sélectionnez Compte de service > Créateur de jetons du compte de service.
Cliquez sur OK.
Ne fermez pas la fenêtre de votre navigateur. Vous en aurez besoin lors de la tâche suivante.
Créez une clé de compte de service :
- Dans la console Google Cloud, cliquez sur l'adresse e-mail du compte de service que vous avez créé.
- Cliquez sur Clés.
- Cliquez sur AJOUTER UNE CLÉ -> Créer une clé.
- Cliquez sur Create (Créer). Un fichier JSON contenant la clé privée du compte de service est téléchargé sur votre ordinateur.
- Cliquez sur Close (Fermer).
gcloud
Vous pouvez exécuter les commandes suivantes à l'aide de la Google Cloud CLI sur votre ordinateur local ou dans Cloud Shell.
Définissez le compte par défaut pour
gcloud
. Si vous avez plusieurs comptes, veillez à choisir le compte du projet Google Cloud que vous souhaitez utiliser.gcloud auth login
Saisissez la commande suivante pour afficher les ID de vos projets Google Cloud :
gcloud projects list
Définissez le projet par défaut. Remplacez
PROJECT_ID
par l'ID du projet Google Cloud que vous souhaitez utiliser.gcloud config set project PROJECT_ID
Créez un compte de service. Remplacez
SA_NAME
etSA_DISPLAY_NAME
par le nom et le nom à afficher que vous souhaitez utiliser.gcloud iam service-accounts create SA_NAME \ --display-name "SA_DISPLAY_NAME"
Affichez l'adresse e-mail du compte de service que vous venez de créer.
gcloud iam service-accounts list
Ajoutez le rôle Créateur de jetons du compte de service. Remplacez
SA_EMAIL_ADDRESS
par l'adresse e-mail du compte de service.gcloud projects add-iam-policy-binding PROJECT_ID \ --member serviceAccount:SA_EMAIL_ADDRESS \ --role roles/iam.serviceAccountTokenCreator
Créez un fichier de clé de compte de service dans le répertoire de travail actuel. Remplacez
FILE_NAME
par le nom que vous souhaitez utiliser pour le fichier de clé. Par défaut, la commandegcloud
crée un fichier JSON.gcloud iam service-accounts keys create FILE_NAME.json \ --iam-account SA_EMAIL_ADDRESS
Pour en savoir plus sur les commandes précédentes, consultez la documentation de référence sur gcloud
.
Pour plus d'informations sur la sauvegarde de la clé privée, consultez la section Bonnes pratiques de gestion des identifiants.
Configurer l'API pour la fonctionnalité d'authentification
Vous devez disposer d'un objet d'exigences de sécurité et d'un objet de définitions de sécurité dans le document OpenAPI pour que le proxy ESP puisse valider les revendications dans le jeton JWT signé.
Ajoutez le compte de service en tant qu'émetteur dans le document OpenAPI.
securityDefinitions: DEFINITION_NAME: authorizationUrl: "" flow: "implicit" type: "oauth2" x-google-issuer: "SA_EMAIL_ADDRESS" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/SA_EMAIL_ADDRESS"
- Remplacez
DEFINITION_NAME
par une chaîne qui identifie cette définition de sécurité. Vous pouvez le remplacer par le nom du compte de service ou un nom qui identifie le service appelant. - Remplacez
SA_EMAIL_ADDRESS
par l'adresse e-mail du compte de service. - Vous pouvez établir plusieurs définitions de sécurité dans le document OpenAPI, mais l'émetteur (
x-google-issuer
) doit être différent pour chaque définition. Si vous avez créé des comptes de service distincts pour chaque service appelant, vous pouvez créer une définition de sécurité pour chaque compte de service, par exemple :
securityDefinitions: service-1: authorizationUrl: "" flow: "implicit" type: "oauth2" x-google-issuer: "service-1@example-project-12345.iam.gserviceaccount.com" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/service-1@example-project-12345.iam.gserviceaccount.com" service-2: authorizationUrl: "" flow: "implicit" type: "oauth2" x-google-issuer: "service-2@example-project-12345.iam.gserviceaccount.com" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/service-2@example-project-12345.iam.gserviceaccount.com"
- Remplacez
Vous pouvez également ajouter
x-google-audiences
à la sectionsecurityDefinitions
. Si vous n'ajoutez pasx-google-audiences
, ESP exige que la revendication"aud"
(audience) du jeton JWT soit au formathttps://SERVICE_NAME
, où SERVICE_NAME correspond au nom de votre service Endpoints, que vous avez configuré dans le champhost
du document OpenAPI, sauf si l'indicateur--disable_jwt_audience_service_name_check
est utilisé. Si l'indicateur est utilisé et quex-google-audiences
n'est pas spécifié, le champaud
du jeton JWT n'est pas validé.Vous pouvez également ajouter
x-google-jwt-locations
à la sectionsecurityDefinitions
. Vous pouvez utiliser cette valeur pour définir un emplacement JWT personnalisé. Les emplacements JWT par défaut sont l'en-têteAuthorization
(préfixé par "Bearer"), l'en-têteX-Goog-Iap-Jwt-Assertion
et le paramètre de requêteaccess_token
. Remarque :- Si vous spécifiez
x-google-jwt-locations
, Endpoints ignore tous les emplacements par défaut. x-google-jwt-locations
n'est compatible qu'avec ESPv2.
- Si vous spécifiez
Ajoutez une section
security
au niveau supérieur du fichier (non imbriqué ni en retrait) pour l'appliquer à l'ensemble de l'API, ou au niveau d'une méthode spécifique pour ne l'appliquer qu'à celle-ci. Attention, si vous utilisez des sectionssecurity
au niveau de l'API et au niveau de la méthode, les paramètres au niveau de l'API seront ignorés.security: - DEFINITION_NAME: []
- Remplacez
DEFINITION_NAME
par le nom que vous avez utilisé dans la sectionsecurityDefinitions
. Si vous avez plusieurs définitions dans la section
securityDefinitions
, ajoutez-les dans la sectionsecurity
. Exemple :security: - service-1: [] - service-2: []
- Remplacez
Déployez le document OpenAPI mis à jour. Remplacez
OPENAPI_DOC
par le nom du document OpenAPI.gcloud endpoints services deploy OPENAPI_DOC
Avant que le proxy ESP ne transmette une requête à l'API, il vérifie :
- la signature du jeton JWT à l'aide de la clé publique, située dans l'URI spécifié dans le champ
x-google-jwks_uri
du document OpenAPI ; - que la revendication
"iss"
(émetteur) du jeton JWT correspond à la valeur spécifiée dans le champx-google-issuer
; - que la revendication
"aud"
(audience) du jeton JWT contient le nom du service Endpoints ou correspond à l'une des valeurs que vous avez spécifiées dans le champx-google-audiences
; - que le jeton n'a pas expiré en utilisant la revendication
"exp"
(date/heure d'expiration).
Pour en savoir plus sur x-google-issuer
, x-google-jwks_uri
, x-google-audiences
et x-google-jwt-locations
, consultez la page Extensions OpenAPI.
Effectuer une requête authentifiée à une API Endpoints
Pour effectuer une requête authentifiée, le service appelant envoie un jeton JWT signé par le compte de service que vous avez spécifié dans le document OpenAPI. Le service appelant doit :
- Créer un jeton JWT et le signer avec la clé privée du compte de service.
- Envoyer le jeton JWT signé dans une requête à l'API.
L'exemple de code suivant illustre ce processus pour certains langages. Pour effectuer une requête authentifiée dans d'autres langages, reportez-vous à jwt.io pour obtenir la liste des bibliothèques compatibles.
- Ajoutez la fonction suivante au service appelant et transmettez-lui les paramètres suivants :
Java -
saKeyfile
: chemin d'accès complet au fichier de clé privée du compte de service. saEmail
: adresse e-mail du compte de service.-
audience
: si vous avez ajouté le champx-google-audiences
au document OpenAPI, définissezaudience
sur l'une des valeurs que vous avez spécifiées pourx-google-audiences
. Sinon, définissezaudience
surhttps://SERVICE_NAME
, oùSERVICE_NAME
est le nom du service Endpoints. expiryLength
: délai d'expiration du jeton JWT, en secondes.
Python sa_keyfile
: chemin d'accès complet au fichier de clé privée du compte de service.-
sa_email
: adresse e-mail du compte de service. -
audience
: si vous avez ajouté le champx-google-audiences
au document OpenAPI, définissezaudience
sur l'une des valeurs que vous avez spécifiées pourx-google-audiences
. Sinon, définissezaudience
surhttps://SERVICE_NAME
, oùSERVICE_NAME
est le nom du service Endpoints. expiry_length
: délai d'expiration du jeton JWT, en secondes.
Go -
saKeyfile
: chemin d'accès complet au fichier de clé privée du compte de service. -
saEmail
: adresse e-mail du compte de service. -
audience
: si vous avez ajouté le champx-google-audiences
au document OpenAPI, définissezaudience
sur l'une des valeurs que vous avez spécifiées pourx-google-audiences
. Sinon, définissezaudience
surhttps://SERVICE_NAME
, oùSERVICE_NAME
est le nom du service Endpoints. -
expiryLength
: délai d'expiration du jeton JWT, en secondes.
La fonction crée un jeton JWT, le signe à l'aide du fichier de clé privée et renvoie le jeton JWT signé.
Java Python Go -
- Dans le service appelant, ajoutez la fonction suivante pour envoyer le jeton JWT signé dans l'en-tête
Authorization: Bearer
de la requête à l'API :Java Python Go
Par mesure de sécurité, lorsque vous envoyez une requête à l'aide d'un jeton JWT, nous vous recommandons de placer le jeton d'authentification dans l'en-tête Authorization: Bearer
. Exemple :
curl --request POST \ --header "Authorization: Bearer ${TOKEN}" \ "${ENDPOINTS_HOST}/echo"
où ENDPOINTS_HOST
et TOKEN
sont des variables d'environnement contenant, respectivement, le nom d'hôte de l'API et le jeton d'authentification.
Recevoir les résultats authentifiés dans votre API
ESP transfère généralement tous les en-têtes reçus. Cependant, il remplace l'en-tête Authorization
d'origine lorsque l'adresse de backend est spécifiée par x-google-backend
dans la spécification OpenAPI ou BackendRule
dans la configuration du service gRPC.
ESP envoie le résultat de l'authentification dans le champ X-Endpoint-API-UserInfo
à l'API backend. Nous vous recommandons d'utiliser cet en-tête à la place de l'en-tête Authorization
d'origine. Cet en-tête est une chaîne qui définit un encodage base64url
d'un objet JSON. Le format de l'objet JSON diffère entre ESPv2 et ESP.
Pour ESPv2, l'objet JSON correspond exactement à la charge utile JWT d'origine. Pour ESP, l'objet JSON utilise des noms de champ différents et place la charge utile JWT d'origine sous le champ claims
.
Pour en savoir plus sur le format, consultez la section Gérer les jetons JWT dans le service de backend.