Autenticar usuarios con Go

Las aplicaciones que se ejecutan en Google Cloud plataformas gestionadas, como App Engine, pueden evitar la gestión de la autenticación de usuarios y la gestión de sesiones mediante Identity-Aware Proxy (IAP) para controlar el acceso a ellas. IAP no solo puede controlar el acceso a la aplicación, sino que también proporciona información sobre los usuarios autenticados, como la dirección de correo electrónico y un identificador persistente para la aplicación en forma de nuevos encabezados HTTP.

Objetivos

  • Requerir que los usuarios de tu aplicación de App Engine se autentiquen mediante IAP.

  • Accede a las identidades de los usuarios en la aplicación para mostrar la dirección de correo autenticada del usuario actual.

Costes

En este documento, se utilizan los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costes basada en el uso previsto, utiliza la calculadora de precios.

Los usuarios nuevos Google Cloud pueden disfrutar de una prueba gratuita.

Cuando termines las tareas que se describen en este documento, puedes evitar que se te siga facturando eliminando los recursos que has creado. Para obtener más información, consulta la sección Limpiar.

Antes de empezar

  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.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Install the Google Cloud CLI.

  4. Si utilizas un proveedor de identidades (IdP) externo, primero debes iniciar sesión en la CLI de gcloud con tu identidad federada.

  5. Para inicializar gcloud CLI, ejecuta el siguiente comando:

    gcloud init
  6. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  7. Install the Google Cloud CLI.

  8. Si utilizas un proveedor de identidades (IdP) externo, primero debes iniciar sesión en la CLI de gcloud con tu identidad federada.

  9. Para inicializar gcloud CLI, ejecuta el siguiente comando:

    gcloud init
  10. Prepara tu entorno de desarrollo.
  11. Configurar el proyecto

    1. En la ventana de terminal, clona el repositorio de la aplicación de muestra en tu máquina local:

      git clone https://github.com/GoogleCloudPlatform/golang-samples.git
    2. Accede al directorio que contiene el código de muestra:

      cd golang-samples/getting-started/authenticating-users

    Fondo

    En este tutorial se usa IAP para autenticar a los usuarios. Este es solo uno de los varios enfoques posibles. Para obtener más información sobre los distintos métodos para autenticar usuarios, consulta la sección Conceptos de autenticación.

    La aplicación Hello user-email-address

    La aplicación de este tutorial es una aplicación Hello World mínima de App Engine con una característica atípica: en lugar de "Hello world", muestra "Hello user-email-address", donde user-email-address es la dirección de correo del usuario autenticado.

    Esta función es posible examinando la información autenticada que la compra en la aplicación añade a cada solicitud web que pasa por tu aplicación. Se añaden tres nuevos encabezados de solicitud a cada solicitud web que llega a tu aplicación. Los dos primeros encabezados son cadenas de texto sin formato que puedes usar para identificar al usuario. La tercera cabecera es un objeto firmado criptográficamente con la misma información.

    • X-Goog-Authenticated-User-Email: la dirección de correo de un usuario lo identifica. No almacenes información personal si tu aplicación puede evitarlo. Esta aplicación no almacena ningún dato, solo lo devuelve al usuario.

    • X-Goog-Authenticated-User-Id: este ID de usuario asignado por Google no muestra información sobre el usuario, pero permite que una aplicación sepa que el usuario que ha iniciado sesión es el mismo que se ha visto anteriormente.

    • X-Goog-Iap-Jwt-Assertion: puedes configurar Google Cloud aplicaciones para que acepten solicitudes web de otras aplicaciones en la nube, sin necesidad de usar compras en aplicaciones, además de solicitudes web de Internet. Si una aplicación está configurada de esta forma, es posible que estas solicitudes tengan encabezados falsificados. En lugar de usar cualquiera de los encabezados de texto sin formato mencionados anteriormente, puedes usar y verificar este encabezado firmado criptográficamente para comprobar que la información la ha proporcionado Google. Tanto la dirección de correo del usuario como un ID de usuario persistente están disponibles como parte de este encabezado firmado.

    Si tienes la certeza de que la aplicación está configurada de forma que solo se puedan enviar solicitudes web de Internet y de que nadie puede inhabilitar el servicio de compras en la aplicación, solo necesitas una línea de código para obtener un ID de usuario único:

    userID := r.Header.Get("X-Goog-Authenticated-User-ID")

    Sin embargo, una aplicación resistente debe prever que las cosas salgan mal, incluidos los problemas inesperados de configuración o del entorno, por lo que te recomendamos que crees una función que use y verifique el encabezado firmado criptográficamente. La firma de ese encabezado no se puede falsificar y, cuando se verifica, se puede usar para devolver la identificación.

    Información sobre el código

    En esta sección se explica cómo funciona el código. Si quieres ejecutar la aplicación, puedes ir a la sección Implementar la aplicación.

    • El archivo go.mod define un módulo de Go y los módulos de los que depende.

      module github.com/GoogleCloudPlatform/golang-samples/getting-started/authenticating-users
      
      go 1.24.0
      
      require (
      	cloud.google.com/go/compute/metadata v0.6.0
      	github.com/golang-jwt/jwt v3.2.2+incompatible
      )
      
      require golang.org/x/sys v0.29.0 // indirect
      
    • El archivo app.yaml indica a App Engine qué entorno de lenguaje requiere tu código.

      runtime: go112
    • La aplicación empieza importando paquetes y definiendo una función main. La función main registra un controlador de índice e inicia un servidor HTTP.

      
      // The authenticating-users program is a sample web server application that
      // extracts and verifies user identity data passed to it via Identity-Aware
      // Proxy.
      package main
      
      import (
      	"encoding/json"
      	"fmt"
      	"log"
      	"net/http"
      	"os"
      	"time"
      
      	"cloud.google.com/go/compute/metadata"
      	"github.com/golang-jwt/jwt"
      )
      
      // app holds the Cloud IAP certificates and audience field for this app, which
      // are needed to verify authentication headers set by Cloud IAP.
      type app struct {
      	certs map[string]string
      	aud   string
      }
      
      func main() {
      	a, err := newApp()
      	if err != nil {
      		log.Fatal(err)
      	}
      
      	http.HandleFunc("/", a.index)
      
      	port := os.Getenv("PORT")
      	if port == "" {
      		port = "8080"
      		log.Printf("Defaulting to port %s", port)
      	}
      
      	log.Printf("Listening on port %s", port)
      	if err := http.ListenAndServe(":"+port, nil); err != nil {
      		log.Fatal(err)
      	}
      }
      
      // newApp creates a new app, returning an error if either the Cloud IAP
      // certificates or the app's audience field cannot be obtained.
      func newApp() (*app, error) {
      	certs, err := certificates()
      	if err != nil {
      		return nil, err
      	}
      
      	aud, err := audience()
      	if err != nil {
      		return nil, err
      	}
      
      	a := &app{
      		certs: certs,
      		aud:   aud,
      	}
      	return a, nil
      }
      
    • La función index obtiene el valor del encabezado de la aserción JWT que IAP ha añadido a la solicitud entrante y llama a la función validateAssertion para validar el valor firmado criptográficamente. La dirección de correo se usa en una respuesta web mínima.

      
      // index responds to requests with our greeting.
      func (a *app) index(w http.ResponseWriter, r *http.Request) {
      	if r.URL.Path != "/" {
      		http.NotFound(w, r)
      		return
      	}
      
      	assertion := r.Header.Get("X-Goog-IAP-JWT-Assertion")
      	if assertion == "" {
      		fmt.Fprintln(w, "No Cloud IAP header found.")
      		return
      	}
      	email, _, err := validateAssertion(assertion, a.certs, a.aud)
      	if err != nil {
      		log.Println(err)
      		fmt.Fprintln(w, "Could not validate assertion. Check app logs.")
      		return
      	}
      
      	fmt.Fprintf(w, "Hello %s\n", email)
      }
      
    • La función validateAssertion valida que la aserción se haya firmado correctamente y devuelve la dirección de correo y el ID de usuario asociados.

      Para validar una aserción JWT, es necesario conocer los certificados de clave pública de la entidad que firmó la aserción (Google en este caso) y la audiencia a la que va dirigida la aserción. En el caso de una aplicación de App Engine, la audiencia es una cadena con Google Cloud información de identificación del proyecto. La función validateAssertion obtiene esos certificados de la función certs y la cadena de audiencia de la función audience.

      
      // validateAssertion validates assertion was signed by Google and returns the
      // associated email and userID.
      func validateAssertion(assertion string, certs map[string]string, aud string) (email string, userID string, err error) {
      	token, err := jwt.Parse(assertion, func(token *jwt.Token) (interface{}, error) {
      		keyID := token.Header["kid"].(string)
      
      		_, ok := token.Method.(*jwt.SigningMethodECDSA)
      		if !ok {
      			return nil, fmt.Errorf("unexpected signing method: %q", token.Header["alg"])
      		}
      
      		cert := certs[keyID]
      		return jwt.ParseECPublicKeyFromPEM([]byte(cert))
      	})
      
      	if err != nil {
      		return "", "", err
      	}
      
      	claims, ok := token.Claims.(jwt.MapClaims)
      	if !ok {
      		return "", "", fmt.Errorf("could not extract claims (%T): %+v", token.Claims, token.Claims)
      	}
      
      	if claims["aud"].(string) != aud {
      		return "", "", fmt.Errorf("mismatched audience. aud field %q does not match %q", claims["aud"], aud)
      	}
      	return claims["email"].(string), claims["sub"].(string), nil
      }
      
    • Puedes buscar el ID numérico y el nombre del proyecto e incluirlos en el código fuente, pero la función audience lo hace por ti consultando el servicio de metadatos estándar que está disponible para todas las aplicaciones de App Engine. Como el servicio de metadatos es externo al código de la aplicación, el resultado se guarda en una variable global que se devuelve sin tener que buscar los metadatos en las llamadas posteriores. Google Cloud

      El servicio de metadatos de App Engine (y otros servicios de metadatos similares para otros servicios de computación Google Cloud ) tiene el aspecto de un sitio web y se consulta mediante consultas web estándar. Sin embargo, el servicio de metadatos no es un sitio externo, sino una función interna que devuelve la información solicitada sobre la aplicación en ejecución, por lo que es seguro usar http en lugar de solicitudes https. El servicio de metadatos se usa para obtener los identificadores actuales Google Cloud necesarios para definir la audiencia prevista de la aserción JWT.

      
      // audience returns the expected audience value for this service.
      func audience() (string, error) {
      	projectNumber, err := metadata.NumericProjectID()
      	if err != nil {
      		return "", fmt.Errorf("metadata.NumericProjectID: %w", err)
      	}
      
      	projectID, err := metadata.ProjectID()
      	if err != nil {
      		return "", fmt.Errorf("metadata.ProjectID: %w", err)
      	}
      
      	return "/projects/" + projectNumber + "/apps/" + projectID, nil
      }
      
    • Para verificar una firma digital, se necesita el certificado de clave pública del firmante. Google proporciona un sitio web que devuelve todos los certificados de clave pública que se utilizan actualmente. Estos resultados se almacenan en caché por si se necesitan de nuevo en la misma instancia de la aplicación.

      
      // certificates returns Cloud IAP's cryptographic public keys.
      func certificates() (map[string]string, error) {
      	const url = "https://www.gstatic.com/iap/verify/public_key"
      	client := http.Client{
      		Timeout: 5 * time.Second,
      	}
      	resp, err := client.Get(url)
      	if err != nil {
      		return nil, fmt.Errorf("Get: %w", err)
      	}
      
      	var certs map[string]string
      	dec := json.NewDecoder(resp.Body)
      	if err := dec.Decode(&certs); err != nil {
      		return nil, fmt.Errorf("Decode: %w", err)
      	}
      
      	return certs, nil
      }
      

    Desplegar la aplicación

    Ahora puedes implementar la aplicación y, a continuación, habilitar las compras en la aplicación para que los usuarios tengan que autenticarse antes de poder acceder a ella.

    1. En la ventana de terminal, ve al directorio que contiene el archivo app.yaml y despliega la aplicación en App Engine:

      gcloud app deploy
      
    2. Cuando se te solicite, selecciona una región cercana.

    3. Cuando se te pregunte si quieres continuar con la operación de implementación, escribe Y.

      En unos minutos, tu aplicación estará disponible en Internet.

    4. Ver la aplicación:

      gcloud app browse
      

      En el resultado, copia web-site-url, la dirección web de la aplicación.

    5. En una ventana del navegador, pega web-site-url para abrir la aplicación.

      No se muestra ningún correo porque aún no estás usando las compras en la aplicación, por lo que no se envía ninguna información del usuario a la aplicación.

    Habilitar IAP

    Ahora que existe una instancia de App Engine, puedes protegerla con IAP:

    1. En la Google Cloud consola, ve a la página Identity-Aware Proxy.

      Ir a la página Identity-Aware Proxy

    2. Como es la primera vez que habilitas una opción de autenticación para este proyecto, verás un mensaje que indica que debes configurar la pantalla de consentimiento de OAuth antes de poder usar IAP.

      Haz clic en Configurar pantalla de consentimiento.

    3. En la pestaña Pantalla de consentimiento de OAuth de la página Credenciales, rellena los siguientes campos:

      • Si tu cuenta pertenece a una organización de Google Workspace, selecciona Externa y haz clic en Crear. Para empezar, la aplicación solo estará disponible para los usuarios a los que concedas permiso explícitamente.

      • En el campo Nombre de la aplicación, introduce IAP Example.

      • En el campo Correo de asistencia, introduce tu dirección de correo.

      • En el campo Dominio autorizado, introduce la parte del nombre de host de la URL de la aplicación. Por ejemplo, iap-example-999999.uc.r.appspot.com. Pulsa la tecla Enter después de introducir el nombre de host en el campo.

      • En el campo Enlace a la página principal de la aplicación, introduce la URL de tu aplicación (por ejemplo, https://iap-example-999999.uc.r.appspot.com/).

      • En el campo Línea de la política de privacidad de la aplicación, usa la misma URL que el enlace de la página principal para hacer pruebas.

    4. Haz clic en Guardar. Cuando se te pida que crees credenciales, puedes cerrar la ventana.

    5. En la Google Cloud consola, ve a la página Identity-Aware Proxy.

      Ir a la página Identity-Aware Proxy

    6. Para actualizar la página, haz clic en Actualizar . En la página se muestra una lista de los recursos que puedes proteger.

    7. En la columna IAP, haz clic para activar las compras en la aplicación.

    8. En tu navegador, vuelve a web-site-url.

    9. En lugar de la página web, hay una pantalla de inicio de sesión para autenticarte. Cuando inicias sesión, se te deniega el acceso porque la compra en la aplicación no tiene una lista de usuarios a los que permitir el acceso a la aplicación.

    Añadir usuarios autorizados a la aplicación

    1. En la Google Cloud consola, ve a la página Identity-Aware Proxy.

      Ir a la página Identity-Aware Proxy

    2. Seleccione la casilla de la aplicación de App Engine y, a continuación, haga clic en Añadir principal.

    3. Introduce allAuthenticatedUsers y, a continuación, selecciona el rol Usuario de aplicaciones web protegidas mediante IAP/IAP de Cloud.

    4. Haz clic en Guardar.

    Ahora, cualquier usuario que Google pueda autenticar podrá acceder a la aplicación. Si quieres, puedes restringir aún más el acceso añadiendo una o varias personas o grupos como principales:

    • Cualquier dirección de correo de Gmail o Google Workspace

    • Una dirección de correo de un grupo de Google

    • Un nombre de dominio de Google Workspace

    Acceder a la aplicación

    1. En tu navegador, ve a web-site-url.

    2. Para actualizar la página, haz clic en Actualizar .

    3. En la pantalla de inicio de sesión, inicia sesión con tus credenciales de Google.

      En la página se muestra el mensaje "Hola, user-email-address" con tu dirección de correo.

      Si sigues viendo la misma página que antes, puede que el navegador no esté actualizando completamente las nuevas solicitudes ahora que has habilitado las compras en la aplicación. Cierra todas las ventanas del navegador, vuelve a abrirlas e inténtalo de nuevo.

    Conceptos de autenticación

    Hay varias formas en las que una aplicación puede autenticar a sus usuarios y restringir el acceso solo a los usuarios autorizados. En las siguientes secciones se enumeran los métodos de autenticación habituales, ordenados de menor a mayor esfuerzo para la aplicación.

    Opción Ventajas Desventajas
    Autenticación de aplicaciones
    • La aplicación puede ejecutarse en cualquier plataforma, con o sin conexión a Internet
    • Los usuarios no tienen que usar ningún otro servicio para gestionar la autenticación
    • La aplicación debe gestionar las credenciales de los usuarios de forma segura y protegerlas para que no se divulguen.
    • La aplicación debe mantener los datos de sesión de los usuarios que hayan iniciado sesión
    • La aplicación debe permitir que los usuarios se registren, cambien la contraseña y la recuperen
    OAuth2
    • La aplicación puede ejecutarse en cualquier plataforma con conexión a Internet, incluida una estación de trabajo de desarrollador
    • La aplicación no necesita funciones de registro de usuarios, cambio de contraseña ni recuperación de contraseña.
    • El riesgo de divulgación de la información del usuario se delega en otro servicio
    • Nuevas medidas de seguridad de inicio de sesión gestionadas fuera de la aplicación
    • Los usuarios deben registrarse en el servicio de gestión de identidades
    • La aplicación debe mantener los datos de sesión de los usuarios que hayan iniciado sesión
    IAP
    • La aplicación no necesita tener ningún código para gestionar usuarios, autenticación o estado de la sesión
    • La aplicación no tiene credenciales de usuario que puedan verse comprometidas
    • La aplicación solo puede ejecutarse en plataformas compatibles con el servicio. En concreto, determinados Google Cloud servicios que admiten compras en aplicaciones, como App Engine.

    Autenticación gestionada por la aplicación

    Con este método, la aplicación gestiona por sí sola todos los aspectos de la autenticación de usuarios. La aplicación debe mantener su propia base de datos de credenciales de usuario y gestionar las sesiones de usuario. Además, debe proporcionar funciones para gestionar las cuentas y contraseñas de usuario, comprobar las credenciales de usuario y emitir, comprobar y actualizar las sesiones de usuario con cada inicio de sesión autenticado. En el siguiente diagrama se ilustra el método de autenticación gestionado por la aplicación.

    Flujo gestionado por la aplicación

    Como se muestra en el diagrama, después de que el usuario inicie sesión, la aplicación crea y mantiene información sobre la sesión del usuario. Cuando el usuario hace una solicitud a la aplicación, esta debe incluir información de sesión que la aplicación debe verificar.

    La principal ventaja de este enfoque es que es autónomo y está bajo el control de la aplicación. La aplicación ni siquiera tiene que estar disponible en Internet. La principal desventaja es que ahora la aplicación es responsable de proporcionar todas las funciones de gestión de cuentas y de proteger todos los datos de credenciales sensibles.

    Autenticación externa con OAuth2

    Una buena alternativa a gestionar todo en la aplicación es usar un servicio de identidad externo, como Google, que gestione toda la información y las funciones de las cuentas de usuario y que sea responsable de proteger las credenciales sensibles. Cuando un usuario intenta iniciar sesión en la aplicación, la solicitud se redirige al servicio de identidad, que autentica al usuario y, a continuación, redirige la solicitud a la aplicación con la información de autenticación necesaria. Para obtener más información, consulta el artículo sobre cómo se usa OAuth 2.0 en las aplicaciones de servidor web.

    En el siguiente diagrama se muestra la autenticación externa con el método OAuth2.

    Flujo de OAuth2

    El flujo del diagrama empieza cuando el usuario envía una solicitud para acceder a la aplicación. En lugar de responder directamente, la aplicación redirige el navegador del usuario a la plataforma de identidad de Google, que muestra una página para iniciar sesión en Google. Después de iniciar sesión correctamente, el navegador del usuario se redirige a la aplicación. Esta solicitud incluye información que la aplicación puede usar para buscar información sobre el usuario autenticado. La aplicación responde al usuario.

    Este método ofrece muchas ventajas para la aplicación, ya que delega todas las funciones y los riesgos de gestión de cuentas en el servicio externo, lo que puede mejorar la seguridad de inicio de sesión y de la cuenta sin que la aplicación tenga que cambiar. Sin embargo, como se muestra en el diagrama anterior, la aplicación debe tener acceso a Internet para usar este método. La aplicación también es responsable de gestionar las sesiones después de que el usuario se haya autenticado.

    Identity-Aware Proxy

    El tercer método, que se explica en este tutorial, consiste en usar IAP para gestionar toda la autenticación y la gestión de sesiones con cualquier cambio en la aplicación. IAP intercepta todas las solicitudes web a tu aplicación, bloquea las que no se hayan autenticado y reenvía las demás con los datos de identidad del usuario añadidos a cada solicitud.

    El proceso de gestión de solicitudes se muestra en el siguiente diagrama.

    Flujo de IAP

    IAP intercepta las solicitudes de los usuarios, lo que bloquea las solicitudes no autenticadas. Las solicitudes autenticadas se reenvían a la aplicación, siempre que el usuario autenticado esté en la lista de usuarios permitidos. Las solicitudes que pasan por IAP tienen encabezados añadidos que identifican al usuario que ha hecho la solicitud.

    La aplicación ya no necesita gestionar ninguna cuenta de usuario ni información de sesión. Cualquier operación que necesite conocer un identificador único del usuario puede obtenerlo directamente de cada solicitud web entrante. Sin embargo, solo se puede usar para servicios de computación que admitan IAP, como App Engine y balanceadores de carga. No puedes usar IAP en un equipo de desarrollo local.

    Limpieza

    Para evitar que los recursos utilizados en este tutorial se cobren en tu cuenta de Google Cloud, elimina el proyecto que contiene los recursos o conserva el proyecto y elimina los recursos.

    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.