Instructivo para proteger los servicios de Cloud Run

En este instructivo, se explica cómo crear una aplicación segura de dos servicios que se ejecute en Cloud Run. Esta aplicación es un editor de Markdown. Incluye un servicio de “frontend” público que cualquiera puede usar para redactar texto de Markdown y un servicio de “backend” privado que procesa texto de Markdown en HTML.

Diagrama que muestra el flujo de solicitudes desde el “editor” de frontend al “procesador” de backend.
El “procesador” de backend es un servicio privado. Esto permite garantizar un estándar de transformación de texto en una organización sin realizar un seguimiento de los cambios en las bibliotecas de varios lenguajes.

El servicio de backend es privado mediante la función de autenticación de servicio a servicio basada en IAM integrada de Cloud Run (completamente administrado), que limita quién puede llamar al servicio. Ambos servicios se compilan con el principio de menor privilegio, sin acceso al resto de Google Cloud, excepto cuando sea necesario.

Limitaciones o no objetivos de este instructivo

Objetivos

  • Crear una cuenta de servicio dedicada con los permisos mínimos para la autenticación de servicio a servicio y acceso del servicio al resto de Google Cloud
  • Escribir, compilar y, también, implementar dos servicios en Cloud Run que interactúen
  • Realizar solicitudes entre un servicio público y uno privado de Cloud Run

Costos

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

Usa la calculadora de precios para generar una estimación de los costos según el uso previsto.

Es posible que los usuarios nuevos de Google Cloud sean aptos 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 proyecto

  3. Asegúrate de que la facturación esté habilitada para tu proyecto de Cloud. Descubre cómo confirmar que tienes habilitada la facturación en un proyecto.

  4. Habilita la API Cloud Run.

    Habilita la API

  5. Instala e inicializa el SDK de Cloud.
  6. Instala curl para probar el servicio.

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. Si usas Cloud Run (completamente administrado), configura gcloud para la región elegida y especifica managed como tu plataforma de Cloud Run:

    gcloud config set run/region REGION
    gcloud config set run/platform managed

    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

  • asia-east1 (Taiwán)
  • asia-northeast1 (Tokio)
  • asia-northeast2 (Osaka)
  • europe-north1 (Finlandia)
  • europe-west1 (Bélgica)
  • europe-west4 (Países Bajos)
  • us-central1 (Iowa)
  • us-east1 (Carolina del Sur)
  • us-east4 (Virginia del Norte)
  • us-west1 (Oregón)

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)
  • australia-southeast1 (Sídney)
  • europe-central2 (Varsovia, Polonia)
  • europe-west2 (Londres, Reino Unido)
  • europe-west3 (Fráncfort, Alemania)
  • europe-west6 (Zúrich, Suiza)
  • northamerica-northeast1 (Montreal)
  • southamerica-east1 (São Paulo, Brasil)
  • us-west2 (Los Ángeles)
  • us-west3 (Las Vegas)
  • us-west4 (Salt Lake City)

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

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.

    Go

    git clone https://github.com/GoogleCloudPlatform/golang-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/markdown-preview/

    Python

    cd python-docs-samples/run/markdown-preview/

    Go

    cd golang-samples/run/markdown-preview/

    Java

    cd java-docs-samples/run/markdown-preview/

Revisa el servicio de procesamiento de Markdown privado

Desde la perspectiva del frontend, hay una especificación de API simple para el servicio de Markdown:

  • Un extremo en /
  • Se prevén solicitudes POST
  • El cuerpo de la solicitud POST es texto de Markdown

Te recomendamos revisar todo el código en busca de problemas de seguridad o simplemente para obtener más información al respecto mediante una exploración del directorio ./renderer/. Ten en cuenta que en el instructivo no se explica el código de transformación de Markdown.

Envía el servicio de procesamiento de Markdown privado

