Configura tu entorno


A menudo necesitarás una configuración adicional para tus funciones, como claves API de terceros o configuraciones ajustables. El SDK de Firebase para Cloud Functions ofrece una configuración de entorno integrada para facilitar el almacenamiento y la recuperación de este tipo de datos para su proyecto.

Puedes elegir entre tres opciones:

  • Configuración parametrizada (recomendada para la mayoría de escenarios). Esto proporciona una configuración de entorno fuertemente tipada con parámetros que se validan en el momento de la implementación, lo que evita errores y simplifica la depuración.
  • Configuración basada en archivos de variables de entorno . Con este enfoque, crea manualmente un archivo dotenv para cargar variables de entorno.
  • Configuración del entorno de ejecución con Firebase CLI y functions.config (solo Cloud Functions (1.ª generación)).

Para la mayoría de los casos de uso, se recomienda la configuración parametrizada. Este enfoque hace que los valores de configuración estén disponibles tanto en tiempo de ejecución como en tiempo de implementación, y la implementación se bloquea a menos que todos los parámetros tengan un valor válido. Por el contrario, la configuración con variables de entorno no está disponible en el momento de la implementación.

Configuración parametrizada

Cloud Functions para Firebase proporciona una interfaz para definir parámetros de configuración de forma declarativa dentro de su código base. El valor de estos parámetros está disponible tanto durante la implementación de la función, al configurar las opciones de implementación y tiempo de ejecución, como durante la ejecución. Esto significa que la CLI bloqueará la implementación a menos que todos los parámetros tengan un valor válido.

Nodo.js

const { onRequest } = require('firebase-functions/v2/https');
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 = onRequest(
  { minInstances: minInstancesConfig },
(req, res) => {
    res.send(`${welcomeMessage.value()}! I am a function.`);
  }
);

Pitón

from firebase_functions import https_fn
from firebase_functions.params import IntParam, StringParam

MIN_INSTANCES = IntParam("HELLO_WORLD_MIN_INSTANCES")
WELCOME_MESSAGE = StringParam("WELCOME_MESSAGE")

# To use configured parameters inside the config for a function, provide them
# directly. To use them at runtime, call .value() on them.
@https_fn.on_request(min_instances=MIN_INSTANCES)
def hello_world(req):
    return https_fn.Response(f'{WELCOME_MESSAGE.value()}! I am a function!')

Al implementar una función con variables de configuración parametrizadas, Firebase CLI primero intenta cargar sus valores desde archivos .env locales. Si no están presentes en esos archivos y no se establece ningún valor default , la CLI solicitará los valores durante la implementación y luego guardará automáticamente sus valores en un archivo .env llamado .env.<project_ID> en su directorio 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

Dependiendo de su flujo de trabajo de desarrollo, puede resultar útil agregar el archivo .env.<project_ID> generado al control de versiones.

Configurar el comportamiento de la CLI

Los parámetros se pueden configurar con un objeto Options que controla cómo la CLI solicitará valores. El siguiente ejemplo establece opciones para validar el formato de un número de teléfono, proporcionar una opción de selección simple y completar una opción de selección automáticamente desde el proyecto de Firebase:

Nodo.js

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: params.select(["odd", "even"])});

const memory = defineInt("MEMORY", {
  description: "How much memory do you need?",
  input: params.select({ "micro": 256, "chonky": 2048 }),
});

const extensions = defineList("EXTENSIONS", {
  description: "Which file types should be processed?",
  input: params.multiSelect(["jpg", "tiff", "png", "webp"]),
});

const storageBucket = defineString('BUCKET', {
  description: "This will automatically
populate the selector field with the deploying Cloud Project’s
storage buckets",
  input: params.PICK_STORAGE_BUCKET,
});

Pitón

from firebase_functions.params import (
    StringParam,
    ListParam,
    TextInput,
    SelectInput,
    SelectOptions,
    ResourceInput,
    ResourceType,
)

