Autenticazione degli utenti con Identity-Aware Proxy per Ruby

Le app in esecuzione su piattaforme gestite da Google Cloud, come App Engine, possono evitare di gestire l'autenticazione degli utenti e la gestione delle sessioni utilizzando Identity-Aware Proxy (IAP) per controllare l'accesso. IAP non solo può controllare l'accesso all'app, ma fornisce anche informazioni sugli utenti autenticati, tra cui l'indirizzo email e un identificatore persistente dell'app sotto forma di nuove intestazioni HTTP.

Obiettivi

  • Richiedi agli utenti della tua app App Engine di autenticarsi utilizzando IAP.

  • Accedere alle identità degli utenti nell'app per visualizzare l'indirizzo email autenticato degli utenti correnti.

Costi

In questo documento utilizzi i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi basata sull'utilizzo previsto, utilizza il Calcolatore prezzi. I nuovi utenti di Google Cloud potrebbero essere idonei per una prova gratuita.

Al termine delle attività descritte in questo documento, puoi evitare la fatturazione continua eliminando le risorse che hai creato. Per ulteriori informazioni, consulta la sezione Pulizia.

Prima di iniziare

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  5. Make sure that billing is enabled for your Google Cloud project.

  6. Prepara l'ambiente di sviluppo.

Premesse

Questo tutorial utilizza IAP per autenticare gli utenti. Questo è solo uno dei diversi approcci possibili. Per scoprire di più sui vari metodi per autenticare gli utenti, consulta la sezione Concetti di autenticazione.

L'app Hello user-email-address

L'app per questo tutorial è una versione minima dell'app App Engine di Hello World, con una caratteristica non tipica: anziché"Hello World", mostra"Hello user-email-address", dove user-email-address è l'indirizzo email autenticato dell'utente.

Questa funzionalità è possibile esaminando le informazioni autenticate che IAP aggiunge a ogni richiesta web inviata all'app. Sono state aggiunte tre nuove intestazioni di richiesta a ogni richiesta web che raggiunge la tua app. Le prime due intestazioni sono stringhe di testo semplici che puoi utilizzare per identificare l'utente. La terza intestazione è un oggetto firmato tramite crittografia con le stesse informazioni.

  • X-Goog-Authenticated-User-Email: l'indirizzo email di un utente lo identifica. Non memorizzare informazioni personali se la tua app può evitarle. Questa app non memorizza alcun dato, ma ne fa eco all'utente.

  • X-Goog-Authenticated-User-Id: questo ID utente assegnato da Google non mostra le informazioni relative all'utente, ma consente a un'app di sapere che un utente che ha eseguito l'accesso è lo stesso che è stato visualizzato in precedenza.

  • X-Goog-Iap-Jwt-Assertion: puoi configurare le app Google Cloud in modo che accetti richieste web da altre app cloud, ignorando IAP e le richieste web Internet. Se un'app è così configurata, è possibile che tali richieste abbiano intestazioni contraffatte. Anziché utilizzare le intestazioni di testo normale indicate in precedenza, puoi utilizzare e verificare questa intestazione firmata tramite crittografia per verificare che le informazioni siano state fornite da Google. Sia l'indirizzo email dell'utente sia uno User-ID permanente sono disponibili come parte di questa intestazione firmata.

Se hai la certezza che l'app sia configurata in modo tale che solo le richieste web Internet possano raggiungerla e che nessuno possa disattivare il servizio IAP per l'app, il recupero di uno User-ID univoco richiede una sola riga di codice:

user_id = request.env["HTTP_X_GOOG_AUTHENTICATED_USER_ID"]

Tuttavia, un'app resiliente dovrebbe aspettarsi qualcosa che non va, inclusi problemi di configurazione o ambientali imprevisti, quindi consigliamo di creare una funzione che utilizzi e verifichi l'intestazione firmata tramite crittografia. La firma dell'intestazione non può essere falsificata e, una volta verificata, può essere utilizzata per restituire l'identificazione.

