Instructivo de autenticación de usuarios finales para Cloud Run

En este instructivo, se muestra cómo crear un servicio de votación, que consiste en lo siguiente:

  • Un cliente basado en el navegador que realiza las siguientes acciones:

    1. Usa Identity Platform para recuperar un token de ID.
    2. Permite a los usuarios votar por su animales nacionales favoritos.
    3. Agrega ese token de ID a una solicitud al servidor de Cloud Run que procesa el voto.
  • Un servidor de Cloud Run que realiza las siguientes acciones:

    1. Verifica que el usuario final se haya autenticado de forma correcta mediante un token de ID válido.
    2. Procesa el voto del usuario final.
    3. Con sus propias credenciales, se envía el voto a Cloud SQL para el almacenamiento.
  • Una base de datos PostgresSQL que almacena los votos.

Para que sea más simple, en este instructivo se usa Google como proveedor: los usuarios deben autenticarse con una Cuenta de Google a fin de adquirir su token de ID. Sin embargo, puedes usar otros proveedores o métodos de autenticación para que los usuarios accedan.

Este servicio minimiza los riesgos de seguridad con Secret Manager a fin de proteger los datos sensibles que se usan para conectarse a la instancia de Cloud SQL. También usa una identidad de servicio con privilegios mínimos para proteger el acceso a la base de datos.

Objetivos

Escribir, compilar e implementar un servicio en Cloud Run que muestre cómo realizar lo siguiente:

  • Usa Identity Platform para autenticar un usuario final en el backend del servicio de Cloud Run.

  • Crea una identidad con privilegios mínimos para que el servicio otorgue acceso mínimo a los recursos de Google Cloud.

  • Usa Secret Manager para manejar datos sensibles cuando conectas el servicio de Cloud Run a una base de datos PostgreSQL.

Costos

En este instructivo, se usan los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios. Es posible que los usuarios nuevos de Google Cloud califiquen para obtener una prueba gratuita.

Antes de comenzar

  1. Accede a tu cuenta de Google Cloud. Si eres nuevo en Google Cloud, crea una cuenta para evaluar el rendimiento de nuestros productos en situaciones reales. Los clientes nuevos también obtienen $300 en créditos gratuitos para ejecutar, probar y, además, implementar cargas de trabajo.
  2. En la página del selector de proyectos de Google Cloud Console, selecciona o crea un proyecto de Google Cloud.

    Ir al selector de proyectos

  3. Asegúrate de que la facturación esté habilitada para tu proyecto de Cloud. Obtén información sobre cómo verificar si la facturación está habilitada en un proyecto.

  4. En la página del selector de proyectos de Google Cloud Console, selecciona o crea un proyecto de Google Cloud.

    Ir al selector de proyectos

  5. Asegúrate de que la facturación esté habilitada para tu proyecto de Cloud. Obtén información sobre cómo verificar si la facturación está habilitada en un proyecto.

  6. Habilita las API de Cloud Run, Secret Manager, Cloud SQL, Container Registry, and Cloud Build .

    Habilita las API

Configura los valores predeterminados de gcloud

A fin de configurar gcloud con los valores predeterminados para el servicio de Cloud Run, sigue estos pasos:

  1. Configura el proyecto predeterminado:

    gcloud config set project PROJECT_ID

    Reemplaza PROJECT_ID por el nombre del proyecto que creaste para este instructivo.

  2. Configura gcloud en la región que elegiste:

    gcloud config set run/region REGION

    Reemplaza REGION por la región de Cloud Run compatible que prefieras.

Ubicaciones de Cloud Run

Cloud Run es regional, lo que significa que la infraestructura que ejecuta los servicios se ubica en una región específica, y Google la administra para que esté disponible de manera redundante en todas las zonas de esa región.

El cumplimiento de los requisitos de latencia, disponibilidad o durabilidad es el factor principal para seleccionar la región en la que se ejecutan los servicios de Cloud Run. Por lo general, puedes seleccionar la región más cercana a los usuarios, pero debes considerar la ubicación de los otros productos de Google Cloud que usa el servicio de Cloud Run. Si usas productos de Google Cloud en varias ubicaciones, la latencia y el costo del servicio pueden verse afectados.

Cloud Run está disponible en las siguientes regiones:

Sujetas a los Precios del nivel 1