MIN_INSTANCES = IntParam("HELLO_WORLD_MIN_INSTANCES")

WELCOME_MESSAGE = StringParam(
    "WELCOME_MESSAGE",
    default="Hello World",
    description="The greeting that is returned to the caller of this function",
)

ONLY_PHONE_NUMBERS = StringParam(
    "PHONE_NUMBER",
    input=TextInput(
        validation_regex="\d{3}-\d{3}-\d{4}",
        validation_error_message="Please enter a phone number in the format XXX-YYY-XXX",
    ),
)

SELECT_OPTION = StringParam(
    "PARITY",
    input=SelectInput([SelectOptions(value="odd"), SelectOptions(value="even")]),
)

STORAGE_BUCKET = StringParam(
    "BUCKET",
    input=ResourceInput(type=ResourceType.STORAGE_BUCKET),
    description="This will automatically populate the selector field with the deploying Cloud Project's storage buckets",
)

Tipos de parámetros

La configuración parametrizada proporciona una escritura segura para los valores de los parámetros y también admite secretos de Cloud Secret Manager. Los tipos admitidos son:

  • Secreto
  • Cadena
  • Booleano
  • Entero
  • Flotar
  • Lista (Node.js)

Valores de parámetros y expresiones.

Firebase evalúa sus parámetros tanto en el momento de la implementación como mientras se ejecuta su función. Debido a estos entornos duales, se debe tener especial cuidado al comparar los valores de los parámetros y al usarlos para configurar las opciones de tiempo de ejecución para sus funciones.

Para pasar un parámetro a su función como una opción de tiempo de ejecución, páselo directamente:

Nodo.js

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

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

Pitón

from firebase_functions import https_fn
from firebase_functions.params import IntParam

MIN_INSTANCES = IntParam("HELLO_WORLD_MIN_INSTANCES")

@https_fn.on_request(min_instances=MIN_INSTANCES)
def hello_world(req):
    ...

Además, si necesita comparar con un parámetro para saber qué opción elegir, deberá usar comparadores integrados en lugar de verificar el valor:

Nodo.js

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

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

Pitón

from firebase_functions import https_fn
from firebase_functions.params import IntParam, StringParam

ENVIRONMENT = StringParam("ENVIRONMENT", default="dev")
MIN_INSTANCES = ENVIRONMENT.equals("PRODUCTION").then(10, 0)

@https_fn.on_request(min_instances=MIN_INSTANCES)
def hello_world(req):
    ...

Se puede acceder a los parámetros y expresiones de parámetros que solo se usan en tiempo de ejecución con su función value :

Nodo.js

const { onRequest } = require('firebase-functions/v2/https');
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 = onRequest(
(req, res) => {
    res.send(`${welcomeMessage.value()}! I am a function.`);
  }
);

Pitón

from firebase_functions import https_fn
from firebase_functions.params import StringParam

WELCOME_MESSAGE = StringParam("WELCOME_MESSAGE")

@https_fn.on_request()
def hello_world(req):
    return https_fn.Response(f'{WELCOME_MESSAGE.value()}! I am a function!')

Parámetros incorporados

El SDK de Cloud Functions ofrece tres parámetros predefinidos, disponibles en el subpaquete firebase-functions/params :

Nodo.js

  • projectID : el proyecto de nube en el que se ejecuta la función.
  • databaseURL : la URL de la instancia de Realtime Database asociada con la función (si está habilitada en el proyecto de Firebase).
  • storageBucket : el depósito de Cloud Storage asociado con la función (si está habilitado en el proyecto de Firebase).

Pitón

  • PROJECT_ID : el proyecto de nube en el que se ejecuta la función.
  • DATABASE_URL : la URL de la instancia de Realtime Database asociada con la función (si está habilitada en el proyecto de Firebase).
  • STORAGE_BUCKET : el depósito de Cloud Storage asociado con la función (si está habilitado en el proyecto de Firebase).

