Autenticazione tra servizi

Puoi implementare l'autenticazione tra i servizi utilizzando un account di servizio in un servizio gRPC. Questa pagina illustra l'autenticazione da servizio a servizio guidandoti attraverso un esempio completo, incluso come configurare Extensible Service Proxy (ESP) in un servizio gRPC per supportare le richieste autenticate e come chiamare il servizio da un client gRPC.

Affinché un servizio possa effettuare chiamate autenticate a un'API Cloud Endpoints, il servizio chiamante deve disporre di un service account e deve inviare un token di autenticazione nella chiamata. Il chiamante deve utilizzare un token ID Google o un JSON Web Token (JWT) personalizzato firmato solo dall'account di servizio del chiamante. ESP convalida che l'attestazione iss nel JWT corrisponda all'impostazione issuer nella configurazione del servizio. ESP non verifica le autorizzazioni di Identity and Access Management concesse all'account di servizio.

Nel nostro esempio, configuri e utilizzi la forma più semplice di autenticazione da servizio a servizio, in cui il client utilizza il proprio service account Google Cloud per generare JWT di autenticazione. L'approccio per gli altri metodi di autenticazione è simile, anche se il processo lato client per ottenere token di autenticazione validi dipende dal metodo di autenticazione utilizzato.

Prima di iniziare

Questa guida utilizza l'esempio della libreria utilizzato nei nostri tutorial.

  1. Clona il repository Git in cui è ospitato il codice di esempio gRPC:

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git
    
  2. Cambia la directory di lavoro:

    cd python-docs-samples/endpoints/bookstore-grpc/
    
  3. Segui le istruzioni riportate nei tutorial per configurare un progetto, se non ne hai già uno.

In questo esempio, utilizzi il deployment in Google Kubernetes Engine, anche se la configurazione dell'autenticazione è la stessa per Compute Engine.

Nell'esempio, vengono fatti riferimenti a due progetti Google Cloud Platform:

  • Il progetto di producer di servizi, ovvero il progetto proprietario del servizio Cloud Endpoints per gRPC.
  • Il progetto consumer del servizio, ovvero il progetto proprietario del client gRPC.

Creazione del account di servizio e della chiave del consumer

Per creare l'account di servizio e la chiave per il progetto consumer:

  1. Nella console Google Cloud , vai ad API e servizi.

    API e servizi

    Assicurati di trovarti nel tuo progetto consumer.
  2. Nella pagina Credenziali, seleziona Chiave account di servizio dall'elenco a discesa Crea credenziali.
  3. Nella pagina Crea account di servizio account, seleziona un service account esistente che vuoi utilizzare. Altrimenti, nell'elenco a discesa Service account, seleziona Nuovo service account e digita un nome per l'account.

    Viene creato un ID service account corrispondente. Prendi nota dell'ID, perché ti servirà nelle sezioni successive. Ad esempio:

    service-account-name@YOUR_PROJECT_ID.iam.gserviceaccount.com
    
  4. Fai clic sull'elenco a discesa Ruolo e seleziona i ruoli seguenti:

    • Service account > Service Account User
    • Service account > Creatore token service account
  5. Assicurati che sia selezionato il tipo di chiave JSON.

  6. Fai clic su Crea. Il file della chiave JSON dell'account di servizio viene scaricato sul computer locale. Prendi nota della posizione e assicurati che sia memorizzata in modo sicuro perché viene utilizzata in seguito per generare i token.

Configurazione dell'autenticazione per il servizio

Utilizza il progetto producer per tutti i passaggi di questa sezione.

Configurare l'autenticazione nella configurazione dell'API gRPC

L'autenticazione per ESP è configurata nella sezione authentication del file YAML di configurazione dell'API gRPC. La configurazione con l'autenticazione per questo servizio di esempio si trova in api_config_auth.yaml.

authentication:
  providers:
  - id: google_service_account
    # Replace SERVICE-ACCOUNT-ID with your service account's email address.
    issuer: SERVICE-ACCOUNT-ID
    jwks_uri: https://www.googleapis.com/robot/v1/metadata/x509/SERVICE-ACCOUNT-ID
  rules:
  # This auth rule will apply to all methods.
  - selector: "*"
    requirements:
      - provider_id: google_service_account

La sezione providers specifica i provider di autenticazione che vuoi utilizzare. In questo caso, vuoi utilizzare un account di servizio Google come provider di autenticazione. La sezione rules specifica che hai bisogno di token di questo provider per accedere a tutti i metodi del tuo servizio.

Nella tua copia di questo file dal repository clonato:

  • Modifica MY_PROJECT_ID con l'ID del tuo progetto produttore.
  • Modifica SERVICE-ACCOUNT-ID nella sezione authentication (sia nei valori issuer che jwks_uri) con l'ID account di servizio consumer che hai annotato nella sezione precedente. In questo modo ESP sa che vuoi concedere l'accesso al tuo servizio agli utenti che forniscono token validi da questoaccount di serviziont specifico.
  • Se vuoi, aggiungi jwt_locations sotto l'elemento providers. Puoi utilizzare questo valore per definire una posizione JWT personalizzata. Le posizioni predefinite del JWT sono i metadati Authorization (con il prefisso "Bearer ") e i metadati X-Goog-Iap-Jwt-Assertion.

Salva il file per il passaggio successivo.

Esegui il deployment della configurazione e del servizio

