Configurare un servizio Cloud Run per accedere sia a un servizio Cloud Run interno sia a una rete internet pubblica

1. Introduzione

Panoramica

Per proteggere il traffico di rete per i propri servizi e applicazioni, molte organizzazioni utilizzano una rete Virtual Private Cloud (VPC) su Google Cloud con controlli perimetrali per impedire l'esfiltrazione di dati. Una rete VPC è una versione virtuale di una rete fisica implementata all'interno della rete di produzione di Google. Una rete VPC fornisce connettività per le istanze di macchine virtuali (VM) Compute Engine, offre bilanciatori del carico di rete pass-through interni nativi e sistemi proxy per i bilanciatori del carico delle applicazioni interni, si connette alle reti on-premise utilizzando i tunnel Cloud VPN e i collegamenti VLAN per Cloud Interconnect e distribuisce il traffico dai bilanciatori del carico esterni di Google Cloud ai backend.

A differenza delle VM, i servizi Cloud Run non sono associati a nessuna rete VPC specifica per impostazione predefinita. Questo codelab mostra come modificare le impostazioni di Ingress (connessioni in entrata) in modo che solo il traffico proveniente da un VPC possa accedere a un servizio Cloud Run (ad es. un servizio di backend). Inoltre, questo codelab mostra come fare in modo che un secondo servizio (ad es. un servizio frontend) acceda sia al servizio Cloud Run di backend tramite un VPC sia a internet pubblico.

In questo esempio, il servizio Cloud Run di backend restituisce "hello world". Il servizio Cloud Run di frontend fornisce un campo di immissione nell'UI per raccogliere un URL. Quindi il servizio frontend effettua una richiesta GET a quell'URL (ad es. il servizio di backend), trasformandola in una richiesta da servizio a servizio (anziché da browser a servizio). Quando il servizio frontend riesce a raggiungere il backend, nel browser viene visualizzato il messaggio "hello world". Poi, vedrai come effettuare una chiamata a https://curlmyip.org per recuperare l'indirizzo IP del tuo servizio frontend.

Cosa imparerai a fare

  • Come consentire solo il traffico da un VPC al tuo servizio Cloud Run
  • Come configurare il traffico in uscita su un servizio Cloud Run (ad es. frontend) per comunicare con un servizio Cloud Run solo con traffico in entrata interno (ad es. backend), mantenendo l'accesso a internet pubblico per il servizio frontend.

2. Configurazione e requisiti

Prerequisiti

  • Hai eseguito l'accesso alla console Cloud.
  • In precedenza hai eseguito il deployment di una funzione di 2ª gen. Ad esempio, puoi seguire la guida rapida Eseguire il deployment di una funzione Cloud Functions di 2ª gen per iniziare.

Attiva Cloud Shell

  1. Nella console Cloud, fai clic su Attiva Cloud Shell d1264ca30785e435.png.

cb81e7c8e34bc8d.png

Se è la prima volta che avvii Cloud Shell, viene visualizzata una schermata intermedia che ne descrive le funzionalità. Se hai visualizzato una schermata intermedia, fai clic su Continua.

d95252b003979716.png

Bastano pochi istanti per eseguire il provisioning e connettersi a Cloud Shell.

7833d5e1c5d18f54.png

Questa macchina virtuale è caricata con tutti gli strumenti di sviluppo necessari. Offre una home directory persistente di 5 GB ed è in esecuzione su Google Cloud, migliorando notevolmente le prestazioni di rete e l'autenticazione. Gran parte del lavoro per questo codelab, se non tutto, può essere svolto con un browser.

Una volta eseguita la connessione a Cloud Shell, dovresti vedere che il tuo account è autenticato e il progetto è impostato sul tuo ID progetto.

  1. Esegui questo comando in Cloud Shell per verificare che l'account sia autenticato:
gcloud auth list

Output comando

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Esegui questo comando in Cloud Shell per verificare che il comando gcloud conosca il tuo progetto:
gcloud config list project

Output comando

[core]
project = <PROJECT_ID>

In caso contrario, puoi impostarlo con questo comando:

gcloud config set project <PROJECT_ID>

Output comando

Updated property [core/project].

3. Crea i servizi Cloud Run

Imposta le variabili di ambiente

Puoi impostare le variabili di ambiente che verranno utilizzate durante questo codelab.

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

Crea il servizio Cloud Run di backend

Innanzitutto, crea una directory per il codice sorgente e passa a questa directory.

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

Quindi, crea un file `package.json`` con i seguenti contenuti:

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

Poi, crea un file sorgente index.js con i contenuti riportati di seguito. Questo file contiene il punto di ingresso del servizio e la logica principale dell'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}`);
});

Infine, esegui il deployment del servizio Cloud Run eseguendo il seguente comando.

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

Crea il servizio Cloud Run di frontend

Vai alla directory frontend

cd ../frontend-w-internet

Quindi, crea un file package.json con i seguenti contenuti:

{
  "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"
  }
}

Poi, crea un file sorgente index.js con i contenuti riportati di seguito. Questo file contiene il punto di ingresso del servizio e la logica principale dell'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 una directory pubblica per il file index.html

mkdir public
touch public/index.html

Aggiorna index.html in modo che contenga quanto segue:

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

Infine, esegui il deployment del servizio Cloud Run eseguendo il seguente comando.

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