Estos funcionan como parámetros de cadena definidos por el usuario en todos los aspectos, excepto que, dado que Firebase CLI siempre conoce sus valores, sus valores nunca se solicitarán durante la implementación ni se guardarán en archivos .env .

Parámetros secretos

Los parámetros de tipo Secret , definidos mediante defineSecret() , representan parámetros de cadena que tienen un valor almacenado en Cloud Secret Manager. En lugar de compararlo con un archivo .env local y escribir un nuevo valor en el archivo si falta, los parámetros secretos verifican su existencia en Cloud Secret Manager y solicitan interactivamente el valor de un nuevo secreto durante la implementación.

Los parámetros secretos definidos de esta manera deben estar vinculados a funciones individuales que deberían tener acceso a ellos:

Nodo.js

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

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

Pitón

from firebase_functions import https_fn
from firebase_functions.params import SecretParam

DISCORD_API_KEY = SecretParam('DISCORD_API_KEY');

@https_fn.on_request(secrets=[DISCORD_API_KEY])
def post_to_discord(req):
    api_key = DISCORD_API_KEY.value()

Debido a que los valores de los secretos están ocultos hasta la ejecución de la función, no puede usarlos mientras configura su función.

Variables de entorno

Cloud Functions para Firebase admite el formato de archivo dotenv para cargar variables de entorno especificadas en un archivo .env en el tiempo de ejecución de su aplicación. Una vez implementadas, las variables de entorno se pueden leer a través de la interfaz process.env (en proyectos basados ​​en Node.js) u os.environ (en proyectos basados ​​en Python).

Para configurar su entorno de esta manera, cree un archivo .env en su proyecto, agregue las variables deseadas e implemente:

  1. Cree un archivo .env en su directorio functions/ :

    # Directory layout:
    #   my-project/
    #     firebase.json
    #     functions/
    #       .env
    #       package.json
    #       index.js
    
  2. Abra el archivo .env para editarlo y agregue las claves deseadas. Por ejemplo:

    PLANET=Earth
    AUDIENCE=Humans
    
  3. Implemente funciones y verifique que se hayan cargado las variables de entorno:

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

Una vez que se implementan sus variables de entorno personalizadas, su código de función puede acceder a ellas:

Nodo.js

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

Pitón

import os

@https_fn.on_request()
def hello(req):
    return https_fn.Response(
        f"Hello {os.environ.get('PLANET')} and {os.environ.get('AUDIENCE')}"
    )

Implementar múltiples conjuntos de variables de entorno

Si necesita un conjunto alternativo de variables de entorno para sus proyectos de Firebase (como ensayo o producción), cree un .env. <project or alias > y escriba allí las variables de entorno específicas del proyecto. Las variables de entorno de .env archivos .env y específicos del proyecto (si existen) se incluirán en todas las funciones implementadas.

Por ejemplo, un proyecto podría incluir estos tres archivos que contienen valores ligeramente diferentes para desarrollo y producción:

.env .env.dev .env.prod
PLANETA=Tierra

AUDIENCIA=Humanos

AUDIENCIA=Desarrolladores humanos AUDIENCIA=Prod humanos

Dados los valores en esos archivos separados, el conjunto de variables de entorno implementadas con sus funciones variará según su proyecto de destino:

$ 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

Variables de entorno reservadas