Sujetas a los Precios del nivel 2

  • asia-east2 (Hong Kong)
  • asia-northeast3 (Seúl, Corea del Sur)
  • asia-southeast1 (Singapur)
  • asia-southeast2 (Yakarta)
  • asia-south1 (Bombay, India)
  • asia-south2 Delhi (India)
  • australia-southeast1 (Sídney)
  • australia-southeast2 (Melbourne)
  • europe-central2 (Varsovia, Polonia)
  • europe-west2 (Londres, Reino Unido)
  • europe-west3 (Fráncfort, Alemania)
  • europe-west6 (Zúrich, Suiza) Ícono de la hoja Bajo nivel de CO2
  • northamerica-northeast1 (Montreal) Ícono de la hoja Bajo nivel de CO2
  • northamerica-northeast2 (Toronto) Ícono de la hoja Bajo nivel de CO2
  • southamerica-east1 (São Paulo, Brasil) Ícono de la hoja Bajo nivel de CO2
  • southamerica-west1 (Santiago, Chile)
  • us-west2 (Los Ángeles)
  • us-west3 (Salt Lake City)
  • us-west4 (Las Vegas)

Si ya creaste un servicio de Cloud Run, puedes ver la región en el panel de Cloud Run en la consola.

Recupera la muestra de código

A fin de recuperar la muestra de código para su uso, haz lo siguiente:

  1. Clona el repositorio de la app de muestra en tu máquina local:

    Node.js

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

    De manera opcional, puedes descargar la muestra como un archivo zip y extraerla.

    Python

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

    De manera opcional, puedes descargar la muestra como un archivo ZIP y extraerla.

    Java

    git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git

    De manera opcional, puedes descargar la muestra como un archivo ZIP y extraerla.

  2. Ve al directorio que contiene el código de muestra de Cloud Run:

    Node.js

    cd nodejs-docs-samples/run/idp-sql/

    Python

    cd python-docs-samples/run/idp-sql/

    Java

    cd java-docs-samples/run/idp-sql/

Visualiza la arquitectura

Diagrama de arquitectura
En el diagrama, se muestra un acceso de usuario final a través de una ventana emergente de Acceso con Google que proporciona el IdP y, luego, se lo redirecciona a Cloud Run con la identidad del usuario.
  1. Un usuario final realiza la primera solicitud al servidor de Cloud Run.

  2. El cliente se carga en el navegador.

  3. El usuario proporciona credenciales de acceso a través de la ventana emergente de Acceso con Google desde Identity Platform. Una alerta le da la bienvenida al usuario que accedió.

  4. El control se redirecciona al servidor. El usuario final vota por el cliente, que recupera un token de ID de Identity Platform y lo agrega al encabezado de la solicitud de votación.

  5. Cuando el servidor recibe la solicitud, verifica el token de ID de Identity Platform y confirma que el usuario final está autenticado de forma adecuada. Luego, el servidor envía el voto a Cloud SQL con sus propias credenciales.

Comprende el código central

La muestra se implementa como cliente y servidor, como se describe a continuación.

Integración en Identity Platform: código del cliente

En esta muestra, se usan los SDK de Firebase a fin de integrarse a Identity Platform para acceder y administrar usuarios. Para conectarse a Identity Platform, el JavaScript del cliente contiene la referencia a las credenciales del proyecto como un objeto de configuración e importa los SDK de Firebase JavaScript necesarios:

const config = {
  apiKey: 'API_KEY',
  authDomain: 'PROJECT_ID.firebaseapp.com',
};
<!-- Firebase App (the core Firebase SDK) is always required and must be listed first-->
<script src="https://www.gstatic.com/firebasejs/7.18/firebase-app.js"></script>
<!-- Add Firebase Auth service-->
<script src="https://www.gstatic.com/firebasejs/7.18/firebase-auth.js"></script>

El SDK de Firebase JavaScript controla el flujo de acceso. Para ello, solicita al usuario final que acceda a su Cuenta de Google a través de una ventana emergente. Luego, los redirecciona al servicio.

function signIn() {
  const provider = new firebase.auth.GoogleAuthProvider();
  provider.addScope('https://www.googleapis.com/auth/userinfo.email');
  firebase
    .auth()
    .signInWithPopup(provider)
    .then(result => {
      // Returns the signed in user along with the provider's credential
      console.log(`${result.user.displayName} logged in.`);
      window.alert(`Welcome ${result.user.displayName}!`);
    })
    .catch(err => {
      console.log(`Error during sign in: ${err.message}`);
      window.alert('Sign in failed. Retry or check your browser logs.');
    });
}