Para enviar tu código, compilar con Cloud Build, subir a Container Registry y, además, implementar en Cloud Run (completamente administrado), sigue estos pasos:

  1. Cambia al directorio renderer:

    cd renderer/
  2. Ejecuta el siguiente comando para compilar el contenedor y publicar en Container Registry.

    Node.js

    gcloud builds submit --tag gcr.io/PROJECT_ID/renderer

    En el ejemplo anterior, PROJECT_ID es el ID de tu proyecto de GCP y renderer es el nombre que deseas darle al servicio.

    Si la operación se completa de manera correcta, verás un mensaje de ÉXITO con el ID, la hora de creación y el nombre de la imagen. La imagen se almacena en Container Registry y puede volver a usarse si así se desea.

    Python

    gcloud builds submit --tag gcr.io/PROJECT_ID/renderer

    En el ejemplo anterior, PROJECT_ID es el ID de tu proyecto de GCP y renderer es el nombre que deseas darle al servicio.

    Si la operación se completa de manera correcta, verás un mensaje de ÉXITO con el ID, la hora de creación y el nombre de la imagen. La imagen se almacena en Container Registry y puede volver a usarse si así se desea.

    Go

    gcloud builds submit --tag gcr.io/PROJECT_ID/renderer

    En el ejemplo anterior, PROJECT_ID es el ID de tu proyecto de GCP y renderer es el nombre que deseas darle al servicio.

    Si la operación se completa de manera correcta, verás un mensaje de ÉXITO con el ID, la hora de creación y el nombre de la imagen. La imagen se almacena en Container Registry y puede volver a usarse si así se desea.

    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/renderer

    En el ejemplo anterior, PROJECT_ID es el ID de tu proyecto de GCP y renderer es el nombre que deseas darle al servicio.

    Una vez que lo hayas hecho, verás un mensaje de COMPILACIÓN EXITOSA. La imagen se almacena en Container Registry y puede volver a usarse si así se desea.

  3. Implementa como un servicio privado con acceso restringido.

    Cloud Run (completamente administrado) proporciona funciones de control de acceso y de identidad de servicio listas para usar. El control de acceso proporciona una capa de autenticación que impide que los usuarios y otros servicios invoquen el servicio. La identidad de servicio permite restringir el acceso de tu servicio a otros recursos de Google Cloud mediante la creación de una cuenta de servicio dedicada con permisos limitados.

    1. Crea una cuenta de servicio para que funcione como la “identidad de procesamiento” del servicio de procesamiento. De forma predeterminada, esta no tiene otros privilegios más que la membresía del proyecto.

       gcloud iam service-accounts create renderer-identity
      

      El servicio de procesamiento de Markdown no se integra directamente con ningún otro componente en Google Cloud. No necesita más permisos.

    2. Implementa con la cuenta de servicio renderer-identity y rechaza el acceso no autenticado.

      gcloud run deploy renderer \
        --image gcr.io/PROJECT_ID/renderer \
        --service-account renderer-identity \
        --no-allow-unauthenticated

      Cloud Run puede usar el nombre corto de la cuenta de servicio en lugar de la dirección de correo electrónico completa si la cuenta de servicio es parte del mismo proyecto.

Prueba el servicio de procesamiento de Markdown privado

Un navegador web no puede cargar directamente los servicios privados. En su lugar, usa curl o una herramienta de CLI de solicitud HTTP similar que permita inyectar un encabezado Authorization.

Para enviar texto en negrita al servicio y ver que convierta los asteriscos de Markdown en etiquetas HTML <strong>, sigue estos pasos:

  1. Obtén la URL de la salida de la implementación.

  2. Usa gcloud a fin de derivar un token especial de identidad solo de desarrollo para la autenticación:

    TOKEN=$(gcloud auth print-identity-token)
  3. Crea una solicitud curl que pase el texto de Markdown sin procesar como un parámetro de string de consulta de URL con caracteres de escape:

    curl -H "Authorization: Bearer $TOKEN" \
       -H 'Content-Type: text/plain' \
       -d '**Hello Bold Text**' \
       SERVICE_URL
  4. La respuesta debe ser un fragmento de HTML:

     <strong>Hello Bold Text</strong>
    

Revisa la integración entre los servicios de editor y de procesamiento

El servicio de editor proporciona una IU de entrada de texto simple y un espacio para ver la vista previa de HTML. Antes de continuar, abre el directorio ./editor/ para revisar el código que recuperaste antes.

A continuación, explora las siguientes secciones de código que integran de forma segura los dos servicios.

Node.js

El módulo render.js crea solicitudes autenticadas para el servicio del procesador privado. Usa el servidor de metadatos de Google Cloud en el entorno de Cloud Run para crear un token de identidad y agregarlo a la solicitud HTTP como parte de un encabezado Authorization.