Algunas claves de variables de entorno están reservadas para uso interno. No utilice ninguna de estas claves en sus archivos .env :

  • Todas las claves que comienzan con X_GOOGLE_
  • Todas las claves que comienzan con EXT_
  • Todas las claves que comienzan con FIREBASE_
  • Cualquier clave de la siguiente lista:
  • NUBE_RUNTIME_CONFIG
  • PUNTO DE ENTRADA
  • GCP_PROJECT
  • GCLOUD_PROJECT
  • GOOGLE_CLOUD_PROJECT
  • FUNCTION_TRIGGER_TYPE
  • NOMBRE DE LA FUNCIÓN
  • FUNCTION_MEMORY_MB
  • FUNCTION_TIMEOUT_SEC
  • FUNCIÓN_IDENTIDAD
  • FUNCTION_REGION
  • FUNCTION_TARGET
  • FUNCTION_SIGNATURE_TYPE
  • K_SERVICIO
  • K_REVISION
  • PUERTO
  • K_CONFIGURACIÓN

Almacene y acceda a información de configuración confidencial

Las variables de entorno almacenadas en archivos .env se pueden utilizar para la configuración de funciones, pero no debe considerarlas una forma segura de almacenar información confidencial, como credenciales de bases de datos o claves API. Esto es especialmente importante si verifica sus archivos .env en el control de fuente.

Para ayudarlo a almacenar información de configuración confidencial, Cloud Functions para Firebase se integra con Google Cloud Secret Manager . Este servicio cifrado almacena los valores de configuración de forma segura y, al mismo tiempo, permite un fácil acceso desde sus funciones cuando sea necesario.

Crear y usar un secreto

Para crear un secreto, use Firebase CLI.

Para crear y utilizar un secreto:

  1. Desde la raíz del directorio de su proyecto local, ejecute el siguiente comando:

    firebase functions:secrets:set SECRET_NAME

  2. Introduzca un valor para SECRET_NAME .

    La CLI muestra un mensaje de éxito y advierte que debe implementar funciones para que el cambio surta efecto.

  3. Antes de implementar, asegúrese de que su código de funciones permita que la función acceda al secreto usando el parámetro runWith :

    Nodo.js

    const { onRequest } = require('firebase-functions/v2/https');
    
    exports.processPayment = onRequest(
      { secrets: ["SECRET_NAME"] },
      (req, res) => {
        const myBillingService = initializeBillingService(
          // reference the secret value
          process.env.SECRET_NAME
        );
        // Process the payment
      }
    );

    Pitón

    import os
    from firebase_functions import https_fn
    
    @https_fn.on_request(secrets=["SECRET_NAME"])
    def process_payment(req):
        myBillingService = initialize_billing(key=os.environ.get('SECRET_NAME'))
        # Process the payment
        ...
    
  4. Implementar funciones en la nube:

    firebase deploy --only functions

    Ahora podrá acceder a él como a cualquier otra variable de entorno. Por el contrario, si otra función que no especifica el secreto en runWith intenta acceder al secreto, recibe un valor indefinido:

    Nodo.js

    exports.anotherEndpoint = 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
    });
    

    Pitón

    @https_fn.on_request()
    def another_endpoint(req):
        return https_fn.Response(f"The secret API key is {os.environ.get("SECRET_NAME")}")
        # Responds with "The secret API key is None" because the `secrets` parameter is missing.
    

Una vez implementada su función, tendrá acceso al valor secreto. Sólo las funciones que incluyen específicamente un secreto en su parámetro runWith tendrán acceso a ese secreto como variable de entorno. Esto le ayuda a asegurarse de que los valores secretos solo estén disponibles cuando sean necesarios, lo que reduce el riesgo de filtrar un secreto accidentalmente.

Manejando secretos

Utilice Firebase CLI para administrar sus secretos. Al administrar secretos de esta manera, tenga en cuenta que algunos cambios de CLI requieren que modifique y/o vuelva a implementar funciones asociadas. Específicamente:

  • Siempre que establezca un nuevo valor para un secreto, debe volver a implementar todas las funciones que hacen referencia a ese secreto para que recojan el valor más reciente.
  • Si elimina un secreto, asegúrese de que ninguna de las funciones implementadas haga referencia a ese secreto. Las funciones que utilizan un valor secreto que se ha eliminado fallarán silenciosamente.

A continuación se muestra un resumen de los comandos de Firebase CLI para la administración de secretos:

