Configura l'ambiente


Spesso avrai bisogno di una configurazione aggiuntiva per le tue funzioni, ad esempio chiavi API di terze parti o impostazioni ottimizzabili. L'SDK Firebase per Cloud Functions offre una configurazione dell'ambiente integrata per semplificare l'archiviazione e il recupero di questo tipo di dati per il progetto.

Puoi scegliere tra tre opzioni:

  • Configurazione con parametri (consigliata per la maggior parte degli scenari). Ciò fornisce una configurazione dell'ambiente di tipo elevato con parametri convalidati al momento del deployment, che previene gli errori e semplifica il debug.
  • Configurazione delle variabili di ambiente basata su file. Con questo approccio, puoi creare manualmente un file dotenv per caricare le variabili di ambiente.
  • Configurazione dell'ambiente di runtime con l'interfaccia a riga di comando di Firebase e functions.config (solo Cloud Functions (1a generazione).

Per la maggior parte dei casi d'uso, è consigliata la configurazione con parametri. Questo approccio rende i valori di configurazione disponibili sia in fase di runtime che di deployment e il deployment viene bloccato a meno che tutti i parametri non abbiano un valore valido. Al contrario, la configurazione con variabili di ambiente non è disponibile al momento del deployment.

Configurazione parametrizzata

Cloud Functions for Firebase fornisce un'interfaccia per definire i parametri di configurazione in modo dichiarativo all'interno del codebase. Il valore di questi parametri è disponibile sia durante il deployment delle funzioni, sia durante l'impostazione delle opzioni di deployment e runtime, nonché durante l'esecuzione. Ciò significa che l'interfaccia a riga di comando bloccherà il deployment, a meno che tutti i parametri non abbiano un valore valido.

Per definire i parametri nel codice, utilizza questo modello:

const functions = require('firebase-functions');
const { defineInt, defineString } = require('firebase-functions/params');

// Define some parameters
const minInstancesConfig = defineInt('HELLO_WORLD_MININSTANCES');
const welcomeMessage = defineString('WELCOME_MESSAGE');

// To use configured parameters inside the config for a function, provide them
// directly. To use them at runtime, call .value() on them.
export const helloWorld = functions.runWith({ minInstances: minInstancesConfig}).https.onRequest(
  (req, res) => {
    res.send(`${welcomeMessage.value()}! I am a function.`);
  }
);

Quando esegui il deployment di una funzione con variabili di configurazione con parametri, l'interfaccia a riga di comando di Firebase tenta prima di caricare i propri valori dai file .env locali. Se non sono presenti in questi file e non è impostato alcun default, l'interfaccia a riga di comando richiederà i valori durante il deployment, quindi salverà automaticamente i valori in un file .env denominato .env.<project_ID> nella directory functions/:

$ firebase deploy
i  functions: preparing codebase default for deployment
? Enter a string value for ENVIRONMENT: prod
i  functions: Writing new parameter values to disk: .env.projectId
…
$ firebase deploy
i  functions: Loaded environment variables from .env.projectId

A seconda del tuo flusso di lavoro di sviluppo, potrebbe essere utile aggiungere al controllo della versione il file .env.<project_ID> generato.

Configura comportamento dell'interfaccia a riga di comando

I parametri possono essere configurati con un oggetto Options che controlla in che modo l'interfaccia a riga di comando richiederà i valori. L'esempio seguente imposta le opzioni per convalidare il formato di un numero di telefono, fornire una semplice opzione di selezione e compilare automaticamente un'opzione di selezione dal progetto Firebase:

const { defineString } = require('firebase-functions/params');

const welcomeMessage = defineString('WELCOME_MESSAGE', {default: 'Hello World',
description: 'The greeting that is returned to the caller of this function'});

const onlyPhoneNumbers = defineString('PHONE_NUMBER', {input: {text:
{validationRegex: /\d{3}-\d{3}-\d{4}/, validationErrorMessage: "Please enter
a phone number in the format XXX-YYY-ZZZZ"}}});

const selectedOption = defineString('PARITY', {input: {select: {options:
[{value: "odd"}, {value: "even"}]}}})

const storageBucket = defineString('BUCKET', {input: {resource: {type:
"storage.googleapis.com/Bucket"}}, description: "This will automatically
populate the selector field with the deploying Cloud Project’s
storage buckets"})

Tipi di parametri

La configurazione con parametri fornisce una digitazione efficace per i valori dei parametri e supporta anche i secret di Cloud Secret Manager. I tipi supportati sono:

  • Secret
  • Stringa
  • Booleano
  • Numero intero
  • In virgola mobile

Valori ed espressioni dei parametri

Firebase valuta i parametri sia al momento del deployment sia durante l'esecuzione della funzione. A causa di questi ambienti doppi, è necessario prestare maggiore attenzione quando si confrontano i valori dei parametri e quando vengono utilizzati per impostare le opzioni di runtime per le funzioni.

Per passare un parametro alla funzione come opzione di runtime, passalo direttamente:

const functions = require('firebase-functions');
const { defineInt} = require('firebase-functions/params');
const minInstancesConfig = defineInt('HELLO\_WORLD\_MININSTANCES');

export const helloWorld = functions.runWith({ minInstances: minInstancesConfig}).https.onRequest(
  (req, res) => {
    //…

Inoltre, se devi fare un confronto con un parametro per sapere quale opzione scegliere, dovrai utilizzare comparatori integrati anziché controllare il valore:

const functions = require('firebase-functions');
const { defineBool } = require('firebase-functions/params');
const environment = params.defineString(‘ENVIRONMENT’, {default: ‘dev’});

// use built-in comparators
const minInstancesConfig =environment.equals('PRODUCTION').thenElse(10, 1);
export const helloWorld = functions.runWith({ minInstances: minInstancesConfig}).https.onRequest(
  (req, res) => {
    //…

È possibile accedere ai parametri e alle espressioni parametro utilizzati solo in fase di runtime con la relativa funzione value:

const functions = require('firebase-functions');
const { defineString } = require('firebase-functions/params');
const welcomeMessage = defineString('WELCOME_MESSAGE');

// To use configured parameters inside the config for a function, provide them
// directly. To use them at runtime, call .value() on them.
export const helloWorld = functions.https.onRequest(
 (req, res) => {
    res.send(`${welcomeMessage.value()}! I am a function.`);
  }
);

Parametri integrati

L'SDK Cloud Functions offre tre parametri predefiniti, disponibili nel sottopacchetto firebase-functions/params:

  • projectID: il progetto cloud in cui è in esecuzione la funzione.
  • databaseURL: l'URL dell'istanza di Realtime Database associata alla funzione (se abilitata nel progetto Firebase).
  • storageBucket: il bucket Cloud Storage associato alla funzione (se abilitata nel progetto Firebase).

Queste funzioni come i parametri stringa definiti dall'utente sotto tutti gli aspetti; tuttavia, i loro valori sono sempre noti all'interfaccia a riga di comando di Firebase, pertanto non verranno mai richiesti al momento del deployment né salvati nei file .env.

Parametri secret

I parametri di tipo Secret, definiti utilizzando defineSecret(), rappresentano i parametri stringa con un valore archiviato in Cloud Secret Manager. Anziché eseguire il controllo rispetto a un file .env locale e scrivere un nuovo valore nel file se mancante, i parametri secret verificano la presenza in Cloud Secret Manager e richiedono in modo interattivo il valore di un nuovo secret durante il deployment.

I parametri secret definiti in questo modo devono essere associati a singole funzioni che devono accedervi:

const functions = require('firebase-functions');
const { defineSecret } = require('firebase-functions/params');
const discordApiKey = defineSecret('DISCORD_API_KEY');

export const postToDiscord = functions.runWith({ secrets: [discordApiKey] }).https.onRequest(
  (req, res) => {
    const apiKey = discordApiKey.value();
    //…

Poiché i valori dei secret sono nascosti fino all'esecuzione della funzione, non puoi utilizzarli durante la configurazione della funzione.

Variabili di ambiente

Cloud Functions for Firebase supporta il formato file dotenv per caricare le variabili di ambiente specificate in un file .env nel runtime dell'applicazione. Una volta eseguito il deployment, le variabili di ambiente possono essere lette tramite l'interfaccia process.env.

Per configurare l'ambiente in questo modo, crea un file .env nel progetto, aggiungi le variabili desiderate ed esegui il deployment:

  1. Crea un file .env nella directory functions/:

    # Directory layout:
    #   my-project/
    #     firebase.json
    #     functions/
    #       .env
    #       package.json
    #       index.js
    
  2. Apri il file .env da modificare e aggiungi le chiavi desiderate. Ad esempio:

    PLANET=Earth
    AUDIENCE=Humans
    
  3. Esegui il deployment delle funzioni e verifica che le variabili di ambiente siano state caricate:

    firebase deploy --only functions
    # ...
    # i functions: Loaded environment variables from .env.
    # ...
    

Una volta eseguito il deployment delle variabili di ambiente personalizzate, il codice della funzione può accedervi con la sintassi process.env:

// Responds with "Hello Earth and Humans"
exports.hello = functions.https.onRequest((request, response) => {
  response.send(`Hello ${process.env.PLANET} and ${process.env.AUDIENCE}`);
});

Deployment di più insiemi di variabili di ambiente

Se hai bisogno di un set alternativo di variabili di ambiente per i tuoi progetti Firebase (ad esempio gestione temporanea e produzione), crea un file .env.<project or alias> e scrivi lì le variabili di ambiente specifiche del progetto. Le variabili di ambiente di .env e i file .env specifici del progetto (se presenti) verranno incluse in tutte le funzioni di cui è stato eseguito il deployment.

Ad esempio, un progetto potrebbe includere questi tre file con valori leggermente diversi per lo sviluppo e la produzione:

.env .env.dev .env.prod
PLANET=Terra

SEGMENTO DI PUBBLICO=Umani

AUDIENCE=Dev Humans PUBBLICO=Prod Humans

Dati i valori in questi file separati, l'insieme di variabili di ambiente di cui è stato eseguito il deployment con le funzioni varierà a seconda del progetto di destinazione:

$ firebase use dev
$ firebase deploy --only functions
i functions: Loaded environment variables from .env, .env.dev.
# Deploys functions with following user-defined environment variables:
#   PLANET=Earth
#   AUDIENCE=Dev Humans

$ firebase use prod
$ firebase deploy --only functions
i functions: Loaded environment variables from .env, .env.prod.
# Deploys functions with following user-defined environment variables:
#   PLANET=Earth
#   AUDIENCE=Prod Humans

Variabili di ambiente riservate

Alcune chiavi delle variabili di ambiente sono riservate per uso interno. Non utilizzare queste chiavi nei file .env:

  • Tutte le chiavi iniziano con X_GOOGLE_
  • Tutte le chiavi a partire da EXT_
  • Tutte le chiavi che iniziano con FIREBASE_
  • Qualsiasi chiave dall'elenco seguente:
  • CLOUD_RUNTIME_CONFIG
  • ENTRY_POINT
  • GCP_PROJECT
  • GCLOUD_PROJECT
  • GOOGLE_CLOUD_PROJECT
  • FUNCTION_TRIGGER_TYPE
  • FUNCTION_NAME
  • FUNCTION_MEMORY_MB
  • FUNCTION_TIMEOUT_SEC
  • FUNCTION_IDENTITY
  • FUNCTION_REGION
  • FUNCTION_TARGET
  • FUNCTION_SIGNATURE_TYPE
  • K_SERVICE
  • K_REVISION
  • PORT
  • K_CONFIGURATION

Archiviare e accedere a informazioni di configurazione sensibili

Le variabili di ambiente archiviate nei file .env possono essere utilizzate per la configurazione delle funzioni, ma non dovresti considerarle un modo sicuro per archiviare informazioni sensibili come le credenziali del database o le chiavi API. Questo è particolarmente importante se controlli i tuoi file .env nel controllo del codice sorgente.

Per aiutarti ad archiviare informazioni di configurazione sensibili, Cloud Functions for Firebase si integra con Google Cloud Secret Manager. Questo servizio criptato archivia i valori di configurazione in modo sicuro, pur consentendo un facile accesso dalle funzioni quando necessario.

Crea e utilizza un secret

Per creare un secret, utilizza l'interfaccia a riga di comando di Firebase.

Per creare e utilizzare un secret:

  1. Dalla directory radice della directory del progetto locale, esegui questo comando:

    firebase functions:secrets:set SECRET_NAME

  2. Inserisci un valore per SECRET_NAME.

    L'interfaccia a riga di comando visualizza un messaggio di successo e avvisa che devi eseguire il deployment delle funzioni affinché la modifica abbia effetto.

  3. Prima di eseguire il deployment, assicurati che il codice delle funzioni consenta alla funzione di accedere al secret utilizzando il parametro runWith:

    exports.processPayment = functions
      // Make the secret available to this function
      .runWith({ secrets: ["SECRET_NAME"] })
      .onCall((data, context) => {
        const myBillingService = initializeBillingService(
          // reference the secret value
          process.env.SECRET_NAME
        );
        // Process the payment
      });
  4. Esegui il deployment di Cloud Functions:

    firebase deploy --only functions

Ora potrai accedervi come qualsiasi altra variabile di ambiente. Al contrario, se un'altra funzione che non specifica il secret in runWith tenta di accedere al secret, riceve un valore indefinito:

  exports.anotherEndpoint = functions.https.onRequest((request, response) => {
    response.send(`The secret API key is ${process.env.SECRET_NAME}`);
    // responds with "The secret API key is undefined" because the `runWith` parameter is missing
  });

Una volta eseguito il deployment, la funzione avrà accesso al valore del secret. Solo le funzioni che includono in modo specifico un secret nel parametro runWith avranno accesso a quel secret come variabile di ambiente. In questo modo puoi assicurarti che i valori dei secret siano disponibili solo dove sono necessari, riducendo il rischio di divulgazione accidentale di un secret.

Gestione dei secret

Utilizza l'interfaccia a riga di comando di Firebase per gestire i secret. Quando gestisci i secret in questo modo, tieni presente che alcune modifiche all'interfaccia a riga di comando richiedono di modificare e/o eseguire nuovamente il deployment delle funzioni associate. Nello specifico:

  • Ogni volta che imposti un nuovo valore per un secret, devi eseguire nuovamente il deployment di tutte le funzioni che fanno riferimento al secret in modo che possano recuperare il valore più recente.
  • Se elimini un secret, assicurati che nessuna delle funzioni di cui hai eseguito il deployment faccia riferimento a quel secret. Le funzioni che utilizzano un valore del secret eliminato non funzioneranno correttamente.

Ecco un riepilogo dei comandi dell'interfaccia a riga di comando di Firebase per la gestione dei secret:

# Change the value of an existing secret
firebase functions:secrets:set SECRET_NAME

# View the value of a secret
functions:secrets:access SECRET_NAME

# Destroy a secret
functions:secrets:destroy SECRET_NAME

# View all secret versions and their state
functions:secrets:get SECRET_NAME

# Automatically clean up all secrets that aren't referenced by any of your functions
functions:secrets:prune

Per i comandi access e destroy, puoi fornire il parametro di versione facoltativo per gestire una versione specifica. Ad esempio:

functions:secrets:access SECRET_NAME[@VERSION]

Per maggiori informazioni su queste operazioni, passa -h con il comando per visualizzare la guida dell'interfaccia a riga di comando.

Come vengono fatturati i secret

Secret Manager consente 6 versions di secret attive senza costi. Ciò significa che puoi avere 6 secret al mese in un progetto Firebase senza costi.

Per impostazione predefinita, l'interfaccia a riga di comando di Firebase tenta di eliminare automaticamente le versioni dei secret inutilizzate dove appropriato, ad esempio quando esegui il deployment di funzioni con una nuova versione del secret. Inoltre, puoi eseguire attivamente la pulizia dei secret inutilizzati utilizzando functions:secrets:destroy e functions:secrets:prune.

Secret Manager consente 10.000 operazioni di accesso mensili non fatturate su un secret. Le istanze di funzione leggono solo i secret specificati nel parametro runWith ogni volta che eseguono l'avvio a freddo. Se hai molte istanze di funzione che leggono molti secret, il tuo progetto potrebbe superare questo limite. A quel punto, ti verranno addebitati 0,03 $ogni 10.000 operazioni di accesso.

Per maggiori informazioni, consulta Prezzi di Secret Manager.

Supporto emulatore

La configurazione dell'ambiente con dotenv è progettata per interoperare con un emulatore Cloud Functions locale.

Quando utilizzi un emulatore Cloud Functions locale, puoi sostituire le variabili di ambiente per il tuo progetto configurando un file .env.local. I contenuti di .env.local hanno la precedenza su .env e sul file .env specifico del progetto.

Ad esempio, un progetto potrebbe includere questi tre file contenenti valori leggermente diversi per lo sviluppo e i test locali:

.env .env.dev .env.local
PLANET=Terra

SEGMENTO DI PUBBLICO=Umani

AUDIENCE=Dev Humans AUDIENCE=Persone locali

Se avviato nel contesto locale, l'emulatore carica le variabili di ambiente come mostrato di seguito:

  $ firebase emulators:start
  i  emulators: Starting emulators: functions
  # Starts emulator with following environment variables:
  #  PLANET=Earth
  #  AUDIENCE=Local Humans

Secret e credenziali nell'emulatore Cloud Functions

L'emulatore di Cloud Functions supporta l'uso di secret per archiviare e accedere a informazioni di configurazione sensibili. Per impostazione predefinita, l'emulatore tenterà di accedere ai tuoi secret di produzione utilizzando le credenziali predefinite dell'applicazione. In alcune situazioni come gli ambienti CI, l'emulatore potrebbe non riuscire ad accedere ai valori segreti a causa di limitazioni relative alle autorizzazioni.

Analogamente al supporto dell'emulatore Cloud Functions per le variabili di ambiente, puoi eseguire l'override dei valori dei secret configurando un file .secret.local. In questo modo puoi testare facilmente le funzioni localmente, soprattutto se non hai accesso al valore del secret.

Migrazione dalla configurazione dell'ambiente

Se utilizzi la configurazione dell'ambiente con functions.config, puoi eseguire la migrazione della configurazione esistente come variabili di ambiente (nel formato dotenv). L'interfaccia a riga di comando di Firebase fornisce un comando di esportazione che restituisce la configurazione di ogni alias o progetto elencato nel file .firebaserc della directory (nell'esempio seguente, local, dev e prod) come file .env.

Per eseguire la migrazione, esporta le configurazioni dell'ambiente esistenti utilizzando il comando firebase functions:config:export:

firebase functions:config:export
i  Importing configs from projects: [project-0, project-1]
⚠  The following configs keys could not be exported as environment variables:

⚠  project-0 (dev):
    1foo.a => 1FOO\_A (Key 1FOO\_A must start with an uppercase ASCII letter or underscore, and then consist of uppercase ASCII letters, digits, and underscores.)

Enter a PREFIX to rename invalid environment variable keys: CONFIG\_
✔  Wrote functions/.env.prod
✔  Wrote functions/.env.dev
✔  Wrote functions/.env.local
✔  Wrote functions/.env

Tieni presente che, in alcuni casi, ti verrà richiesto di inserire un prefisso per rinominare le chiavi delle variabili di ambiente esportate. Questo perché non tutte le configurazioni possono essere trasformate automaticamente, poiché potrebbero non essere valide o potrebbero essere una chiave di variabile di ambiente prenotata.

Ti consigliamo di esaminare attentamente i contenuti dei file .env generati prima di eseguire il deployment delle funzioni o di verificare i file .env nel controllo del codice sorgente. Se alcuni valori sono sensibili e non devono essere divulgati, rimuovili dai tuoi file .env e archiviali in modo sicuro in Secret Manager.

Dovrai anche aggiornare il codice delle funzioni. Tutte le funzioni che utilizzano functions.config ora dovranno usare process.env, come mostrato in Eseguire l'upgrade alla 2a generazione.

Configurazione dell'ambiente

Prima del rilascio del supporto delle variabili di ambiente in firebase-functions v3.18.0, l'utilizzo di functions.config() era l'approccio consigliato per la configurazione dell'ambiente. Questo approccio è ancora supportato, ma consigliamo a tutti i nuovi progetti di utilizzare invece le variabili di ambiente, poiché sono più semplici da usare e migliorano la portabilità del codice.

Imposta la configurazione dell'ambiente con l'interfaccia a riga di comando

Per archiviare i dati di ambiente, puoi utilizzare il comando firebase functions:config:set nell'interfaccia a riga di comando di Firebase. Ogni chiave può avere uno spazio dei nomi utilizzando punti per raggruppare le configurazioni correlate. Tieni presente che nelle chiavi vengono accettati solo caratteri minuscoli; non sono consentiti caratteri maiuscoli.

Ad esempio, per archiviare l'ID client e la chiave API per "Alcuni servizi", puoi eseguire:

firebase functions:config:set someservice.key="THE API KEY" someservice.id="THE CLIENT ID"

Recupera la configurazione attuale dell'ambiente

Per ispezionare ciò che è attualmente archiviato nella configurazione dell'ambiente del progetto, puoi utilizzare firebase functions:config:get. Verrà restituito un file JSON simile al seguente:

{
  "someservice": {
    "key":"THE API KEY",
    "id":"THE CLIENT ID"
  }
}

Questa funzionalità si basa sull'API Google Cloud Runtime Configuration.

Utilizza functions.config per accedere alla configurazione dell'ambiente in una funzione

Alcune configurazioni vengono fornite automaticamente nello spazio dei nomi riservato firebase. La configurazione dell'ambiente viene resa disponibile all'interno della funzione in esecuzione tramite functions.config(). Per utilizzare la configurazione riportata sopra, il tuo codice potrebbe avere il seguente aspetto:

const functions = require('firebase-functions');
const request = require('request-promise');

exports.userCreated = functions.database.ref('/users/{id}').onWrite(event => {
  let email = event.data.child('email').val();

  return request({
    url: 'https://someservice.com/api/some/call',
    headers: {
      'X-Client-ID': functions.config().someservice.id,
      'Authorization': `Bearer ${functions.config().someservice.key}`
    },
    body: {email: email}
  });
});

Usa la configurazione dell'ambiente per inizializzare un modulo

Alcuni moduli nodo sono pronti senza alcuna configurazione. Altri moduli richiedono una configurazione aggiuntiva per essere inizializzati correttamente. Ti consigliamo di archiviare questa configurazione in variabili di configurazione dell'ambiente, anziché come hardcoded. Ciò consente di mantenere il codice molto più portabile, il che consente di rendere open source l'applicazione o di passare facilmente dalla versione di produzione a quella temporanea.

Ad esempio, per utilizzare il modulo Slack Node SDK, puoi scrivere questo:

const functions = require('firebase-functions');
const IncomingWebhook = require('@slack/client').IncomingWebhook;
const webhook = new IncomingWebhook(functions.config().slack.url);

Prima del deployment, imposta la variabile di configurazione dell'ambiente slack.url:

firebase functions:config:set slack.url=https://hooks.slack.com/services/XXX

Comandi ambientali aggiuntivi

  • firebase functions:config:unset key1 key2 rimuove le chiavi specificate dalla configurazione
  • firebase functions:config:clone --from <fromProject> clona l'ambiente di un altro progetto nel progetto attualmente attivo.

Variabili di ambiente compilate automaticamente

Alcune variabili di ambiente vengono compilate automaticamente nel runtime delle funzioni e nelle funzioni emulate localmente. Sono incluse le variabili di ambiente compilate da Google Cloud e una variabile di ambiente specifica di Firebase:

process.env.FIREBASE_CONFIG: fornisce le seguenti informazioni sulla configurazione del progetto Firebase:

{
  databaseURL: 'https://databaseName.firebaseio.com',
  storageBucket: 'projectId.appspot.com',
  projectId: 'projectId'
}

Questa configurazione viene applicata automaticamente quando inizializzi l'SDK Firebase Admin senza argomenti. Se stai scrivendo funzioni in JavaScript, inizializza come segue:

const admin = require('firebase-admin');
admin.initializeApp();

Se stai scrivendo funzioni in TypeScript, inizializzalo in questo modo:

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import 'firebase-functions';
admin.initializeApp();

Se devi inizializzare l'SDK Admin con la configurazione del progetto predefinita utilizzando le credenziali dell'account di servizio, puoi caricare le credenziali da un file e aggiungerle a FIREBASE_CONFIG nel seguente modo:

serviceAccount = require('./serviceAccount.json');

const adminConfig = JSON.parse(process.env.FIREBASE_CONFIG);
adminConfig.credential = admin.credential.cert(serviceAccount);
admin.initializeApp(adminConfig);