Cuando un usuario accede de forma correcta, el cliente usa los métodos de Firebase para crear un token de ID. El cliente agrega el token de ID al encabezado Authorization de su solicitud al servidor.

async function vote(team) {
  if (firebase.auth().currentUser) {
    // Retrieve JWT to identify the user to the Identity Platform service.
    // Returns the current token if it has not expired. Otherwise, this will
    // refresh the token and return a new one.
    try {
      const token = await firebase.auth().currentUser.getIdToken();
      const response = await fetch('/', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          Authorization: `Bearer ${token}`,
        },
        body: 'team=' + team, // send application data (vote)
      });
      if (response.ok) {
        const text = await response.text();
        window.alert(text);
        window.location.reload();
      }
    } catch (err) {
      console.log(`Error when submitting vote: ${err}`);
      window.alert('Something went wrong... Please try again!');
    }
  } else {
    window.alert('User not signed in.');
  }
}

Integración en Identity Platform: código del servidor

El servidor usa el SDK de Firebase Admin para verificar el token de ID de usuario que se envió desde el cliente. Si el token de ID proporcionado tiene el formato correcto, no está vencido y tiene la firma adecuada, el método muestra el token de ID decodificado. El servidor extrae uid de Identity Platform para ese usuario.

Node.js

const firebase = require('firebase-admin');
// Initialize Firebase Admin SDK
firebase.initializeApp();

// Extract and verify Id Token from header
const authenticateJWT = (req, res, next) => {
  const authHeader = req.headers.authorization;
  if (authHeader) {
    const token = authHeader.split(' ')[1];
    // If the provided ID token has the correct format, is not expired, and is
    // properly signed, the method returns the decoded ID token
    firebase
      .auth()
      .verifyIdToken(token)
      .then(decodedToken => {
        const uid = decodedToken.uid;
        req.uid = uid;
        next();
      })
      .catch(err => {
        req.logger.error(`Error with authentication: ${err}`);
        return res.sendStatus(403);
      });
  } else {
    return res.sendStatus(401);
  }
};

Python

def jwt_authenticated(func: Callable[..., int]) -> Callable[..., int]:
    @wraps(func)
    def decorated_function(*args: a, **kwargs: a) -> a:
        header = request.headers.get("Authorization", None)
        if header:
            token = header.split(" ")[1]
            try:
                decoded_token = firebase_admin.auth.verify_id_token(token)
            except Exception as e:
                logger.exception(e)
                return Response(status=403, response=f"Error with authentication: {e}")
        else:
            return Response(status=401)

        request.uid = decoded_token["uid"]
        return func(*args, **kwargs)

    return decorated_function

Java

/** Extract and verify Id Token from header */
private String authenticateJwt(Map<String, String> headers) {
  String authHeader =
      (headers.get("authorization") != null)
          ? headers.get("authorization")
          : headers.get("Authorization");
  if (authHeader != null) {
    String idToken = authHeader.split(" ")[1];
    // If the provided ID token has the correct format, is not expired, and is
    // properly signed, the method returns the decoded ID token
    try {
      FirebaseToken decodedToken = FirebaseAuth.getInstance().verifyIdToken(idToken);
      String uid = decodedToken.getUid();
      return uid;
    } catch (FirebaseAuthException e) {
      logger.error("Error with authentication: " + e.toString());
      throw new ResponseStatusException(HttpStatus.FORBIDDEN, "", e);
    }
  } else {
    logger.error("Error no authorization header");
    throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
  }
}

Conecta el servidor a Cloud SQL

El servidor se conecta al socket de dominio Unix de la instancia de Cloud SQL con el siguiente formato: /cloudsql/CLOUD_SQL_CONNECTION_NAME.

Node.js

/**
 * Connect to the Cloud SQL instance through UNIX Sockets
 *
 * @param {object} credConfig The Cloud SQL connection configuration from Secret Manager
 * @returns {object} Knex's PostgreSQL client
 */
const connectWithUnixSockets = async credConfig => {
  const dbSocketPath = process.env.DB_SOCKET_PATH || '/cloudsql';
  // Establish a connection to the database
  return Knex({
    client: 'pg',
    connection: {
      user: credConfig.DB_USER, // e.g. 'my-user'
      password: credConfig.DB_PASSWORD, // e.g. 'my-user-password'
      database: credConfig.DB_NAME, // e.g. 'my-database'
      host: `${dbSocketPath}/${credConfig.CLOUD_SQL_CONNECTION_NAME}`,
    },
    ...config,
  });
};