# 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

Para los comandos access y destroy , puede proporcionar el parámetro de versión opcional para administrar una versión particular. Por ejemplo:

functions:secrets:access SECRET_NAME[@VERSION]

Para obtener más información sobre estas operaciones, pase -h con el comando para ver la ayuda de CLI.

Cómo se facturan los secretos

Secret Manager permite 6 versiones secretas activas sin costo. Esto significa que puedes tener 6 secretos por mes en un proyecto de Firebase sin costo alguno.

De forma predeterminada, Firebase CLI intenta destruir automáticamente las versiones secretas no utilizadas cuando corresponde, como cuando implementas funciones con una nueva versión del secreto. Además, puede limpiar activamente los secretos no utilizados utilizando functions:secrets:destroy y functions:secrets:prune .

Secret Manager permite 10.000 operaciones de acceso mensuales no facturadas a un secreto. Las instancias de función leen solo los secretos especificados en su parámetro runWith cada vez que se inician en frío. Si tiene muchas instancias de funciones que leen muchos secretos, su proyecto puede exceder esta asignación, momento en el que se le cobrarán $0,03 por cada 10 000 operaciones de acceso.

Para obtener más información, consulte Precios de Secret Manager .

Soporte de emulador

La configuración del entorno con dotenv está diseñada para interoperar con un emulador local de Cloud Functions .

Cuando utiliza un emulador local de Cloud Functions, puede anular las variables de entorno de su proyecto configurando un archivo .env.local . El contenido de .env.local tiene prioridad sobre .env y el archivo .env específico del proyecto.

Por ejemplo, un proyecto podría incluir estos tres archivos que contienen valores ligeramente diferentes para el desarrollo y las pruebas locales:

.env .env.dev .env.local
PLANETA=Tierra

AUDIENCIA=Humanos

AUDIENCIA=Desarrolladores humanos AUDIENCIA = Humanos locales

Cuando se inicia en el contexto local, el emulador carga las variables de entorno como se muestra:

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

Secretos y credenciales en el emulador de Cloud Functions

El emulador de Cloud Functions admite el uso de secretos para almacenar y acceder a información de configuración confidencial . De forma predeterminada, el emulador intentará acceder a sus secretos de producción utilizando las credenciales predeterminadas de la aplicación . En determinadas situaciones, como entornos de CI, es posible que el emulador no pueda acceder a valores secretos debido a restricciones de permisos.

De manera similar a la compatibilidad del emulador de Cloud Functions con variables de entorno, puede anular los valores secretos configurando un archivo .secret.local . Esto le facilita probar sus funciones localmente, especialmente si no tiene acceso al valor secreto.

Migrar desde la configuración del entorno

Si ha estado utilizando la configuración del entorno con functions.config , puede migrar su configuración existente como variables de entorno (en formato dotenv ). Firebase CLI proporciona un comando de exportación que genera la configuración de cada alias o proyecto enumerado en el archivo .firebaserc de su directorio (en el siguiente ejemplo, local , dev y prod ) como archivos .env .

Para migrar, exporte las configuraciones de su entorno existente usando el 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

Tenga en cuenta que, en algunos casos, se le pedirá que ingrese un prefijo para cambiar el nombre de las claves de las variables de entorno exportadas. Esto se debe a que no todas las configuraciones se pueden transformar automáticamente, ya que pueden no ser válidas o pueden ser una clave de variable de entorno reservada .

Le recomendamos que revise cuidadosamente el contenido de los archivos .env generados antes de implementar sus funciones o verificar los archivos .env en el control de código fuente. Si algún valor es confidencial y no debe filtrarse, elimínelo de sus archivos .env y guárdelo de forma segura en Secret Manager .

También necesitarás actualizar tu código de funciones. Cualquier función que use functions.config ahora deberá usar process.env en su lugar, como se muestra en Variables de entorno .