Crea il codice sorgente

  1. Utilizza un editor di testo per creare un file denominato app.rb, e incolla il seguente codice al suo interno:

    require "base64"
    require "json"
    require "jwt"
    require "net/http"
    require "openssl"
    require "sinatra"
    require "uri"
    
    def certificates
      uri = URI.parse "https://www.gstatic.com/iap/verify/public_key"
      response = Net::HTTP.get_response uri
      JSON.parse response.body
    end
    
    set :certificates, certificates
    
    def get_metadata item_name
      endpoint = "http://metadata.google.internal"
      path = "/computeMetadata/v1/project/#{item_name}"
      uri = URI.parse endpoint + path
    
      http = Net::HTTP.new uri.host, uri.port
      request = Net::HTTP::Get.new uri.request_uri
      request["Metadata-Flavor"] = "Google"
      response = http.request request
      response.body
    end
    
    def audience
      project_number = get_metadata "numeric-project-id"
      project_id = get_metadata "project-id"
      "/projects/#{project_number}/apps/#{project_id}"
    end
    
    set :audience, audience
    
    def validate_assertion assertion
      a_header = Base64.decode64 assertion.split(".")[0]
      key_id = JSON.parse(a_header)["kid"]
      cert = OpenSSL::PKey::EC.new settings.certificates[key_id]
      info = JWT.decode assertion, cert, true, algorithm: "ES256", aud: settings.audience
      [info[0]["email"], info[0]["sub"]]
    rescue StandardError => e
      puts "Failed to validate assertion: #{e}"
      [nil, nil]
    end
    
    get "/" do
      assertion = request.env["HTTP_X_GOOG_IAP_JWT_ASSERTION"]
      email, _user_id = validate_assertion assertion
      "<h1>Hello #{email}</h1>"
    end

    Questo file app.rb viene spiegato in dettaglio nella sezione Comprendere il codice più avanti in questo tutorial.

  2. Nella finestra del terminale, vai alla stessa cartella in cui hai appena creato app.rb ed esegui bundle init.

  3. Aggiungi quanto segue al Gemfile risultante:

    gem "jwt", "~> 2.2"
    gem "sinatra", "~> 2.0"

    Gemfile elenca tutte le librerie Ruby non standard che l'app deve caricare per App Engine:

    • Sinatra è il framework web rubino utilizzato per l'app.

    • jwt fornisce il metodo di controllo e decodifica JWT.

  4. Installa le dipendenze elencate nel Gemfile:

    bundle install
    
  5. Crea un file denominato app.yaml e incolla il seguente testo al suo interno:

    runtime: ruby25
    entrypoint: bundle exec ruby app.rb

    Il file app.yaml indica ad App Engine l'ambiente relativo alla lingua richiesto dal codice.

Nozioni di base sul codice

