Configurar o ambiente

Muitas vezes, você precisará de configuração adicional para suas funções, como chaves de API de terceiros ou configurações ajustáveis. O SDK do Firebase para Cloud Functions oferece configuração de ambiente integrada para facilitar o armazenamento e a recuperação desses tipos de dados para seu projeto.

Escolha entre a configuração baseada em arquivos de variáveis de ambiente (recomendado) ou a configuração do ambiente de execução com a CLI do Firebase e functions.config. As duas abordagens são descritas neste guia.

Variáveis de ambiente

O Cloud Functions para Firebase suporta o formato de arquivo dotenv para carregar variáveis de ambiente especificadas em um arquivo .env no ambiente de execução do seu aplicativo. Depois de implantadas, as variáveis de ambiente podem ser lidas usando a interface process.env.

Para configurar o ambiente dessa maneira, crie um arquivo .env no projeto, adicione as variáveis desejadas e implante:

  1. Crie um arquivo .env no diretório functions/:

    # Directory layout:
    #   my-project/
    #     firebase.json
    #     functions/
    #       .env
    #       package.json
    #       index.js
    
  2. Abra o arquivo .env para editar e adicione as chaves desejadas. Exemplo:

    PLANET=Earth
    AUDIENCE=Humans
    
  3. Implante funções e verifique se as variáveis de ambiente foram carregadas:

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

