Configurar un servicio de Cloud Run para acceder a un servicio interno de Cloud Run y a la Internet pública

1. Introducción

Descripción general

Para proteger el tráfico de red de sus servicios y aplicaciones, muchas organizaciones usan una red de nube privada virtual (VCP) en Google Cloud con controles perimetrales para evitar el robo de datos. Una red de VPC es una versión virtual de una red física que se implementa dentro de la red de producción de Google. Una red de VPC proporciona conectividad para tus instancias de máquina virtual (VM) de Compute Engine, ofrece balanceadores de cargas de red de transferencia internos nativos y sistemas proxy para balanceadores de cargas de aplicaciones internos, se conecta a redes locales usando túneles de Cloud VPN y adjuntos de VLAN para Cloud Interconnect, y distribuye el tráfico de balanceadores de cargas externos de Google Cloud a backends.

A diferencia de las VMs, los servicios de Cloud Run no están asociados con ninguna red de VPC en particular de forma predeterminada. En este codelab, se muestra cómo cambiar la configuración de entrada (conexiones entrantes) para que solo el tráfico proveniente de una VPC pueda acceder a un servicio de Cloud Run (p.ej., un servicio de backend). Además, en este codelab, se muestra cómo hacer que un segundo servicio (p.ej., un servicio de frontend) acceda al servicio de backend de Cloud Run a través de una VPC y, además, seguir teniendo acceso público a Internet.

En este ejemplo, el servicio de backend de Cloud Run muestra Hello World. El servicio de frontend de Cloud Run proporciona un campo de entrada en la IU para recopilar una URL. Luego, el servicio de frontend realiza una solicitud GET a esa URL (p.ej., el servicio de backend), por lo que se convierte en una solicitud de servicio a servicio (en lugar de una solicitud de navegador a servicio). Cuando el servicio de frontend llega correctamente al backend, se muestra el mensaje Hello World en el navegador. Luego, verás cómo puedes llamar a https://curlmyip.org para recuperar la dirección IP de tu servicio Frontend.

Qué aprenderás

  • Cómo permitir solo el tráfico de una VPC al servicio de Cloud Run
  • Cómo configurar la salida en un servicio de Cloud Run (p.ej., frontend) para comunicarse con un servicio de Cloud Run de solo entrada interna (p.ej., backend) y, al mismo tiempo, mantener el acceso público a Internet para el servicio de frontend.

2. Configuración y requisitos

Requisitos previos

Activar Cloud Shell

  1. En la consola de Cloud, haz clic en Activar Cloud Shelld1264ca30785e435.png.

cb81e7c8e34bc8d.png

Si es la primera vez que inicias Cloud Shell, verás una pantalla intermedia que describe en qué consiste. Si apareció una pantalla intermedia, haz clic en Continuar.

d95252b003979716.png

El aprovisionamiento y la conexión a Cloud Shell solo tomará unos minutos.

7833d5e1c5d18f54.png

Esta máquina virtual está cargada con todas las herramientas de desarrollo necesarias. Ofrece un directorio principal persistente de 5 GB y se ejecuta en Google Cloud, lo que mejora considerablemente el rendimiento de la red y la autenticación. Gran parte de tu trabajo en este codelab, si no todo, se puede hacer con un navegador.

Una vez que te conectes a Cloud Shell, deberías ver que estás autenticado y que el proyecto está configurado con tu ID del proyecto.

  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que tienes la autenticación:
gcloud auth list

Resultado del comando

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Ejecuta el siguiente comando en Cloud Shell para confirmar que el comando de gcloud conoce tu proyecto:
gcloud config list project

Resultado del comando

[core]
project = <PROJECT_ID>

De lo contrario, puedes configurarlo con el siguiente comando:

gcloud config set project <PROJECT_ID>

Resultado del comando

Updated property [core/project].

3. Crea los servicios de Cloud Run

Configura variables de entorno

Puedes establecer variables de entorno que se usarán en este codelab.

PROJECT_ID=<YOUR_PROJECT_ID>
REGION=<YOUR_REGION, e.g. us-central1>
FRONTEND=frontend-with-internet
BACKEND=backend
SUBNET_NAME=default

Crea el servicio de backend de Cloud Run

Primero, crea un directorio para el código fuente y desplázate a ese directorio con el comando cd.

mkdir -p egress-private-codelab/frontend-w-internet egress-private-codelab/backend && cd egress-private-codelab/backend