En otros entornos, render.js usa credenciales predeterminadas de la aplicación para solicitar un token de los servidores de Google.

const {GoogleAuth} = require('google-auth-library');
const got = require('got');
const auth = new GoogleAuth();

let client, serviceUrl;

// renderRequest creates a new HTTP request with IAM ID Token credential.
// This token is automatically handled by private Cloud Run (fully managed) and Cloud Functions.
const renderRequest = async markdown => {
  if (!process.env.EDITOR_UPSTREAM_RENDER_URL)
    throw Error('EDITOR_UPSTREAM_RENDER_URL needs to be set.');
  serviceUrl = process.env.EDITOR_UPSTREAM_RENDER_URL;

  // Build the request to the Renderer receiving service.
  const serviceRequestOptions = {
    method: 'POST',
    headers: {
      'Content-Type': 'text/plain',
    },
    body: markdown,
    timeout: 3000,
  };

  try {
    // Create a Google Auth client with the Renderer service url as the target audience.
    if (!client) client = await auth.getIdTokenClient(serviceUrl);
    // Fetch the client request headers and add them to the service request headers.
    // The client request headers include an ID token that authenticates the request.
    const clientHeaders = await client.getRequestHeaders();
    serviceRequestOptions.headers['Authorization'] =
      clientHeaders['Authorization'];
  } catch (err) {
    throw Error('could not create an identity token: ', err);
  }

  try {
    // serviceResponse converts the Markdown plaintext to HTML.
    const serviceResponse = await got(serviceUrl, serviceRequestOptions);
    return serviceResponse.body;
  } catch (err) {
    throw Error('request to rendering service failed: ', err);
  }
};

Analiza el Markdown de JSON y envíalo al servicio del procesador para que se transforme en HTML.

app.post('/render', async (req, res) => {
  try {
    const markdown = req.body.data;
    const response = await renderRequest(markdown);
    res.status(200).send(response);
  } catch (err) {
    console.log('error: markdown rendering:', err);
    res.status(500).send(err);
  }
});

Python

El método new_request crea solicitudes autenticadas a servicios privados. Usa el servidor de metadatos de Google Cloud en el entorno de Cloud Run para crear un token de identidad y agregarlo a la solicitud HTTP como parte de un encabezado Authorization.

En otros entornos, new_request solicita un token de identidad desde los servidores de Google mediante la autenticación con credenciales predeterminadas de la aplicación.

import os
import urllib

import google.auth.transport.requests
import google.oauth2.id_token

def new_request(data):
    """
    new_request creates a new HTTP request with IAM ID Token credential.
    This token is automatically handled by private Cloud Run (fully managed)
    and Cloud Functions.
    """

    url = os.environ.get("EDITOR_UPSTREAM_RENDER_URL")
    if not url:
        raise Exception("EDITOR_UPSTREAM_RENDER_URL missing")

    req = urllib.request.Request(url, data=data.encode())
    auth_req = google.auth.transport.requests.Request()
    target_audience = url

    id_token = google.oauth2.id_token.fetch_id_token(auth_req, target_audience)
    req.add_header("Authorization", f"Bearer {id_token}")

    response = urllib.request.urlopen(req)
    return response.read()

Analiza el Markdown de JSON y envíalo al servicio del procesador para que se transforme en HTML.

@app.route("/render", methods=["POST"])
def render_handler():
    body = request.get_json()
    if not body:
        return "Error rendering markdown: Invalid JSON", 400

    data = body["data"]
    try:
        parsed_markdown = render.new_request(data)
        return parsed_markdown, 200
    except Exception as err:
        return f"Error rendering markdown: {err}", 500

Go

RenderService crea solicitudes autenticadas a servicios privados. Usa el servidor de metadatos de Google Cloud en el entorno de Cloud Run para crear un token de identidad y agregarlo a la solicitud HTTP como parte de un encabezado Authorization.

En otros entornos, RenderService solicita un token de identidad desde los servidores de Google mediante la autenticación con credenciales predeterminadas de la aplicación.

import (
	"bytes"
	"context"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"golang.org/x/oauth2"
	"google.golang.org/api/idtoken"
)

// RenderService represents our upstream render service.
type RenderService struct {
	// URL is the render service address.
	URL string
	// tokenSource provides an identity token for requests to the Render Service.
	tokenSource oauth2.TokenSource
}