Python

def init_unix_connection_engine(
    db_config: Dict[str, str]
) -> sqlalchemy.engine.base.Engine:
    creds = credentials.get_cred_config()
    db_user = creds["DB_USER"]
    db_pass = creds["DB_PASSWORD"]
    db_name = creds["DB_NAME"]
    db_socket_dir = creds.get("DB_SOCKET_DIR", "/cloudsql")
    cloud_sql_connection_name = creds["CLOUD_SQL_CONNECTION_NAME"]

    pool = sqlalchemy.create_engine(
        # Equivalent URL:
        # postgres+pg8000://<db_user>:<db_pass>@/<db_name>
        #                         ?unix_sock=<socket_path>/<cloud_sql_instance_name>/.s.PGSQL.5432
        sqlalchemy.engine.url.URL.create(
            drivername="postgresql+pg8000",
            username=db_user,  # e.g. "my-database-user"
            password=db_pass,  # e.g. "my-database-password"
            database=db_name,  # e.g. "my-database-name"
            query={
                "unix_sock": "{}/{}/.s.PGSQL.5432".format(
                    db_socket_dir, cloud_sql_connection_name  # e.g. "/cloudsql"
                )  # i.e "<PROJECT-NAME>:<INSTANCE-REGION>:<INSTANCE-NAME>"
            },
        ),
        **db_config,
    )
    pool.dialect.description_encoding = None
    logger.info("Database engine initialised from unix conection")

    return pool

Java

Usa la integración del activador de PostgreSQL Spring Cloud Google Cloud para interactuar con tus bases de datos de PostgreSQL en Google Cloud SQL mediante las bibliotecas de JDBC de Spring. Establece tu configuración de Cloud SQL para MySQL para que configure automáticamente un bean DataSource, que, junto con JDBC de Spring, proporciona un bean de objeto JdbcTemplate que permite operaciones como consultar y modificar una base de datos.

# Uncomment and add env vars for local development
# spring.datasource.username=${DB_USER}
# spring.datasource.password=${DB_PASSWORD}
# spring.cloud.gcp.sql.database-name=${DB_NAME}
# spring.cloud.gcp.sql.instance-connection-name=${CLOUD_SQL_CONNECTION_NAME}  
private final JdbcTemplate jdbcTemplate;

public VoteController(JdbcTemplate jdbcTemplate) {
  this.jdbcTemplate = jdbcTemplate;
}

Controla la configuración sensible con Secret Manager

Secret Manager proporciona almacenamiento centralizado y seguro de datos sensibles, como la configuración de Cloud SQL. El server inserta las credenciales de Cloud SQL desde Secret Manager en el entorno de ejecución a través de una variable de entorno. Obtén más información sobre cómo usar secretos con Cloud Run.

Node.js

// CLOUD_SQL_CREDENTIALS_SECRET is the resource ID of the secret, passed in by environment variable.
// Format: projects/PROJECT_ID/secrets/SECRET_ID/versions/VERSION
const {CLOUD_SQL_CREDENTIALS_SECRET} = process.env;
if (CLOUD_SQL_CREDENTIALS_SECRET) {
  try {
    // Parse the secret that has been added as a JSON string
    // to retrieve database credentials
    return JSON.parse(CLOUD_SQL_CREDENTIALS_SECRET.toString('utf8'));
  } catch (err) {
    throw Error(
      `Unable to parse secret from Secret Manager. Make sure that the secret is JSON formatted: ${err}`
    );
  }
}

Python

def get_cred_config() -> Dict[str, str]:
    secret = os.environ.get("CLOUD_SQL_CREDENTIALS_SECRET")
    if secret:
        return json.loads(secret)

Java

/** Retrieve config from Secret Manager */
public static HashMap<String, Object> getConfig() {
  String secret = System.getenv("CLOUD_SQL_CREDENTIALS_SECRET");
  if (secret == null) {
    throw new IllegalStateException("\"CLOUD_SQL_CREDENTIALS_SECRET\" is required.");
  }
  try {
    HashMap<String, Object> config = new Gson().fromJson(secret, HashMap.class);
    return config;
  } catch (JsonSyntaxException e) {
    logger.error(
        "Unable to parse secret from Secret Manager. Make sure that it is JSON formatted: "
            + e);
    throw new RuntimeException(
        "Unable to parse secret from Secret Manager. Make sure that it is JSON formatted.");
  }
}

