A menudo, necesitarás una configuración adicional para tus funciones, como claves de API de terceros o una configuración ajustable. 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 tu proyecto.
Puedes elegir entre las siguientes opciones:
- La configuración con parámetros (recomendada para la mayoría de las situaciones) proporciona una configuración de entorno de tipo fuerte con parámetros que se validan en el momento de la implementación, lo que evita errores y simplifica la depuración.
- La configuración basada en archivos de las variables de entorno implica la creación manual de un archivo dotenv para cargar variables de entorno.
En la mayoría de los casos de uso, se recomienda la configuración con parámetros. Este enfoque hace que los valores de configuración estén disponibles durante los tiempos de ejecución e implementación. Además, 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 durante el tiempo de implementación.
Configuración con parámetros
Cloud Functions for Firebase proporciona una interfaz para definir parámetros de configuración de forma declarativa dentro de tu base de código. El valor de estos parámetros está disponible durante la implementación de funciones, cuando se configuran las opciones de implementación y entorno de ejecución, y 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.
Node.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.`);
}
);
Python
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!')
Cuando se implementa una función con variables de configuración que tengan parámetros,
Firebase CLI primero intenta cargar sus valores desde los archivos .env locales. Si
no están presentes en esos archivos y no se configura default
, la CLI solicitará
los valores durante la implementación y, luego, los guardará automáticamente en un
archivo .env
llamado .env.<project_ID>
en tu 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
Según tu flujo de trabajo de desarrollo, puede ser útil agregar el archivo .env.<project_ID>
generado al control de versión.
Usa parámetros en el permiso global
Durante la implementación, el código de tus funciones se carga y se inspecciona antes de que los
parámetros tengan valores reales. Esto significa que recuperar valores de parámetros durante
el permiso global genera un error de implementación. En los casos en los que desees usar un
parámetro para inicializar un valor global, usa la devolución de llamada de inicialización
onInit()
. Esta devolución de llamada se ejecuta antes de que se ejecuten las funciones en producción, pero no
se la llama durante el tiempo de implementación, por lo que es un lugar seguro para acceder al valor de
un parámetro.
Node.js
const { GoogleGenerativeAI } = require('@google/generative-ai');
const { defineSecret } = require('firebase-functions/params');
const { onInit } = require('firebase-functions/v2/core');
const apiKey = defineSecret('GOOGLE_API_KEY');
let genAI;
onInit(() => {
genAI = new GoogleGenerativeAI(apiKey.value());
})
Python
from firebase_functions.core import init
from firebase_functions.params import StringParam, PROJECT_ID
import firebase_admin
import vertexai
location = StringParam("LOCATION")
x = "hello"
@init
def initialize():
# Note: to write back to a global, you'll need to use the "global" keyword
# to avoid creating a new local with the same name.
global x
x = "world"
firebase_admin.initialize_app()
vertexai.init(PROJECT_ID.value, location.value)
Si usas parámetros del tipo Secret
, ten en cuenta que solo están disponibles
en el proceso de las funciones que vincularon el secreto. Si un secreto está vinculado
solo en algunas funciones, verifica si secret.value()
es falso antes de usarlo.
Configura el comportamiento de la CLI
Los parámetros se pueden configurar con un objeto Options
que controle cómo la CLI
solicitará valores. En el siguiente ejemplo, se configuran opciones para validar el
formato de un número de teléfono, proporcionar una opción de selección simple y
propagar una opción de selección automáticamente desde el proyecto de Firebase:
Node.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,
});
Python
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 valores de parámetros de tipo fuerte, y también admite secretos de Cloud Secret Manager. Los tipos admitidos son los siguientes:
- Secreto
- String
- Booleano
- Número entero
- Número de punto flotante
- Lista (Node.js)
Expresiones y valores de parámetros
Firebase evalúa tus parámetros en el momento de la implementación y mientras se ejecuta tu función. Debido a estos entornos duales, se debe tener especial cuidado a la hora de comparar valores de parámetros y de usarlos para establecer opciones del entorno de ejecución de las funciones.
Para pasar un parámetro a tu función como una opción del entorno de ejecución, hazlo directamente:
Node.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) => {
//…
Python
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 necesitas comparar con un parámetro para saber qué opción elegir, deberás usar comparadores integrados en lugar de verificar el valor:
Node.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) => {
//…
Python
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 las expresiones de parámetros que solo se usan en el entorno de ejecución
con su función value
:
Node.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.`);
}
);
Python
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 integrados
El SDK de Cloud Functions ofrece tres parámetros predefinidos, disponibles en el
subpaquete firebase-functions/params
:
Node.js
projectID
: Es el proyecto de Cloud en el que se ejecuta la función.databaseURL
: Es la URL de la instancia de Realtime Database asociada a la función (si está habilitada en el proyecto de Firebase).storageBucket
: Es el bucket de Cloud Storage asociado con la función (si está habilitado en el proyecto de Firebase).
Python
PROJECT_ID
: Es el proyecto de Cloud en el que se ejecuta la función.DATABASE_URL
: Es la URL de la instancia de Realtime Database asociada a la función (si está habilitada en el proyecto de Firebase).STORAGE_BUCKET
: Es el bucket de Cloud Storage asociado con la función (si está habilitado en el proyecto de Firebase).
Funcionan como parámetros de cadena definidos
por el usuario en todo sentido, excepto que Firebase CLI siempre conoce
sus valores. Estos valores nunca se solicitarán durante la implementación ni se guardarán en
los archivos .env
.
Parámetros secretos
Los parámetros de tipo Secret
, definidos mediante defineSecret()
, representan parámetros
de string que tienen un valor almacenado en Cloud Secret Manager. En vez de comprobar un archivo local .env
y escribir un nuevo valor en el archivo si falta, los parámetros secretos comprueban la 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 vincularse a funciones individuales que deben tener acceso a ellos:
Node.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();
//…
Python
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 puedes usarlos mientras la configuras.
Variables de entorno
Cloud Functions for Firebase admite el
formato de archivo
dotenv para cargar variables de entorno especificadas en un archivo .env
en el entorno de
ejecución de la aplicación. Una vez que se implementan, estas variables de entorno se pueden leer a través de la interfaz
process.env
(en proyectos basados en Node.js) o
os.environ
(en
proyectos basados en Python).
Para configurar tu entorno de esta manera, crea un archivo .env
en tu proyecto,
agrega las variables que desees y, luego, implementa como se describe a continuación:
Crea un archivo
.env
en tu directoriofunctions/
:# Directory layout: # my-project/ # firebase.json # functions/ # .env # package.json # index.js
Abre el archivo
.env
para editarlo y agrega las claves que desees. Por ejemplo:PLANET=Earth AUDIENCE=Humans
Implementa funciones y verifica que se hayan cargado las variables de entorno:
firebase deploy --only functions # ... # i functions: Loaded environment variables from .env. # ...
Una vez que se implementen las variables de entorno personalizadas, el código de la función podrá acceder a ellas:
Node.js
// Responds with "Hello Earth and Humans"
exports.hello = onRequest((request, response) => {
response.send(`Hello ${process.env.PLANET} and ${process.env.AUDIENCE}`);
});
Python
import os
@https_fn.on_request()
def hello(req):
return https_fn.Response(
f"Hello {os.environ.get('PLANET')} and {os.environ.get('AUDIENCE')}"
)
Implementa varios conjuntos de variables de entorno
Si necesitas un conjunto alternativo de variables de entorno para tus proyectos
de Firebase (como los de etapa de pruebas y los de producción), crea un
archivo .env.<project or
alias>
y escribe allí las
variables específicas del proyecto. Si existen variables de entorno de
.env
y archivos .env
específicos del proyecto,
se incluirán en todas las funciones que se implementen.
Por ejemplo, un proyecto podría incluir estos tres archivos que contienen valores ligeramente distintos para el desarrollo y la producción:
.env
|
.env.dev
|
.env.prod
|
PLANET=Earth
AUDIENCE=Humans |
AUDIENCE=Dev Humans | AUDIENCE=Prod Humans |
Dados los valores en esos archivos separados, el conjunto de variables de entorno que se implementen con las funciones variará según el 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 uses ninguna de
las siguientes claves en los 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:
- 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
Almacena información de configuración sensible y accede a ella
Las variables de entorno que se almacenan en archivos .env
se pueden usar para configurar
funciones, pero no debes considerarlas como una forma segura de almacenar información sensible,
como las credenciales de la base de datos o las claves de API. Esto es muy importante
si revisas tus archivos .env
en el control de la fuente.
Para ayudarte a almacenar esta información de configuración sensible, Cloud Functions for Firebase se integra en Google Cloud Secret Manager. Este servicio encriptado almacena valores de configuración de manera segura y, a la vez, te permite acceder a ellos fácilmente desde tus funciones cuando sea necesario.
Crea y usa un secreto
Usa Firebase CLI para crear un secreto.
Si quieres crear y usar un secreto, sigue estos pasos:
Desde la raíz del directorio del proyecto local, ejecuta el siguiente comando:
firebase functions:secrets:set SECRET_NAME
Ingresa un valor para SECRET_NAME.
La CLI repite un mensaje de éxito y advierte que debes implementar funciones para que se efectúe el cambio.
Antes de la implementación, asegúrate de que el código de las funciones permita que se acceda al secreto mediante el parámetro
runWith
:Node.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 } );
Python
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 ...
Realiza la implementación de Cloud Functions:
firebase deploy --only functions
Ahora podrás acceder a él como a cualquier otra variable de entorno. Sin embargo, si otra función que no especifica el secreto en
runWith
intenta acceder a este, recibe un valor indefinido:Node.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 });
Python
@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 que se implemente la función, tendrá acceso al valor del secreto. Solo
las funciones que incluyen específicamente un secreto en su parámetro runWith
tendrán
acceso a él como una variable de entorno. Esto te garantiza
que los valores de los secretos solo estén disponibles donde sean necesarios, lo que reduce el riesgo de
filtrar uno por accidente.
Administra secretos
Usa Firebase CLI para administrar tus secretos. Cuando administres secretos de esta manera, ten en cuenta que algunos cambios de la CLI requieren que modifiques o vuelvas a implementar funciones asociadas. En particular, haz lo siguiente:
- Cada vez que configuras un valor nuevo para un secreto, debes volver a implementar todas las funciones que hagan referencia a este para captar el valor más reciente.
- Si borras un secreto, asegúrate de que ninguna de las funciones que se implementaron haga referencia a este. Las funciones que usen un valor del secreto que se borró fallarán silenciosamente.
Este es 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
, puedes proporcionar el parámetro de versión
opcional para administrar una en particular. Por ejemplo:
functions:secrets:access SECRET_NAME[@VERSION]
Si quieres obtener más información sobre estas operaciones, pasa -h
con el comando para
consultar la ayuda de la CLI.
Cómo se facturan los secretos
Secret Manager permite 6 versiones activas de secretos sin costo. Esto significa que puedes tener 6 secretos por mes en un proyecto de Firebase sin costo.
Según la configuración predeterminada, Firebase CLI intenta destruir automáticamente las versiones de los secretos
sin usar cuando corresponda, como cuando implementas funciones con una versión nueva
del secreto. Además, puedes limpiar activamente aquellos sin usar con
functions:secrets:destroy
y functions:secrets:prune
.
Secret Manager permite 10,000 operaciones de acceso mensual sin facturar en un
secreto. Las instancias de función solo leen los secretos especificados en su parámetro runWith
cada vez que se inician en frío. Si tienes varias instancias de función
que leen muchos secretos, es posible que tu proyecto exceda este permiso. En ese momento,
se te cobrarán $0.03 cada 10,000 operaciones de acceso.
Para obtener más información, consulta PreciosSecret Manager.
Compatibilidad con el emulador
La configuración del entorno con dotenv está diseñada para interoperar con un emulador de Cloud Functions local.
Cuando usas un emulador de Cloud Functions local, puedes anular las variables
de entorno del 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 distintos para el desarrollo y las pruebas locales:
.env
|
.env.dev
|
.env.local
|
PLANET=Earth
AUDIENCE=Humans |
AUDIENCE=Dev Humans | AUDIENCE=Local Humans |
Cuando se inicia en el contexto local, el emulador carga las variables de entorno como se muestra a continuación:
$ 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 información de configuración sensible y acceder a ella. De forma predeterminada, el emulador intentará acceder a los secretos de producción con las credenciales predeterminadas de la aplicación. En algunas situaciones, como los entornos de CI, es posible que el emulador no pueda acceder a los valores de los secretos debido a restricciones de permisos.
De manera similar a la compatibilidad del emulador de Cloud Functions con las variables de entorno, puedes
anular los valores de los secretos con la configuración de un archivo .secret.local
. Esto te permite
probar las funciones de forma local, en particular, si no tienes acceso
al valor del secreto.
Migra desde la configuración del entorno
Si usaste la configuración del entorno con functions.config
, puedes
migrar tu configuración existente como variables de entorno (en formato
dotenv).
Firebase CLI proporciona un comando de exportación que muestra la configuración
de cada alias o proyecto que aparece en el directorio del archivo .firebaserc
(en el siguiente ejemplo, local
, dev
y prod
) como archivos .env
.
Para migrar, exporta la configuración del entorno existente con 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
Ten en cuenta que, en algunos casos, se te pedirá que ingreses un prefijo para cambiar el nombre de las claves de variable de entorno que se exportaron. Esto se debe a que no todas las opciones de configuración se pueden transformar automáticamente, ya que puede que no sean válidas o sean una clave de variable de entorno reservada.
Te recomendamos que revises con detenimiento el contenido de los archivos .env
que se generaron antes de implementar las funciones o que revises los archivos .env
en el control de la fuente. Si
algún valor es sensible y no se debe filtrar, quítalo de los archivos .env
y almacénalo de forma segura en
Secret Manager.
También debes actualizar el código de las funciones. Cualquiera que use
functions.config
ahora deberá usar process.env
, como se indica en
Variables de entorno.