// NewRequest creates a new HTTP request to the Render service.
// If authentication is enabled, an Identity Token is created and added.
func (s *RenderService) NewRequest(method string) (*http.Request, error) {
	req, err := http.NewRequest(method, s.URL, nil)
	if err != nil {
		return nil, fmt.Errorf("http.NewRequest: %w", err)
	}

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	// Create a TokenSource if none exists.
	if s.tokenSource == nil {
		s.tokenSource, err = idtoken.NewTokenSource(ctx, s.URL)
		if err != nil {
			return nil, fmt.Errorf("idtoken.NewTokenSource: %w", err)
		}
	}

	// Retrieve an identity token. Will reuse tokens until refresh needed.
	token, err := s.tokenSource.Token()
	if err != nil {
		return nil, fmt.Errorf("TokenSource.Token: %w", err)
	}
	token.SetAuthHeader(req)

	return req, nil
}

La solicitud se envía al servicio del procesador después de agregar el texto de Markdown para transformarlo en HTML. Los errores de respuesta se controlan para diferenciar los problemas de comunicación de la funcionalidad de procesamiento.


var renderClient = &http.Client{Timeout: 30 * time.Second}

// Render converts the Markdown plaintext to HTML.
func (s *RenderService) Render(in []byte) ([]byte, error) {
	req, err := s.NewRequest(http.MethodPost)
	if err != nil {
		return nil, fmt.Errorf("RenderService.NewRequest: %w", err)
	}
	req.Body = ioutil.NopCloser(bytes.NewReader(in))
	defer req.Body.Close()

	resp, err := renderClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("http.Client.Do: %w", err)
	}

	out, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("ioutil.ReadAll: %w", err)
	}

	if resp.StatusCode != http.StatusOK {
		return out, fmt.Errorf("http.Client.Do: %s (%d): request not OK", http.StatusText(resp.StatusCode), resp.StatusCode)
	}

	return out, nil
}

Java

makeAuthenticatedRequest crea solicitudes autenticadas a servicios privados. Usa el servidor de metadatos de Google Cloud en el entorno de Cloud Run para crear un token de identidad y agregarlo a la solicitud HTTP como parte de un encabezado Authorization.

En otros entornos, makeAuthenticatedRequest solicita un token de identidad desde los servidores de Google mediante la autenticación con credenciales predeterminadas de la aplicación.

// makeAuthenticatedRequest creates a new HTTP request authenticated by a JSON Web Tokens (JWT)
// retrievd from Application Default Credentials.
public String makeAuthenticatedRequest(String url, String markdown) {
  String html = "";
  try {
    // Retrieve Application Default Credentials
    GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
    IdTokenCredentials tokenCredentials =
        IdTokenCredentials.newBuilder()
            .setIdTokenProvider((IdTokenProvider) credentials)
            .setTargetAudience(url)
            .build();

    // Create an ID token
    String token = tokenCredentials.refreshAccessToken().getTokenValue();
    // Instantiate HTTP request
    MediaType contentType = MediaType.get("text/plain; charset=utf-8");
    okhttp3.RequestBody body = okhttp3.RequestBody.create(markdown, contentType);
    Request request =
        new Request.Builder()
            .url(url)
            .addHeader("Authorization", "Bearer " + token)
            .post(body)
            .build();

    Response response = ok.newCall(request).execute();
    html = response.body().string();
  } catch (IOException e) {
    logger.error("Unable to get rendered data", e);
  }
  return html;
}

Analiza el Markdown de JSON y envíalo al servicio del procesador para que se transforme en HTML.

// '/render' expects a JSON body payload with a 'data' property holding plain text
// for rendering.
@PostMapping(value = "/render", consumes = "application/json")
public String render(@RequestBody Data data) {
  String markdown = data.getData();

  String url = System.getenv("EDITOR_UPSTREAM_RENDER_URL");
  if (url == null) {
    String msg =
        "No configuration for upstream render service: "
            + "add EDITOR_UPSTREAM_RENDER_URL environment variable";
    logger.error(msg);
    throw new IllegalStateException(msg);
  }

  String html = makeAuthenticatedRequest(url, markdown);
  return html;
}

Envía el servicio de editor público