Configura Identity Platform

Identity Platform requiere una configuración manual en la consola.

  1. Ve a la página Marketplace de Identity Platform en la consola.

    Ir a la página Marketplace de Identity Platform

  2. Haz clic en Habilitar Identity Platform. Se creará un ID de cliente de OAuth2 con el nombre Web client (auto created by Google Service).

  3. Descarga el ID de OAuth2 generado:

    1. En una ventana nueva, ve a la página API y servicios > Credenciales.

      Ir a la página API y servicios > Credenciales

    2. En el registro de “Web client (auto created by Google Service)”, haz clic en el ícono Descargar.

    3. Tenga en cuenta client_id y client_secret.

  4. Configura Google como proveedor:

    1. Ve a la página Proveedores de identidad en Cloud Console.

      Ir a la página Proveedores de identidad

    2. Haz clic en Agregar un proveedor.

    3. Selecciona Google de la lista.

    4. En la configuración del SDK web, ingresa los valores anteriores:

      1. ID de cliente web: client_id

      2. Secreto del cliente web: client_secret

    5. Haz clic en Configurar pantalla.

      1. Selecciona Externos en Tipo de usuario.

      2. Completa los campos obligatorios (correo electrónico de asistencia y del desarrollador).

      3. Continúa hasta la página Resumen.

    6. En “Configurar tu aplicación”, haz clic en Detalles de la configuración. Copia el fragmento en el static/config.js de la muestra para inicializar el SDK de cliente de Identity Platform. Como alternativa, busca el fragmento desde la página de Google Cloud Console en los Detalles de configuración de la aplicación y cópialo en el static/config.js de la muestra.

    7. Haz clic en Guardar.

Implementa el servicio

Sigue los pasos que se indican a continuación para completar el aprovisionamiento y la implementación de la infraestructura, o bien automatiza el proceso en Cloud Shell. Para ello, haz clic en “Ejecutar en Google Cloud”:

Ejecutar en Google Cloud

  1. Crea una instancia de Cloud SQL con base de datos PostgreSQL mediante Console o la CLI:

    gcloud sql instances create CLOUD_SQL_INSTANCE_NAME \
        --database-version=POSTGRES_12 \
        --region=CLOUD_SQL_REGION \
        --cpu=2 \
        --memory=7680MB \
        --root-password=DB_PASSWORD
  2. Agrega los valores de la credencial de Cloud SQL a postgres-secrets.json:

    Node.js

    {
      "CLOUD_SQL_CONNECTION_NAME": "PROJECT_ID:REGION:INSTANCE",
      "DB_NAME": "postgres",
      "DB_USER": "postgres",
      "DB_PASSWORD": "PASSWORD_SECRET"
    }
    

    Python

    {
      "CLOUD_SQL_CONNECTION_NAME": "PROJECT_ID:REGION:INSTANCE",
      "DB_NAME": "postgres",
      "DB_USER": "postgres",
      "DB_PASSWORD": "PASSWORD_SECRET"
    }
    

    Java

    {
      "spring.cloud.gcp.sql.instance-connection-name": "PROJECT_ID:REGION:INSTANCE",
      "spring.cloud.gcp.sql.database-name": "postgres",
      "spring.datasource.username": "postgres",
      "spring.datasource.password": "PASSWORD_SECRET"
    }

  3. Crea un secreto con versión mediante Console o la CLI:

    gcloud secrets create idp-sql-secrets \
        --replication-policy="automatic" \
        --data-file=postgres-secrets.json
  4. Crea una cuenta de servicio para el servidor mediante Console o la CLI:

    gcloud iam service-accounts create idp-sql-identity
  5. Otorga roles para el acceso de Secret Manager y Cloud SQL mediante Console o la CLI:

    1. Permite que la cuenta de servicio asociada con el servidor acceda al secreto creado:

      gcloud secrets add-iam-policy-binding idp-sql-secrets \
        --member serviceAccount:idp-sql-identity@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/secretmanager.secretAccessor
    2. Permite que la cuenta de servicio asociada con el servidor acceda a Cloud SQL:

      gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:idp-sql-identity@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/cloudsql.client
  6. Usa Cloud Build para compilar la imagen de contenedor:

    Node.js

    gcloud builds submit --tag gcr.io/PROJECT_ID/idp-sql

    Python

    gcloud builds submit --tag gcr.io/PROJECT_ID/idp-sql

    Java

    En esta muestra, se usa Jib para compilar imágenes de Docker mediante herramientas de Java comunes. Jib optimiza las compilaciones de contenedores sin la necesidad de tener un Dockerfile o tener Docker instalado. Obtén más información sobre cómo compilar contenedores de Java con Jib.

    1. Usa el auxiliar de credenciales de gcloud para autorizar a Docker a que envíe contenido a tu Container Registry.

      gcloud auth configure-docker

    2. Usa el complemento de Maven para Jib a fin de compilar y enviar el contenedor a Container Registry.

      mvn compile jib:build -Dimage=gcr.io/PROJECT_ID/idp-sql

  7. Implementa la imagen de contenedor en Cloud Run mediante Console o la CLI. Ten en cuenta que el servidor se implementa para permitir el acceso no autenticado. Esto es para que el usuario pueda cargar el cliente y comenzar el proceso. El servidor verifica el token de ID que se agregó a la solicitud de votación de forma manual y autentica al usuario final.

    gcloud run deploy idp-sql \
        --image gcr.io/PROJECT_ID/idp-sql \
        --allow-unauthenticated \
        --service-account idp-sql-identity@PROJECT_ID.iam.gserviceaccount.com \
        --add-cloudsql-instances PROJECT_ID:REGION:CLOUD_SQL_INSTANCE_NAME \
        --update-secrets CLOUD_SQL_CREDENTIALS_SECRET=idp-sql-secrets:latest

    También toma nota de las marcas, --service-account, --add-cloudsql-instances y --update-secrets, que especifican la identidad del servicio, la conexión de la instancia de Cloud SQL y el nombre del secreto con la versión como entorno, respectivamente.