Questi passaggi sono gli stessi descritti in Introduzione a gRPC su GKE:

  1. Esegui il deployment della configurazione del servizio in Endpoints: devi farlo anche se l'hai già fatto per il tutorial, perché si tratta di una configurazione diversa. Prendi nota del nome del servizio restituito:

    gcloud endpoints services deploy api_descriptor.pb api_config_auth.yaml --project PRODUCER_PROJECT
    
  2. Crea un cluster di container e autenticati kubectl al cluster, se non l'hai ancora fatto.

  3. Esegui il deployment dell'API di esempio e di ESP nel cluster. Se utilizzi progetti di produttori e consumer separati, assicurati innanzitutto di aver impostato il progetto appropriato nello strumento a riga di comando gcloud:

    gcloud config set project PRODUCER_PROJECT
    

Chiamata di metodi autenticati da un client gRPC

Infine, sul lato client, puoi utilizzare la chiave del account di servizio per generare un token JWT e poi utilizzarlo per chiamare un metodo autenticato di Bookstore. Innanzitutto, installa i requisiti Python appropriati per generare il token ed eseguire il client di esempio. Assicurati di trovarti nella cartella python-docs-samples/endpoints/bookstore-grpc del client clonato, poi:

virtualenv bookstore-env
source bookstore-env/bin/activate
pip install -r requirements.txt

Generare un token JWT

In questo esempio, la libreria utilizza l'autenticazione da servizio a servizio in cui il servizio chiamante viene autenticato esclusivamente dal suoaccount di serviziot, quindi creare un token appropriato da inviare con le nostre richieste è semplice. Tieni presente che puoi anche richiedere un'autenticazione da servizio a servizio più rigorosa, in cui il token generato deve essere ulteriormente autenticato da Google (utilizzando un token ID Google).

Per questo esempio, lo script Python fornito può generare un token dal file di chiave JSON scaricato in precedenza, utilizzando un ID utente e un indirizzo email fittizi.

#!/usr/bin/env python

# Copyright 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Example of generating a JWT signed from a service account file."""

import argparse
import json
import time

import google.auth.crypt
import google.auth.jwt

"""Max lifetime of the token (one hour, in seconds)."""
MAX_TOKEN_LIFETIME_SECS = 3600


def generate_jwt(service_account_file, issuer, audiences):
    """Generates a signed JSON Web Token using a Google API Service Account."""
    with open(service_account_file) as fh:
        service_account_info = json.load(fh)

    signer = google.auth.crypt.RSASigner.from_string(
        service_account_info["private_key"], service_account_info["private_key_id"]
    )

    now = int(time.time())

    payload = {
        "iat": now,
        "exp": now + MAX_TOKEN_LIFETIME_SECS,
        # aud must match 'audience' in the security configuration in your
        # swagger spec. It can be any string.
        "aud": audiences,
        # iss must match 'issuer' in the security configuration in your
        # swagger spec. It can be any string.
        "iss": issuer,
        # sub and email are mapped to the user id and email respectively.
        "sub": issuer,
        "email": "user@example.com",
    }

    signed_jwt = google.auth.jwt.encode(signer, payload)
    return signed_jwt


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
    )
    parser.add_argument("--file", help="The path to your service account json file.")
    parser.add_argument("--issuer", default="", help="issuer")
    parser.add_argument("--audiences", default="", help="audiences")

    args = parser.parse_args()

    signed_jwt = generate_jwt(args.file, args.issuer, args.audiences)
    print(signed_jwt.decode("utf-8"))

Per generare un token utilizzando lo script:

  • Genera un token JWT e assegnalo alla variabile $JWT_TOKEN:

    JWT_TOKEN=$(python jwt_token_gen.py \
        --file=[SERVICE_ACCOUNT_FILE] \
        --audiences=[SERVICE_NAME] \
        --issuer=[SERVICE-ACCOUNT-ID])
    

    dove:

    • [SERVICE_ACCOUNT_FILE] è il file JSON della chiave dell'account di servizio consumer scaricato.
    • [SERVICE_NAME] è il nome del servizio Bookstore restituito quando hai eseguito il deployment dellaconfigurazione del servizioo aggiornata in Endpoints.
    • [SERVICE-ACCOUNT-ID] è l'ID completo dell'account di servizio consumer quando hai generato il service account.

Effettuare una chiamata gRPC autenticata

Questo ultimo passaggio utilizza bookstore_client.py, lo stesso client utilizzato nei tutorial. Per effettuare una chiamata autenticata, il client passa il JWT come metadati con la chiamata al metodo.

def run(
    host, port, api_key, auth_token, timeout, use_tls, servername_override, ca_path

Per eseguire l'esempio:

  1. Utilizza kubectl get services per ottenere l'indirizzo IP esterno per Bookstore di cui è stato eseguito il deployment:

    #kubectl get services
    NAME                 CLUSTER-IP      EXTERNAL-IP      PORT(S)           AGE
    echo                 10.11.246.240   104.196.186.92   80/TCP            10d
    endpoints            10.11.243.168   104.196.210.50   80/TCP,8090/TCP   10d
    esp-grpc-bookstore   10.11.254.34    104.196.60.37    80/TCP            1d
    kubernetes           10.11.240.1     <none>           443/TCP           10d
    

    In questo caso, si tratta del servizio esp-grpc-bookstore e il suo IP esterno è 104.196.60.37.

  2. Assegna l'indirizzo IP alla variabile EXTERNAL_IP

    EXTERNAL_IP=104.196.60.37
    
  3. Elenca tutti gli scaffali del servizio Libreria:

    python bookstore_client.py --port=80 --host=$EXTERNAL_IP --auth_token=$JWT_TOKEN
    

    Il servizio restituisce tutti gli scaffali della libreria attuale. Puoi verificarlo non fornendo un token o specificando l'IDaccount di serviziot errato quando generi il JWT. Il comando dovrebbe non riuscire.

Passaggi successivi