Para compilar y, luego, implementar tu código, sigue estos pasos:

  1. Cambia al directorio editor:

    cd ../editor
  2. Ejecuta el siguiente comando para compilar el contenedor y publicar en Container Registry.

    Node.js

    gcloud builds submit --tag gcr.io/PROJECT_ID/editor

    En el ejemplo anterior, PROJECT_ID es el ID de tu proyecto de GCP y editor es el nombre que deseas darle al servicio.

    Si la operación se completa de manera correcta, verás un mensaje de ÉXITO con el ID, la hora de creación y el nombre de la imagen. La imagen se almacena en Container Registry y puede volver a usarse si así se desea.

    Python

    gcloud builds submit --tag gcr.io/PROJECT_ID/editor

    En el ejemplo anterior, PROJECT_ID es el ID de tu proyecto de GCP y editor es el nombre que deseas darle al servicio.

    Si la operación se completa de manera correcta, verás un mensaje de ÉXITO con el ID, la hora de creación y el nombre de la imagen. La imagen se almacena en Container Registry y puede volver a usarse si así se desea.

    Go

    gcloud builds submit --tag gcr.io/PROJECT_ID/editor

    En el ejemplo anterior, PROJECT_ID es el ID de tu proyecto de GCP y editor es el nombre que deseas darle al servicio.

    Si la operación se completa de manera correcta, verás un mensaje de ÉXITO con el ID, la hora de creación y el nombre de la imagen. La imagen se almacena en Container Registry y puede volver a usarse si así se desea.

    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.

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

    En el ejemplo anterior, PROJECT_ID es el ID de tu proyecto de GCP y editor es el nombre que deseas darle al servicio.

    Una vez que lo hayas hecho, verás un mensaje de COMPILACIÓN EXITOSA. La imagen se almacena en Container Registry y puede volver a usarse si así se desea.

  3. Implementa como un servicio privado con acceso especial al servicio de procesamiento.

    1. Crea una cuenta de servicio para que funcione como la “identidad de procesamiento” del servicio de procesamiento. De forma predeterminada, esta no tiene otros privilegios más que la membresía del proyecto.

       gcloud iam service-accounts create editor-identity
      

      No es necesario que el servicio de editor interactúe con ningún otro elemento de Google Cloud que no sea el servicio de procesamiento de Markdown.

    2. Otorga acceso a la identidad de procesamiento editor-identity para invocar el servicio de procesamiento de Markdown. Cualquier servicio que use esto como una identidad de procesamiento tendrá este privilegio.

      gcloud run services add-iam-policy-binding renderer \
        --member serviceAccount:editor-identity@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/run.invoker

      Debido a que se le otorga la función de invocador en el contexto del servicio de procesamiento, este servicio es el único servicio privado de Cloud Run que el editor puede invocar.

    3. Implementa con la cuenta de servicio editor-identity y permite el acceso público no autenticado.

      gcloud run deploy editor --image gcr.io/PROJECT_ID/editor \
        --service-account editor-identity \
        --set-env-vars EDITOR_UPSTREAM_RENDER_URL=RENDERER_SERVICE_URL \
        --allow-unauthenticated

      Reemplaza los siguientes elementos:

      • PROJECT_ID por el ID del proyecto.
      • RENDERER_SERVICE_URL por la URL proporcionada después de implementar el servicio de procesamiento de Markdown.

Información sobre el tráfico HTTPS

Hay tres solicitudes HTTP involucradas en el procesamiento de Markdown con estos servicios.

Diagrama que muestra el flujo de solicitud del usuario al editor, cómo el editor obtiene un token del servidor de metadatos y realiza una solicitud al servicio de procesamiento, y cómo el servicio de procesamiento muestra HTML al editor.
El servicio de frontend con editor-identity invoca el servicio de procesamiento. editor-identity y renderer-identity tienen permisos limitados, por lo que las vulnerabilidades de seguridad o las inyecciones de código tienen acceso limitado a otros recursos de Google Cloud.

Haz una prueba

Para probar la aplicación de dos servicios completa, sigue estos pasos:

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

  2. Intenta editar el texto de Markdown a la izquierda y haz clic en el botón para ver la vista previa a la derecha.

    Se verá de la siguiente manera:

    Captura de pantalla de la interfaz de usuario del editor de Markdown

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.

Realice una limpieza

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 Cloud Console, 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

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

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

  2. Quita las opciones de configuración predeterminadas de gcloud que agregaste durante la configuración del 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?