Retoques finales

Identity Platform requiere que autorices la URL del servicio de Cloud Run como un redireccionamiento permitido después del acceso del usuario:

  1. Para editar el proveedor de Google, haz clic en el ícono de lápiz en la página Proveedores de identidad.

  2. Haz clic en Agregar un dominio en Dominios autorizados en el panel derecho y, luego, ingresa la URL de servicio de Cloud Run.

    Puedes ubicar la URL del servicio en los registros después de la compilación o implementación, o puedes encontrarla en cualquier momento con el siguiente comando:

    gcloud run services describe idp-sql --format 'value(status.url)'

Haz una prueba

Para probar el servicio completo, haz lo siguiente:

  1. Dirige tu navegador a la URL proporcionada en el paso de implementación anterior.

  2. Haz clic en el botón Acceder con Google y completa el flujo de autenticación.

  3. Agrega tu voto.

    Se verá de la siguiente manera:

    Captura de pantalla de la interfaz de usuario en la que se muestra el recuento de votos de cada equipo y una lista de votos.

Si eliges seguir desarrollando estos servicios, recuerda que tienen acceso restringido de la administración de identidades y accesos (IAM) al resto de Google Cloud y necesitarán tener funciones de IAM adicionales para acceder a muchos otros servicios.

Limpia

Si creaste un proyecto nuevo para este instructivo, bórralo. Si usaste un proyecto existente y deseas conservarlo sin los cambios que se agregaron en este instructivo, borra los recursos creados para el instructivo.

Borra el proyecto

La manera más fácil de eliminar la facturación es borrar el proyecto que creaste para el instructivo.

Para borrar el proyecto, sigue estos pasos:

  1. En la consola, ve a la página Administrar recursos.

    Ir a Administrar recursos

  2. En la lista de proyectos, elige el proyecto que quieres borrar y haz clic en Borrar.
  3. En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto.

Borra los recursos del instructivo

  1. Usa este comando para borrar el servicio de Cloud Run que implementaste en este instructivo:

    gcloud run services delete SERVICE-NAME

    En el ejemplo anterior, SERVICE-NAME es el nombre del servicio que elegiste.

    También puedes borrar los servicios de Cloud Run desde Google Cloud Console.

  2. Quita la configuración de región predeterminada de gcloud que agregaste durante la configuración en el instructivo:

     gcloud config unset run/region
    
  3. Quita la configuración del proyecto:

     gcloud config unset project
    
  4. Borra otros recursos de Google Cloud que creaste en este instructivo:

¿Qué sigue?