Depois que as variáveis de ambiente personalizadas forem implantadas, o código da função poderá acessá-las com a sintaxe 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}`);
});

Como implantar vários conjuntos de variáveis de ambiente

Se você precisar de um conjunto alternativo de variáveis de ambiente para seus projetos do Firebase (como preparo x produção), crie um arquivo .env.<project or alias> e grave as variáveis específicas do projeto nele. As variáveis de ambiente de .env e arquivos específicos do projeto .env (se existirem) serão incluídos em todas as funções implantadas.

Por exemplo, um projeto pode incluir esses três arquivos com valores um pouco diferentes para desenvolvimento e produção:

.env .env.dev .env.prod
PLANET=Earth

AUDIENCE=Humans

AUDIENCE=Dev Humans AUDIENCE=Prod Humans

Considerando os valores nesses arquivos separados, o conjunto de variáveis de ambiente implantadas com suas funções varia de acordo com o projeto 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

Variáveis de ambiente reservadas

Algumas chaves de variáveis de ambiente são reservadas para uso interno. Não use nenhuma dessas chaves nos arquivos .env:

  • Todas as chaves que começam com X_GOOGLE_
  • Todas as chaves que começam com EXT_
  • Todas as chaves que começam com FIREBASE_
  • Qualquer chave da lista a seguir:
  • 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

Armazene e acesse informações de configuração confidenciais

Variáveis de ambiente armazenadas em arquivos .env podem ser usadas para configurar funções. No entanto, elas não devem ser consideradas uma maneira segura de armazenar informações confidenciais, como credenciais de banco de dados ou chaves de API. Isso é especialmente importante se você verificar seus arquivos .env no controle da origem.

Para ajudar você a armazenar informações de configuração confidenciais, o Cloud Functions para Firebase se integra ao Secret Manager do Google Cloud. Esse serviço criptografado armazena valores de configuração com segurança e ainda facilita o acesso das suas funções quando necessário.

Criar e usar um secret

Para criar um secret, use a CLI do Firebase.

.

Para criar e usar um secret, siga as instruções a seguir:

  1. Na raiz do diretório do projeto local, execute o seguinte comando:

    firebase functions:secrets:set SECRET_NAME

  2. Insira um valor para SECRET_NAME.

    A CLI gera uma mensagem de êxito e avisa que você precisa implantar funções para que a alteração entre em vigor.

  3. Antes da implantação, verifique se o código das funções permite o acesso ao secret usando o parâmetro 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. Implantar o Cloud Functions:

    firebase deploy --only functions

Agora você poderá acessá-lo como qualquer outra variável de ambiente. Por outro lado, se outra função que não especifica o secret em runWith tenta acessá-lo, ele recebe um valor indefinido:

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
});

A função terá acesso ao valor do secret depois que for implantada. Somente funções que incluem especificamente um secret no parâmetro runWith vão ter acesso a ele como uma variável de ambiente. Isso ajuda a garantir que os valores do secret fiquem disponíveis apenas quando necessários, reduzindo o risco de vazamentos acidentais.

Como gerenciar secrets

Use a CLI do Firebase para gerenciar seus secrets. Ao gerenciar secrets dessa maneira, lembre-se de que algumas alterações da CLI exigem que você modifique e/ou reimplante funções associadas. Especificamente:

  • Sempre que você definir um novo valor de secret, implante novamente todas as funções que fazem referência a esse secret para coletar o valor mais recente.
  • Se você excluir um secret, verifique se nenhuma das funções implantadas faz referência a ele. As funções que usam um valor do secret excluído vão falhar de maneira silenciosa.

Veja um resumo dos comandos da CLI do Firebase para gerenciamento de secrets:

# 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 os comandos access e destroy, é possível fornecer o parâmetro de versão opcional para gerenciar uma versão específica. Exemplo:

functions:secrets:access SECRET_NAME[@VERSION]

Para mais informações sobre essas operações, transmita -h com o comando para ver a ajuda da CLI.

Como é feito o faturamento dos secrets

O Secret Manager permite seis versões ativas do secret sem custos financeiros. Isso significa que é possível ter seis secrets por mês em um projeto do Firebase sem custos financeiros.

Por padrão, a CLI do Firebase tenta destruir automaticamente versões do secret não utilizadas quando apropriado, como quando você implanta funções com uma nova versão do secret. Além disso, é possível limpar ativamente os secrets não utilizados usando functions:secrets:destroy e functions:secrets:prune.

O Secret Manager permite 10.000 operações mensais de acesso não faturado em um secret. As instâncias de função leem somente os secrets especificados no parâmetro runWith sempre que iniciam a frio. Se você tiver muitas instâncias de função que leem muitos secrets, seu projeto poderá exceder essa permissão. A partir de então, será cobrado US $0,03 por 10.000 operações de acesso.

Para mais informações, consulte Preços do Secret Manager.

Suporte ao emulador

A configuração do ambiente com dotenv foi projetada para interoperar com um emulador local do Cloud Functions.

Ao usar um emulador local do Cloud Functions, é possível modificar as variáveis de ambiente para o projeto configurando um arquivo .env.local. O conteúdo de .env.local tem precedência sobre .env e sobre o arquivo .env específico do projeto.

Por exemplo, um projeto pode incluir esses três arquivos com valores um pouco diferentes para desenvolvimento e teste local:

.env .env.dev .env.local
PLANET=Earth

AUDIENCE=Humans

AUDIENCE=Dev Humans AUDIENCE=Local Humans

Quando iniciado no contexto local, o emulador carrega as variáveis de ambiente da seguinte maneira:

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

Secrets e credenciais no emulador do Cloud Functions

O emulador do Cloud Functions suporta o uso de secrets para armazenar e acessar informações de configuração confidenciais. Por padrão, o emulador tentará acessar seus secrets de produção usando credenciais padrão do aplicativo. Em determinadas situações, como ambientes de CI, o emulador pode não acessar valores do secret por causa de restrições de permissão.

Da mesma forma que o emulador do Cloud Functions suporta variáveis de ambiente, é possível substituir valores de secrets configurando um arquivo .secret.local. Isso facilita o teste local das funções, especialmente se você não tiver acesso ao valor do secret.

Como migrar da configuração do ambiente

Se você estiver usando a configuração do ambiente com functions.config, é possível migrar a configuração atual como variáveis de ambiente (no formato dotenv). A CLI do Firebase fornece um comando de exportação que gera a configuração de cada alias ou projeto listado no diretório do arquivo .firebaserc (no exemplo abaixo, local ,dev eprod ) como arquivos .env.

Para migrar, exporte as configurações do ambiente atuais usando o 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

Observe que, em alguns casos, você vai precisar inserir um prefixo para renomear as chaves de variáveis de ambiente exportadas. Isso ocorre porque nem todas as configurações podem ser transformadas automaticamente, já que podem ser inválidas ou serem chaves de variável de ambiente reservadas.

Recomendamos que você analise cuidadosamente o conteúdo dos arquivos .env gerados antes de implantar suas funções ou verifique os arquivos .env no controle de origem. Se os valores são confidenciais e não podem vazar, remova-os dos arquivos .env e armazene-os com segurança no Secret Manager.

Também é necessário atualizar seu código de funções. Agora, todas as funções que usam functions.config vão precisar usar process.env, conforme mostrado nas Variáveis de ambiente.

Configuração do ambiente

Antes do lançamento do suporte às variáveis de ambiente em firebase-functions v3.18.0, o uso de functions.config() era a abordagem recomendada para a configuração do ambiente. Essa abordagem ainda é suportada, mas recomendamos que todos os novos projetos usem variáveis de ambiente, porque são mais simples e melhoram a portabilidade do código.

Definir a configuração do ambiente com a CLI

Para armazenar dados do ambiente, use o comando firebase functions:config:set na CLI do Firebase. Cada chave pode receber um namespace com pontos para agrupar configurações relacionadas. Lembre-se de que somente caracteres minúsculos são aceitos nas chaves. Não são permitidos caracteres maiúsculos.

Por exemplo, para armazenar o ID do cliente e a chave de API para "Some Service", você pode executar:

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

Recuperar a configuração atual do ambiente

Para inspecionar o que está armazenado atualmente na configuração do ambiente do seu projeto, use firebase functions:config:get. Isso enviará ao JSON linhas com a seguinte aparência:

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

Essa funcionalidade é baseada na API Runtime Configuration do Google Cloud.

Usar functions.config para acessar a configuração do ambiente em uma função

Algumas configurações são fornecidas automaticamente no namespace firebase reservado. A configuração do ambiente é disponibilizada dentro da função em execução por meio de functions.config(). Para usar a configuração acima, seu código deve ter a seguinte aparência:

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}
  });
});

Usar configuração do ambiente para inicializar um módulo

Alguns módulos de nós estão prontos sem qualquer configuração. Outros módulos precisam de configuração extra para serem inicializados corretamente. Recomendamos que você armazene essa configuração em variáveis de configuração do ambiente, em vez de codificá-la. Isso ajuda você a manter a disponibilidade do seu código, o que permite abrir o código-fonte do seu aplicativo ou alternar facilmente as versões de produção e preparo.

Por exemplo, para usar o módulo Slack Node SDK, convém escrever:

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

Antes da implantação, defina a variável de configuração do ambiente slack.url:

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

Comandos de ambiente adicionais

  • firebase functions:config:unset key1 key2 remove as chaves especificadas da configuração
  • firebase functions:config:clone --from <fromProject> clona o ambiente de outro projeto no projeto ativo no momento.

Variáveis ​​de ambiente preenchidas automaticamente

Existem variáveis ​​de ambiente que são automaticamente preenchidas no ambiente de execução das funções e nas funções emuladas localmente. Isso inclui os preenchimentos do Google Cloud, além de uma variável de ambiente específica do Firebase:

process.env.FIREBASE_CONFIG: fornece as seguintes informações de configuração do projeto do Firebase:

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

Essa configuração é aplicada automaticamente quando você inicializa o SDK Admin do Firebase sem argumentos. Se você estiver escrevendo funções em JavaScript, inicialize deste modo:

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

Se você estiver escrevendo funções no TypeScript, inicialize deste modo:

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

Se você precisar inicializar o SDK Admin com a configuração do projeto padrão usando as credenciais da conta de serviço, poderá carregar as credenciais de um arquivo e adicioná-las ao FIREBASE_CONFIG da seguinte maneira:

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

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