Chiama il servizio di backend

In questa sezione, verificherai di aver eseguito correttamente il deployment di due servizi Cloud Run.

Apri l'URL del servizio frontend nel browser web, ad es. https://frontend-your-hash-uc.a.run.app/

Nella casella di testo, inserisci l'URL del servizio di backend. Tieni presente che questa richiesta viene instradata dall'istanza Cloud Run di frontend al servizio Cloud Run di backend e non dal tuo browser.

Vedrai "hello world"

4. Imposta il servizio di backend solo per il traffico in entrata interno

Puoi eseguire il seguente comando gcloud per incorporare un servizio Cloud Run nella tua rete privata.

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

Se provassi a chiamare il servizio di backend dal servizio frontend, riceveresti un errore 404. La connessione in uscita (o traffico in uscita) del servizio Cloud Run di frontend va prima a internet, quindi Google Cloud non conosce l'origine della richiesta.

5. Configura il servizio frontend per accedere al VPC

In questa sezione, configurerai il servizio Cloud Run di frontend per comunicare con il servizio di backend tramite un VPC.

Per farlo, devi aggiungere il traffico in uscita VPC diretto al servizio Cloud Run di frontend per assicurarti che possa raggiungere gli indirizzi IP interni sulla rete VPC. Poi, configurerai il traffico in uscita in modo che solo le richieste agli IP privati vengano instradate al VPC. Questa configurazione consentirà al frontend di raggiungere comunque internet pubblico. Puoi scoprire di più nella documentazione sulla ricezione delle richieste da altri servizi Cloud Run.

Configura il traffico in uscita VPC diretto

Innanzitutto, esegui questo comando per utilizzare il traffico in uscita VPC diretto sul servizio frontend:

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

Ora puoi verificare che il servizio frontend abbia accesso al VPC:

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

Dovresti vedere un output simile a

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

Abilita l'accesso privato Google

Poi, abilita l'accesso privato Google sulla subnet eseguendo il seguente comando:

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

Puoi verificare che l'accesso privato Google sia stato abilitato eseguendo questo comando:

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

Crea una zona DNS Cloud per gli URL run.app

Infine, crea una zona Cloud DNS per gli URL run.app in modo che Google Cloud possa trattarli come indirizzi IP interni.

In un passaggio precedente, hai configurato il traffico in uscita VPC diretto solo per gli intervalli privati. Ciò significa che le connessioni in uscita dal servizio frontend verranno indirizzate alla rete VPC solo se la destinazione è un IP interno. Tuttavia, il servizio di backend utilizza un URL run.app che viene risolto in un IP pubblico.

In questo passaggio, creerai una zona Cloud DNS per gli URL run.app in modo che vengano risolti negli intervalli di indirizzi IP private.googleapis.com, che vengono riconosciuti come indirizzi IP interni. Ora, tutte le richieste a questi intervalli verranno instradate tramite la rete VPC.

Puoi farlo seguendo la procedura descritta in: 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"

Ora, quando provi a raggiungere il servizio di backend per il tuo sito web, vedrai "hello world" restituito.

E quando provi a raggiungere internet utilizzando https://curlmyip.org/, vedrai il tuo indirizzo IP.

6. Risoluzione dei problemi

Di seguito sono riportati alcuni possibili messaggi di errore che potresti riscontrare se le impostazioni non sono state configurate correttamente.

  • Se ricevi un errore getaddrinfo ENOTFOUND backend-your-hash-uc.a.run.app, assicurati di non aver aggiunto "https://" al record A DNS
  • Se ricevi un errore 404 quando provi ad accedere al backend dopo aver configurato la zona, puoi attendere la scadenza della cache sul record run.app globale (ad es. 6 ore) oppure puoi creare una nuova revisione (cancellando quindi la cache) eseguendo il seguente comando: gcloud beta run services update $FRONTEND --network=$SUBNET_NAME --subnet=$SUBNET_NAME --vpc-egress=private-ranges-only --region=$REGION

7. Complimenti!

Complimenti per aver completato il codelab.

Ti consigliamo di consultare la documentazione sulle reti private su Cloud Run.

Argomenti trattati

  • Come consentire solo il traffico da un VPC al tuo servizio Cloud Run
  • Come configurare il traffico in uscita su un servizio Cloud Run (ad es. frontend) per comunicare con un servizio Cloud Run solo con traffico in entrata interno (ad es. backend), mantenendo l'accesso a internet pubblico per il servizio frontend.

8. Libera spazio

Per evitare addebiti involontari (ad esempio, se questo servizio Cloud Run viene richiamato inavvertitamente più volte di quanto consentito dalla quota di richiami mensili di Cloud Run nel livello senza costi), puoi eliminare il servizio Cloud Run o il progetto creato nel passaggio 2.

Per eliminare i servizi Cloud Run, vai alla console Cloud Run all'indirizzo https://console.cloud.google.com/functions/ ed elimina i servizi $FRONTEND e $BACKEND che hai creato in questo codelab.

Se scegli di eliminare l'intero progetto, puoi andare all'indirizzo https://console.cloud.google.com/cloud-resource-manager, selezionare il progetto creato nel passaggio 2 e scegliere Elimina. Se elimini il progetto, dovrai cambiare progetto in Cloud SDK. Puoi visualizzare l'elenco di tutti i progetti disponibili eseguendo gcloud projects list.