Questa sezione spiega come funziona il codice nel file app.rb. Se vuoi solo eseguire l'app, puoi passare direttamente alla sezione Esegui il deployment dell'app.

  • Quando l'app riceve una richiesta HTTP GET per la home page, Sinatra esegue il seguente blocco:

    get "/" do
      assertion = request.env["HTTP_X_GOOG_IAP_JWT_ASSERTION"]
      email, _user_id = validate_assertion assertion
      "<h1>Hello #{email}</h1>"
    end
  • Il blocco riceve il valore di intestazione dell'asserzione JWT che IAP ha aggiunto dalla richiesta in entrata e chiama un metodo per convalidare quel valore firmato crittografico. Il primo valore restituito (email) viene quindi utilizzato in una pagina web minima creata da Sinatra.

    def validate_assertion assertion
      a_header = Base64.decode64 assertion.split(".")[0]
      key_id = JSON.parse(a_header)["kid"]
      cert = OpenSSL::PKey::EC.new settings.certificates[key_id]
      info = JWT.decode assertion, cert, true, algorithm: "ES256", aud: settings.audience
      [info[0]["email"], info[0]["sub"]]
    rescue StandardError => e
      puts "Failed to validate assertion: #{e}"
      [nil, nil]
    end
  • Il metodo validate_assertion utilizza il metodo JWT.decode della libreria jwt di terze parti per verificare che l'asserzione sia stata firmata correttamente e per estrarre le informazioni sul payload dall'asserzione. Tali informazioni corrispondono all'indirizzo email dell'utente autenticato e a un ID univoco permanente per l'utente. Se l'asserzione non può essere decodificata, questo metodo restituisce nil per ognuno di questi valori e stampa un messaggio per registrare l'errore.

  • Per convalidare un'asserzione JWT è necessario conoscere i certificati di chiave pubblica dell'entità che ha firmato l'asserzione (Google in questo caso) e il pubblico a cui è destinata. Per un'app App Engine, il pubblico è una stringa con informazioni di identificazione del progetto Google Cloud. Questo metodo riceve i certificati e la stringa del segmento di pubblico dai metodi precedenti.

    def audience
      project_number = get_metadata "numeric-project-id"
      project_id = get_metadata "project-id"
      "/projects/#{project_number}/apps/#{project_id}"
    end
    
    set :audience, audience
  • Puoi cercare l'ID numerico e il nome del progetto Google Cloud e inserire personalmente quei valori nel codice sorgente, ma il metodo audience lo fa eseguendo una query sul servizio di metadati standard reso disponibile in ogni app App Engine. Poiché il servizio di metadati è esterno al codice dell'app, il risultato viene salvato nell'oggetto settings del framework Sinatra.

    def get_metadata item_name
      endpoint = "http://metadata.google.internal"
      path = "/computeMetadata/v1/project/#{item_name}"
      uri = URI.parse endpoint + path
    
      http = Net::HTTP.new uri.host, uri.port
      request = Net::HTTP::Get.new uri.request_uri
      request["Metadata-Flavor"] = "Google"
      response = http.request request
      response.body
    end
  • Il servizio di metadati App Engine (e servizi di metadati simili per altri servizi di computing Google Cloud) sembra un sito web e viene interrogato da query web standard. Tuttavia, in realtà non è un sito esterno, ma una funzionalità interna che restituisce informazioni richieste sull'app in esecuzione, quindi è sicuro usare http invece delle richieste https. In questo caso, il servizio di metadati App Engine viene utilizzato per ottenere gli identificatori di Google Cloud attuali necessari per definire il pubblico di destinazione dell'asserzione JWT.

    def certificates
      uri = URI.parse "https://www.gstatic.com/iap/verify/public_key"
      response = Net::HTTP.get_response uri
      JSON.parse response.body
    end
    
    set :certificates, certificates
  • La verifica di una firma digitale richiede il certificato di chiave pubblica del firmatario. Google fornisce un sito web che restituisce tutti i certificati di chiave pubblica attualmente in uso. Questi risultati vengono memorizzati nella cache nel caso in cui siano nuovamente necessari nella stessa istanza dell'app.

Eseguire il deployment dell'app

Ora puoi eseguire il deployment dell'app e abilitare IAP per richiedere agli utenti di autenticarsi prima che possano accedere all'app.

  1. Nella finestra del terminale, vai alla directory contenente il file app.yaml ed esegui il deployment dell'app in App Engine:

    gcloud app deploy
    
  2. Quando richiesto, seleziona un'area geografica nelle vicinanze.

  3. Quando ti viene chiesto se vuoi continuare con l'operazione di deployment, inserisci Y.

    L'app viene pubblicata su Internet entro pochi minuti

  4. Visualizza l'app:

    gcloud app browse
    

    Nell'output, copia l'indirizzo web dell'app web-site-url.

  5. In una finestra del browser, incolla web-site-url per aprire l'applicazione.

    Non viene visualizzata alcuna email perché non utilizzi ancora IAP, quindi non vengono inviate informazioni utente all'app.

Abilita IAP

