Configurer un proxy Pub/Sub pour les clients mobiles sur GKE


Ce tutoriel explique comment publier des messages provenant d'applications mobiles ou côté client dans Pub/Sub à l'aide d'un proxy qui gère la logique d'authentification et d'autorisation au lieu d'identifiants côté client.

Vous pouvez authentifier les messages envoyés par le client à Pub/Sub à l'aide de Identity and Access Management (IAM), mais ces identifiants de longue durée n'expirent jamais. Dans les applications côté client, ces identifiants peuvent être découverts grâce à des techniques telles que la décompilation d'applications et la rétro-ingénierie.

À la place, vous pouvez décharger la logique d'authentification et d'autorisation sur un proxy qui effectue les tâches suivantes :

  • Il authentifie les requêtes entrantes pour valider l'utilisateur.
  • Il transfère les requêtes vers Pub/Sub avec les autorisations IAM appropriées.

Ce tutoriel explique comment mettre en œuvre un proxy Pub/Sub sur Google Kubernetes Engine (GKE). Il est destiné aux développeurs d'applications et aux architectes système qui définissent et mettent en œuvre la conception d'applications mobiles ou côté client. Nous partons du principe que vous comprenez les concepts fondamentaux de Kubernetes et que vous êtes familiarisé avec Cloud Endpoints.

Flux de requêtes pour ce tutoriel

Pour comprendre comment Pub/Sub s'intègre dans un pipeline de streaming, envisagez d'effectuer une analyse des flux de clics. Dans ce cas d'utilisation, vous souhaiterez peut-être comprendre comment les utilisateurs interagissent avec votre application mobile. Pour obtenir ces informations, vous devez capturer l'activité des utilisateurs en temps réel. Le schéma suivant illustre le flux de données.

Le proxy Pub/Sub reçoit les messages du client avant que les données soient agrégées.

Les données capturées par l'application sont transmises à Pub/Sub via un proxy. Pub/Sub peut avoir des abonnés en aval, tels que Dataflow ou Dataproc, qui agrègent les données afin que vous puissiez effectuer une analyse significative.

Le schéma suivant présente une vue détaillée du flux de requêtes suivi par ce tutoriel.

Interaction des composants du pipeline dans une requête utilisateur.

Les sections suivantes expliquent comment les différents composants figurant dans ce schéma interagissent.

Authentification des utilisateurs

Les applications mobiles peuvent authentifier les utilisateurs à l'aide de diverses méthodes. Le flux d'authentification est propre à votre application. Ce tutoriel présente l'une de ces solutions d'authentification des utilisateurs. Une mise en œuvre de cette solution accompagne ce tutoriel.

Requêtes envoyées par l'application cliente au proxy Pub/Sub