Luego, crea un archivo `package.json`` con el siguiente contenido:

{
    "name": "backend-service",
    "version": "1.0.0",
    "description": "",
    "scripts": {
        "start": "node index.js"
    },
    "dependencies": {
        "express": "^4.18.1"
    }
}

A continuación, crea un archivo fuente index.js con el siguiente contenido. Este archivo contiene el punto de entrada del servicio y la lógica principal de la app.

const express = require('express');

const app = express();

app.use(express.urlencoded({ extended: true }));

app.get('/', function (req, res) {
    res.send("hello world");
});

const port = parseInt(process.env.PORT) || 8080;
app.listen(port, () => {
    console.log(`helloworld: listening on port ${port}`);
});

Por último, implementa el servicio de Cloud Run ejecutando el siguiente comando.

gcloud run deploy $BACKEND --source . --allow-unauthenticated --region $REGION

Crea el servicio de Cloud Run de frontend

Navega al directorio de frontend

cd ../frontend-w-internet

Luego, crea un archivo package.json con el siguiente contenido:

{
  "name": "frontend",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "start": "node index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "axios": "^1.6.6",
    "express": "^4.18.2",
    "htmx.org": "^1.9.10"
  }
}

A continuación, crea un archivo fuente index.js con el siguiente contenido. Este archivo contiene el punto de entrada del servicio y la lógica principal de la app.

const express = require("express");
const app = express();
const port = 8080;
const path = require('path');
const axios = require('axios');

// serve static content (index.html) using
// built-in middleware function in Express 
app.use(express.static('public'));
app.use(express.urlencoded({ extended: true }));

// this endpoint receives a URL in the post body
// and then makes a get request to that URL
// results are sent back to the caller
app.post('/callService', async (req, res) => {

    const url = req.body.url;
    let message = "";

    try {
        console.log("url: ", url);
        const response = await axios.get(url);
        message = response.data;

    } catch (error) {
        message = error.message;
        console.error(error.message);
    }

    res.send(`
        ${message}
        <p>
        </p>
    `);
});

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`);
});

Crea un directorio público para el archivo index.html

mkdir public
touch public/index.html

Además, actualiza index.html para que contenga lo siguiente:

<html>
  <script
    src="https://unpkg.com/htmx.org@1.9.10"
    integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC"
    crossorigin="anonymous"
  ></script>
  <body>
    <div style="margin-top: 100px; margin-left: 100px">
      <h1>I'm the Request Tester service on the Internet</h1>
      <form hx-trigger="submit" hx-post="/callService" hx-target="#zen">
        <label for="url"> URL:</label>
        <input
          style="width: 308px"
          type="text"
          id="url"
          name="url"
          placeholder="The backend service URL"
          required
        />
        <button hx-indicator="#loading" type="submit">Submit</button>
        <p></p>
        <span class="htmx-indicator" id="loading"> Loading... </span>
        <div id="zen" style="white-space: pre-wrap"></div>
        <p></p>
      </form>
    </div>
  </body>
</html>

Por último, implementa el servicio de Cloud Run ejecutando el siguiente comando.

gcloud run deploy $FRONTEND --source . --allow-unauthenticated --region $REGION

Llama al servicio de backend

En esta sección, verificarás si implementaste correctamente dos servicios de Cloud Run.

Abre la URL del servicio de frontend en tu navegador web, p.ej., https://frontend-your-hash-uc.a.run.app/

En el cuadro de texto, ingresa la URL del servicio de backend. Ten en cuenta que esta solicitud se enruta desde la instancia de frontend de Cloud Run hasta el servicio de backend de Cloud Run, y no desde tu navegador.

Verás “Hello World”

4. Configurar el servicio de backend solo para entrada interna

Puedes ejecutar el siguiente comando de gcloud para incorporar un servicio de Cloud Run en tu red privada.

gcloud run services update $BACKEND --ingress internal --region $REGION

Si intentaras llamar al servicio de backend desde el servicio de frontend, recibirías un error 404. La conexión saliente (o salida) del servicio de frontend de Cloud Run primero se dirige a Internet, por lo que Google Cloud no sabe el origen de la solicitud.

5. Configurar el servicio de frontend para acceder a la VPC

En esta sección, configurarás tu servicio de frontend de Cloud Run para que se comunique con tu servicio de backend a través de una VPC.

Para ello, deberás agregar una salida de VPC directa a tu servicio de frontend de Cloud Run para asegurarte de que pueda acceder a las direcciones IP internas en la red de VPC. Luego, configurarás la salida para que solo las solicitudes a IP privadas se enruten a la VPC. Esta configuración permitirá que el frontend siga accediendo a la Internet pública. Puedes obtener más información en la documentación sobre cómo recibir solicitudes de otros servicios de Cloud Run.

Configura la salida de VPC directa

Primero, ejecuta este comando para usar la salida de VPC directa en tu servicio de frontend:

gcloud beta run services update $FRONTEND \
--network=$SUBNET_NAME \
--subnet=$SUBNET_NAME  \
--vpc-egress=private-ranges-only \
--region=$REGION

Ahora puedes confirmar que tu servicio de frontend tenga acceso a la VPC:

gcloud beta run services describe $FRONTEND \
--region=$REGION

Deberías ver un resultado similar al siguiente

VPC access:
    Network:        default
    Subnet:          default
    Egress:          private-ranges-only

Habilite el Acceso privado a Google

A continuación, habilitarás el Acceso privado a Google en la subred ejecutando el siguiente comando:

gcloud compute networks subnets update $SUBNET_NAME \
--region=$REGION \
--enable-private-ip-google-access

Para verificar que se habilitó el Acceso privado a Google, ejecuta este comando:

gcloud compute networks subnets describe $SUBNET_NAME \
--region=$REGION \
--format="get(privateIpGoogleAccess)"

Crea una zona de Cloud DNS para las URLs de run.app

Por último, crea una zona de Cloud DNS para las URLs de run.app de modo que Google Cloud pueda tratarlas como direcciones IP internas.

En un paso anterior, en el que configuraste la salida de VPC directa para solo rangos privados. Esto significa que las conexiones salientes de tu servicio de frontend solo irán a la red de VPC si el destino es una IP interna. Sin embargo, tu servicio de backend usa una URL run.app que se resuelve en una IP pública.

En este paso, crearás una zona de Cloud DNS para que las URLs de run.app se resuelvan en los rangos de direcciones IP private.googleapis.com, que se reconocen como direcciones IP internas. Cualquier solicitud a estos rangos se enrutará a través de tu red de VPC.

Para ello, sigue estos pasos: https://cloud.google.com/run/docs/securing/private-networking#from-other-services

# do not include the https:// in your DNS Name
# for example: backend-<hash>-uc.a.run.app
DNS_NAME=<your backend service URL without the https://>

gcloud dns --project=$PROJECT_ID managed-zones create codelab-backend-service \
 --description="" \
 --dns-name="a.run.app." \
 --visibility="private" \
 --networks=$SUBNET_NAME

gcloud dns --project=$PROJECT_ID record-sets create $DNS_NAME. \
--zone="codelab-backend-service" \
 --type="A" \
 --ttl="60" \
--rrdatas="199.36.153.8,199.36.153.9,199.36.153.10,199.36.153.11"

Ahora, cuando intentes acceder al servicio de backend de tu sitio web, verás “Hello World”. que se devuelven.

Y cuando intentes acceder a Internet usando https://curlmyip.org/, verás tu dirección IP.

6. Soluciona problemas

Estos son algunos mensajes de error que podrían aparecer si los parámetros no se establecieron correctamente.

  • Si recibes un mensaje de error getaddrinfo ENOTFOUND backend-your-hash-uc.a.run.app, asegúrate de no haber agregado “https://”. al registro A del DNS
  • Si recibes un error 404 cuando intentas acceder al backend después de configurar la zona, puedes esperar a que venza la caché en el registro global run.app (p.ej., 6 horas) o puedes crear una revisión nueva (por lo tanto, borrar la caché) ejecutando el siguiente comando: gcloud beta run services update $FRONTEND --network=$SUBNET_NAME --subnet=$SUBNET_NAME --vpc-egress=private-ranges-only --region=$REGION

7. ¡Felicitaciones!

¡Felicitaciones por completar el codelab!

Te recomendamos que revises la documentación sobre Herramientas de redes privadas en Cloud Run.

Temas abordados

  • Cómo permitir solo el tráfico de una VPC al servicio de Cloud Run
  • Cómo configurar la salida en un servicio de Cloud Run (p.ej., frontend) para comunicarse con un servicio de Cloud Run de solo entrada interna (p.ej., backend) y, al mismo tiempo, mantener el acceso público a Internet para el servicio de frontend.

8. Limpia

Para evitar cargos involuntarios (por ejemplo, si este servicio de Cloud Run se invoca de forma involuntaria más veces que tu asignación mensual de invocación de Cloud Run en el nivel gratuito), puedes borrar el servicio de Cloud Run o borrar el proyecto que creaste en el paso 2.

Para borrar los servicios de Cloud Run, ve a la consola de Cloud Run en https://console.cloud.google.com/functions/ y borra los servicios de $FRONTEND y $BACKEND que creaste en este codelab.

Si decides borrar el proyecto completo, puedes ir a https://console.cloud.google.com/cloud-resource-manager, seleccionar el proyecto que creaste en el paso 2 y elegir Borrar. Si borras el proyecto, deberás cambiar los proyectos en tu SDK de Cloud. Para ver la lista de todos los proyectos disponibles, ejecuta gcloud projects list.