Ora che esiste un'istanza di App Engine, puoi proteggerla con IAP:

  1. In Google Cloud Console, vai alla pagina Identity-Aware Proxy.

    Vai alla pagina Identity-Aware Proxy

  2. Poiché è la prima volta che attivi un'opzione di autenticazione per questo progetto, viene visualizzato un messaggio che ti chiede di configurare la schermata del consenso OAuth prima di poter utilizzare IAP.

    Fai clic su Configura la schermata per il consenso.

  3. Nella scheda Schermata per il consenso OAuth della pagina Credenziali, completa i seguenti campi:

    • Se il tuo account fa parte di un'organizzazione Google Workspace, seleziona Esterno e fai clic su Crea. Per iniziare, l'app sarà disponibile soltanto agli utenti che consenti esplicitamente.

    • Nel campo Nome applicazione, inserisci IAP Example.

    • Nel campo Email dell'assistenza, inserisci il tuo indirizzo email.

    • Nel campo Dominio autorizzato, inserisci la parte del nome host dell'URL dell'app, ad esempio iap-example-999999.uc.r.appspot.com. Premi il tasto Enter dopo aver inserito il nome host nel campo.

    • Nel campo Link alla home page dell'applicazione, inserisci l'URL della tua app, ad esempio https://iap-example-999999.uc.r.appspot.com/.

    • Nel campo Riga delle norme sulla privacy dell'applicazione, utilizza lo stesso URL del link alla home page ai fini di test.

  4. Fai clic su Salva. Quando ti viene chiesto di creare le credenziali, puoi chiudere la finestra.

  5. In Google Cloud Console, vai alla pagina Identity-Aware Proxy.

    Vai alla pagina Identity-Aware Proxy

  6. Per aggiornare la pagina, fai clic su Aggiorna . Nella pagina viene visualizzato un elenco delle risorse che puoi proteggere.

  7. Nella colonna IAP, fai clic per attivare IAP per l'app.

  8. Nel browser, vai di nuovo a web-site-url.

  9. Invece della pagina web, viene visualizzata una schermata di accesso per l'autenticazione. Quando esegui l'accesso, ti viene negato l'accesso perché IAP non dispone di un elenco di utenti da consentire tramite l'app.

Aggiungere utenti autorizzati all'app

  1. In Google Cloud Console, vai alla pagina Identity-Aware Proxy.

    Vai alla pagina Identity-Aware Proxy

  2. Seleziona la casella di controllo per l'app App Engine e fai clic su Aggiungi entità.

  3. Inserisci allAuthenticatedUsers, quindi seleziona il ruolo Utente applicazione web con protezione IAP/IAP protetta.

  4. Fai clic su Salva.

Ora qualsiasi utente che Google può autenticare può accedere all'app. Se vuoi, puoi limitare l'accesso aggiungendo solo una o più persone o gruppi come entità:

  • Qualsiasi indirizzo email Gmail o Google Workspace

  • Un indirizzo email di Google Gruppi

  • Un nome di dominio di Google Workspace

Accedere all'app

  1. Nel browser, vai alla pagina web-site-url.

  2. Per aggiornare la pagina, fai clic su Aggiorna .

  3. Nella schermata di accesso, accedi con le tue credenziali Google.

    La pagina mostra una pagina"Hello user-email-address"con il tuo indirizzo email.

    Se visualizzi la stessa pagina di prima, potrebbe esserci un problema con il browser che non aggiorna completamente le nuove richieste ora che hai abilitato IAP. Chiudi tutte le finestre del browser, riaprile e riprova.

Concetti di autenticazione

Un'app può autenticare i propri utenti in diversi modi e limitare l'accesso solo agli utenti autorizzati. Nelle sezioni seguenti sono riportati i metodi di autenticazione più comuni, in modo da ridurre il livello di impegno per l'app.

Opzione Vantaggi Svantaggi
Autenticazione app
  • L'app può essere eseguita su qualsiasi piattaforma, con o senza connessione a Internet
  • Gli utenti non devono utilizzare altri servizi per gestire l'autenticazione
  • L'app deve gestire le credenziali utente in modo sicuro, proteggere dall'informativa
  • L'app deve gestire i dati delle sessioni degli utenti che hanno eseguito l'accesso
  • L'app deve fornire la registrazione utente, le modifiche alla password, il recupero della password
OAuth2
  • L'app può essere eseguita su qualsiasi piattaforma connessa a Internet, inclusa una workstation per gli sviluppatori
  • L'app non richiede la registrazione dell'utente, le modifiche alla password o le funzioni di recupero della password.
  • Il rischio di divulgazione di informazioni sugli utenti è delegato a un altro servizio.
  • Nuove misure di sicurezza dell'accesso gestite al di fuori dell'app
  • Gli utenti devono registrarsi con il servizio di identità
  • L'app deve gestire i dati delle sessioni degli utenti che hanno eseguito l'accesso
IAP
  • L'app non deve avere alcun codice per gestire gli utenti, l'autenticazione o lo stato della sessione
  • L'app non dispone di credenziali utente che potrebbero essere violate
  • L'app può essere eseguita solo su piattaforme supportate dal servizio. In particolare, alcuni servizi Google Cloud che supportano IAP, come App Engine.