Le backend de l'application génère un jeton d'authentification de courte durée que le client stocke localement (par exemple, à l'aide du système Android Keystore ou des services de trousseau iOS). Ce tutoriel utilise des jetons d'ID OpenID Connect (OIDC) pour authentifier l'application cliente. Google émet et signe le jeton d'ID OIDC.

L'application côté client envoie une requête au proxy Pub/Sub à l'aide du jeton d'ID OIDC. Le proxy Pub/Sub valide le jeton et transfère la requête à Pub/Sub avec les identifiants IAM appropriés.

Publier des messages

Une fois l'application cliente authentifiée, le proxy Pub/Sub envoie une requête de publication à Pub/Sub. Avec IAM, Pub/Sub permet de s'assurer que l'appelant (le proxy Pub/Sub) dispose des autorisations appropriées pour envoyer des requêtes de publication. Dans ce tutoriel, le proxy Pub/Sub utilise le compte de service Compute Engine par défaut pour s'authentifier auprès de Pub/Sub. Le compte de service Compute Engine par défaut dispose du rôle IAM Éditeur (roles/editor), qui fournit un accès en publication au proxy Pub/Sub.

Objectifs

  • Créer un cluster GKE pour exécuter un proxy Pub/Sub
  • Créer un sujet Pub/Sub
  • Déployer le proxy Pub/Sub
  • Configurer Endpoints pour authentifier les requêtes adressées au proxy Pub/Sub
  • Vérifier que les messages sont publiés dans Pub/Sub

Coûts

Dans ce document, vous utilisez les composants facturables suivants de Google Cloud :

Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût. Les nouveaux utilisateurs de Google Cloud peuvent bénéficier d'un essai gratuit.

Une fois que vous avez terminé les tâches décrites dans ce document, vous pouvez éviter de continuer à payer des frais en supprimant les ressources que vous avez créées. Pour en savoir plus, consultez la section Effectuer un nettoyage.

Avant de commencer

  1. Dans Google Cloud Console, accédez à la page de sélection du projet.

    Accéder au sélecteur de projet

  2. Sélectionnez ou créez un projet Google Cloud.

  3. Vérifiez que la facturation est activée pour votre projet Google Cloud.

  4. Dans la console Google Cloud, activez Cloud Shell.

    Activer Cloud Shell

    En bas de la fenêtre de la console Google Cloud, une session Cloud Shell démarre et affiche une invite de ligne de commande. Cloud Shell est un environnement shell dans lequel Google Cloud CLI est déjà installé, et dans lequel des valeurs sont déjà définies pour votre projet actuel. L'initialisation de la session peut prendre quelques secondes.

  5. Définissez les variables d'environnement dont vous avez besoin pour ce tutoriel :
        export PROJECT=$(gcloud config get-value project)
        export REGION=us-central1
        export ZONE=${REGION}-b
        export CLUSTER=pubsub-proxy
        export TOPIC=proxy-test
        export SERVICE_ACCOUNT=publish-test
        export ENDPOINTS_SERVICE="pubtest.endpoints.${PROJECT}.cloud.goog"
        export GENERATE_TOKEN="https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts"
  6. Activez les API pour Cloud Build, Compute Engine, Google Kubernetes Engine, Artifact Analysis, Container Registry, Endpoints, Service Management, Service Control et Pub/Sub :
        gcloud services enable \
            cloudbuild.googleapis.com \
            compute.googleapis.com \
            container.googleapis.com \
            containeranalysis.googleapis.com \
            containerregistry.googleapis.com \
            endpoints.googleapis.com \
            servicemanagement.googleapis.com \
            servicecontrol.googleapis.com \
            pubsub.googleapis.com

Créer un sujet Pub/Sub

  • Dans Cloud Shell, créez un sujet Pub/Sub dans lequel vous publiez des messages :

    gcloud pubsub topics create $TOPIC
    

Créer un cluster GKE

  1. Dans Cloud Shell, créez un cluster GKE :

    gcloud container clusters create $CLUSTER \
        --zone $ZONE \
        --scopes "https://www.googleapis.com/auth/cloud-platform"
    
  2. Obtenez les identifiants du cluster en cours d'exécution :

    gcloud container clusters get-credentials $CLUSTER \
        --zone $ZONE \
        --project $PROJECT
    

Créer une image de conteneur

  1. Dans Cloud Shell, clonez le dépôt de code :

    git clone https://github.com/GoogleCloudPlatform/solutions-pubsub-proxy-rest
    
  2. Utilisez Cloud Build pour créer une image de conteneur à partir de la source, puis enregistrez-la dans Container Registry :

    cd solutions-pubsub-proxy-rest && \
        gcloud builds submit --tag gcr.io/$PROJECT/pubsub-proxy:v1
    

Créer une adresse IP externe statique

  1. Dans Cloud Shell, créez une adresse IP externe statique qui est ensuite attribuée à l'équilibreur de charge du proxy Pub/Sub :

    gcloud compute addresses create service-ip --region $REGION
    
  2. Stockez l'adresse IP statique dans une variable d'environnement, PROXY_IP :

    PROXY_IP=$(gcloud compute addresses describe service-ip \
        --region $REGION --format='value(address)')
    

Déployer Endpoints

Le proxy Pub/Sub authentifie les requêtes des utilisateurs à l'aide d'Endpoints. Endpoints utilise Extensible Service Proxy (ESP) pour fournir des fonctionnalités de gestion d'API telles que l'authentification, la surveillance, le traçage et la gestion du cycle de vie des API. Ce tutoriel utilise Endpoints seulement pour authentifier les requêtes entrantes adressées au proxy Pub/Sub.

Dans ce tutoriel, vous allez déployer ESP en tant que side-car avec le proxy Pub/Sub. ESP intercepte et authentifie les requêtes entrantes avant de les transférer au proxy Pub/Sub.

  1. Dans Cloud Shell, remplacez l'espace réservé [PROJECT_ID] par l'ID de votre projet Google Cloud dans le fichier openapi.yaml :

    sed -i -e "s/\[PROJECT_ID\]/$PROJECT/g" openapi.yaml
    
  2. Dans le fichier manifeste OpenAPI, remplacez l'espace réservé [IP_ADDRESS] par la valeur de PROXY_IP :

    sed -i -e "s/\[IP_ADDRESS\]/$PROXY_IP/g" openapi.yaml
    
  3. Déployez la définition du service OpenAPI sur Endpoints :

    gcloud endpoints services deploy openapi.yaml
    

    La commande précédente crée les éléments suivants :

    • Un service géré portant le nom que vous avez spécifié dans le champ d'hôte du fichier openapi.yaml (pubtest.endpoints.project-id.cloud.goog), où project-id correspond à l'ID de votre projet Google Cloud.
    • Un enregistrement DNS A qui utilise le mappage du nom du service et de l'adresse IP de l'équilibreur de charge du proxy Pub/Sub défini dans l'extension x-google-endpoints du fichier openapi.yaml

    Pendant le déploiement, un avertissement s'affiche. Vous pouvez l'ignorer, car ce tutoriel utilise des jetons d'ID OIDC pour l'authentification au lieu de clés API.

    WARNING: openapi.yaml: Operation 'post' in path '/publish': Operation does
    not require an API key; callers may invoke the method without specifying an
    associated API-consuming project. To enable API key all the
    SecurityRequirement Objects
    (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-requirement-object)
    inside security definition must reference at least one SecurityDefinition
    of type : 'apiKey'.
    
  4. Vérifiez si le service est déployé correctement :

    gcloud endpoints services describe ${ENDPOINTS_SERVICE}
    

    Le résultat ressemble à ce qui suit :

    [...]
    producerProjectId: project-id
    serviceConfig:
      documentation:
        summary: Pub/Sub proxy exposed as an Endpoint API
    [...]
      name: pubtest.endpoints.project-id.cloud.goog
      title: PubSub Proxy
      usage: {}
    serviceName: pubtest.endpoints.project-id.cloud.goog
    

    Dans le résultat :

    • project-id : ID de votre projet Google Cloud

Déployer un proxy

  1. Dans Cloud Shell, générez un certificat SSL autosigné pour autoriser les connexions HTTPS au proxy.

    openssl req -x509 -nodes -days 365 \
        -newkey rsa:2048 -keyout ./nginx.key \
        -out ./nginx.crt \
        -subj "/CN=${ENDPOINTS_SERVICE}"
    
  2. Créez un secret Kubernetes à l'aide du certificat SSL et de la clé privée :

    kubectl create secret generic nginx-ssl \
        --from-file=./nginx.crt \
        --from-file=./nginx.key
    
  3. Remplacez l'espace réservé [PROJECT_ID] dans le fichier manifeste de déploiement par l'ID de votre projet Google Cloud :

    sed -i -e "s/\[PROJECT_ID\]/$PROJECT/g" kube/deployment.yaml
    
  4. Remplacez l'espace réservé [IP_ADDRESS] dans le fichier manifeste de service par la valeur de PROXY_IP :

    sed -i -e "s/\[IP_ADDRESS\]/$PROXY_IP/g" kube/service.yaml
    
  5. Déployez le proxy :

    kubectl apply -f kube/
    
  6. Vérifiez que le déploiement a réussi :

    kubectl rollout status deployment/pubsub-proxy
    

    Le résultat ressemble à ce qui suit :

    [...]
    deployment "pubsub-proxy" successfully rolled out
    
  7. Assurez-vous que deux conteneurs (ESP et le proxy Pub/Sub) s'exécutent dans le pod :

    kubectl get pods $(kubectl get pod \
        -l app=pubsub-proxy \
        -o jsonpath="{.items[0].metadata.name}") \
        -o jsonpath={.spec.containers[*].name}
    

    Le résultat ressemble à ce qui suit :

    esp  pubsub-proxy
    
  8. Vérifiez que la valeur de EXTERNAL-IP passe de <pending>à l'adresse IP externe statique que vous avez créée précédemment :

    kubectl get svc pubsub-proxy -w
    

    Le résultat ressemble à ce qui suit :

    NAME          TYPE          CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
    pubsub-proxy  LoadBalancer  10.7.247.212  <pending>     443:31104/TCP  6m32s
    pubsub-proxy  LoadBalancer  10.7.247.212  <PROXY_IP>    443:31104/TCP  6m5s
    

    Pour arrêter la vérification, appuyez sur CTRL+C.

    Une fois le proxy Pub/Sub déployé, il est exposé à l'adresse https://${ENDPOINTS_SERVICE}/publish. La propagation de la nouvelle configuration DNS peut prendre quelques minutes.

  9. Vérifiez la configuration DNS :

    watch nslookup ${ENDPOINTS_SERVICE}
    

    Le résultat ressemble à ce qui suit :

    Server:   169.254.169.254
    Address:  169.254.169.254#53
    
    Non-authoritative answer:
    Name: pubtest.endpoints.project-id.cloud.goog
    Address: gke-load-balancer-ip
    

    Dans le résultat :

    • gke-load-balancer-ip : adresse IP de votre équilibreur de charge GKE (adresse IP du proxy).

    Pour arrêter la vérification, appuyez sur CTRL+C.

Si l'une des étapes précédentes génère une erreur, consultez les étapes de dépannage.

Générer un jeton d'authentification

La procédure suivante de génération d'un jeton d'authentification est fournie à titre d'exemple. Pour votre environnement de production, vous devez fournir à vos utilisateurs un moyen de générer leurs propres jetons d'authentification. Par exemple, vous trouverez un exemple de code permettant d'obtenir un jeton d'ID OIDC de manière automatisée dans la documentation Identity-Aware Proxy.

Pour générer un jeton d'authentification, procédez comme suit :

  1. Créez un compte de service Google Cloud pour lequel vous générez un jeton d'ID OIDC :

    gcloud iam service-accounts create \
        $SERVICE_ACCOUNT \
        --display-name $SERVICE_ACCOUNT
    
  2. Obtenez l'identité de messagerie du compte de service :

    SA_EMAIL=${SERVICE_ACCOUNT}@${PROJECT}.iam.gserviceaccount.com
    
  3. Attribuez le rôle IAM Créateur de jetons du compte de service (roles/iam.serviceAccountTokenCreator) pour le compte de service :

    gcloud iam service-accounts add-iam-policy-binding $SA_EMAIL \
        --member user:$(gcloud config get-value account) \
        --role roles/iam.serviceAccountTokenCreator
    
  4. À l'aide de l'API IAM Credentials, générez un jeton d'ID OIDC.

    TOKEN=$(curl -s ${GENERATE_TOKEN}/${SA_EMAIL}:generateIdToken \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        -d '{"audience": "'${ENDPOINTS_SERVICE}'", "includeEmail": "true"}' | jq -r ".token")
    

    Le nom du service Endpoints est spécifié dans le champ audience. La revendication audience identifie le destinataire auquel le jeton est destiné.

  5. Vérifiez que le jeton a bien été créé :

    echo $TOKEN
    

    Le jeton Web JSON (JWT, JSON Web Token) est semblable à celui-ci :

    eyJhbGciOiJSUzI1NiIsImtpZCI6IjY4NjQyODlm[...].eyJhdWQiOiJwdWJ0ZXN0LmVuZHBvaW50cy52aXR
    hbC1vY3RhZ29uLTEwOTYxMi5jbG91ZC5nb[...].SjBI4TZjZAlYo6lFKkrvfAcVUp_AJzFKoSsjNbmD_n[...]
    

Appeler Pub/Sub à l'aide d'un proxy

  1. Dans Cloud Shell, publiez un message de test :

    curl -i -k -X POST https://${ENDPOINTS_SERVICE}/publish \
        -H "Authorization: Bearer $TOKEN" \
        -H "Content-Type: application/json" \
        -d '{"topic": "'$TOPIC'", "messages": [ {"attributes": {"key1": "value1", "key2" : "value2"}, "data": "test data"}]}'
    

    Le résultat ressemble à ce qui suit :

    HTTP/2 200
    server: nginx
    date: Sun, 02 Jun 2019 03:53:46 GMT
    ...
    
  2. Vérifiez si le message a bien été publié dans le sujet Pub/Sub :

    kubectl logs -f --tail=5 deployment/pubsub-proxy -c pubsub-proxy
    

    Les journaux de déploiement du proxy Pub/Sub affichent le message Successfully published :

    2019-06-02 03:49:39.723:INFO:oejs.Server:main: Started @2554ms
    Jun 02, 2019 3:53:44 AM com.google.pubsub.proxy.publish.PublishMessage
    getPublisher
    INFO: Creating new publisher for: proxy-test
    Jun 02, 2019 3:53:47 AM
    com.google.pubsub.proxy.publish.PublishMessage$1 onSuccess
    INFO: Successfully published: 569006136173844
    

Dépannage

  1. Dans Cloud Shell, vérifiez l'état des deux conteneurs dans le pod du proxy Pub/Sub :

    kubectl describe pods $(kubectl get pod -l app=pubsub-proxy \
        -o jsonpath="{.items[0].metadata.name}")
    

    Dans la sortie du journal, l'état des conteneurs est Running :

    [...]
    Containers:
      esp:
    [...]
      State:  Running
        Started:  Fri, 21 Jun 2019 16:41:30 +0530
      Ready:  True
      Restart Count:  0
    [...]
      pubsub-proxy:
        State:  Running
          Started:  Fri, 21 Jun 2019 16:41:42 +0530
        Ready:  True
        Restart Count:  0
    [...]
    
  2. (Facultatif) Consultez les journaux des conteneurs pour voir s'il existe d'autres erreurs. Par exemple, pour vérifier les journaux du proxy Pub/Sub, exécutez la commande suivante :

    kubectl logs -f --tail=10 deployment/pubsub-proxy -c pubsub-proxy
    

Pour obtenir de l'aide concernant le dépannage, consultez les documents suivants :

Nettoyer

Pour éviter que des frais ne soient facturés sur votre compte Google Cloud pour les ressources utilisées dans ce tutoriel, vous pouvez supprimer le projet Google Cloud que vous avez créé ou supprimer les ressources associées à ce tutoriel.

Supprimer le projet Google Cloud

Le moyen le plus simple d'empêcher la facturation est de supprimer le projet que vous avez créé pour ce tutoriel.

  1. Dans la console Google Cloud, accédez à la page Gérer les ressources.

    Accéder à la page Gérer les ressources

  2. Dans la liste des projets, sélectionnez le projet que vous souhaitez supprimer, puis cliquez sur Supprimer.
  3. Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur Arrêter pour supprimer le projet.

Supprimer les ressources

Si vous souhaitez conserver le projet Google Cloud que vous avez utilisé dans ce tutoriel, supprimez les différentes ressources :

  1. Dans Cloud Shell, supprimez le cluster GKE :

    gcloud container clusters delete $CLUSTER --zone $ZONE --async
    
  2. Supprimez le code, les artefacts et les autres dépendances que vous avez téléchargés :

    cd .. && rm -rf solutions-pubsub-proxy-rest
    
  3. Supprimez l'image dans Container Registry :

    gcloud container images list-tags \
        gcr.io/$PROJECT/pubsub-proxy \
        --format 'value(digest)' | \
        xargs -I {} gcloud container images delete \
        --force-delete-tags --quiet \
        gcr.io/${PROJECT}/pubsub-proxy@sha256:{}
    
  4. Supprimez le sujet Pub/Sub :

    gcloud pubsub topics delete $TOPIC
    
  5. Supprimez le compte de service :

    gcloud iam service-accounts delete $SA_EMAIL
    
  6. Supprimez Endpoints :

    gcloud endpoints services delete ${ENDPOINTS_SERVICE}
    
  7. Supprimez l'adresse IP statique :

    gcloud compute addresses delete service-ip --region $REGION
    

Étape suivante