Autenticazione gestita dall'app

Con questo metodo, l'app gestisce autonomamente ogni aspetto dell'autenticazione utente. L'app deve mantenere il proprio database di credenziali utente e gestire le sessioni utente e deve fornire funzioni per gestire gli account utente e le password, controllare le credenziali utente, nonché emettere, controllare e aggiornare le sessioni utente con ogni accesso autenticato. Il seguente diagramma illustra il metodo di autenticazione gestito dall'app.

Flusso gestito dall'applicazione

Come mostrato nel diagramma, dopo che l'utente ha eseguito l'accesso, l'app crea e conserva le informazioni sulla sessione dell'utente, Quando l'utente invia una richiesta all'app, la richiesta deve includere le informazioni sulla sessione che l'app è responsabile della verifica.

Il vantaggio principale di questo approccio è che è autonomo e sotto il controllo dell'app. L'app non deve nemmeno essere disponibile su Internet. Lo svantaggio principale è che l'app è ora responsabile di fornire tutte le funzionalità di gestione dell'account e di proteggere tutti i dati sensibili delle credenziali.

Autenticazione esterna con OAuth2

Una buona alternativa alla gestione di tutto ciò che riguarda l'app è l'utilizzo di un servizio di identità esterno, come Google, che gestisce tutte le informazioni e le funzionalità dell'account utente ed è responsabile della salvaguardia delle credenziali sensibili. Quando un utente tenta di accedere all'app, la richiesta viene reindirizzata al servizio di identità, che autentica l'utente, quindi reindirizza la richiesta all'app con le informazioni di autenticazione necessarie fornite. Per ulteriori informazioni, consulta la pagina relativa all'utilizzo di OAuth 2.0 per le applicazioni server web.

Il seguente diagramma illustra l'autenticazione esterna con il metodo OAuth2.

Flusso OAuth2

Il flusso nel diagramma inizia quando l'utente invia una richiesta di accesso all'app. Invece di rispondere direttamente, l'app reindirizza il browser dell'utente alla piattaforma di identità di Google, che visualizza una pagina per accedere a Google. Dopo aver eseguito correttamente l'accesso, il browser dell'utente viene reindirizzato all'app. Questa richiesta include informazioni che l'app può utilizzare per cercare informazioni sull'utente ora autenticato e l'app ora risponde all'utente.

Questo metodo presenta molti vantaggi per l'app. Delega tutte le funzionalità di gestione dell'account e i rischi al servizio esterno, che può migliorare l'accesso e la sicurezza dell'account senza che l'app debba cambiare. Tuttavia, come mostrato nel diagramma precedente, l'app deve avere accesso a Internet per usare questo metodo. L'app è inoltre responsabile della gestione delle sessioni dopo l'autenticazione dell'utente.

Identity-Aware Proxy

Il terzo approccio, che viene seguito da questo tutorial, consiste nell'utilizzare IAP per gestire tutta l'autenticazione e la gestione delle sessioni con qualsiasi modifica apportata all'app. IAP intercetta tutte le richieste web relative alla tua app, blocca tutte quelle che non sono state autenticate e le trasmette tramite i dati di identità dell'utente aggiunti a ogni richiesta.

La gestione delle richieste è mostrata nel diagramma seguente.

Flusso IAP

Le richieste degli utenti vengono intercettate da IAP, che blocca le richieste non autenticate. Le richieste autenticate vengono trasmesse all'app, purché l'utente autenticato sia nell'elenco degli utenti consentiti. Alle richieste trasmesse tramite IAP vengono aggiunte intestazioni che identificano l'utente che ha effettuato la richiesta.

L'app non deve più gestire le informazioni relative all'account utente o alla sessione. Qualsiasi operazione che abbia bisogno di conoscere un identificatore univoco per l'utente può recuperarlo direttamente da ogni richiesta web in arrivo. Tuttavia, può essere utilizzato solo per i servizi di computing che supportano IAP, come App Engine e i bilanciatori del carico. Non puoi utilizzare IAP su una macchina di sviluppo locale.

Esegui la pulizia

Per evitare che al tuo Account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, elimina il progetto che contiene le risorse oppure mantieni il progetto ed elimina le singole risorse.

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.