Mengonfigurasi lingkungan Anda

Sering kali fungsi Anda memerlukan konfigurasi tambahan, seperti kunci API pihak ketiga atau setelan yang dapat disesuaikan. Firebase SDK untuk Cloud Functions menawarkan konfigurasi lingkungan bawaan untuk memudahkan penyimpanan dan pengambilan jenis data ini untuk project Anda.

Anda dapat memilih antara konfigurasi berbasis file dari variabel lingkungan (direkomendasikan) atau konfigurasi lingkungan runtime dengan Firebase CLI dan functions.config. Kedua pendekatan tersebut dijelaskan dalam panduan ini.

Variabel lingkungan

Cloud Functions for Firebase mendukung format file dotenv untuk memuat variabel lingkungan yang ditentukan dalam file .env ke runtime aplikasi Anda. Setelah di-deploy, variabel lingkungan dapat dibaca melalui antarmuka process.env.

Untuk mengonfigurasi lingkungan dengan cara ini, buat file .env di project Anda, tambahkan variabel yang diinginkan, dan deploy:

  1. Buat file .env di direktori functions/ Anda:

    # Directory layout:
    #   my-project/
    #     firebase.json
    #     functions/
    #       .env
    #       package.json
    #       index.js
    
  2. Buka file .env untuk mengedit, lalu tambahkan kunci yang diinginkan. Contoh:

    PLANET=Earth
    AUDIENCE=Humans
    
  3. Deploy fungsi dan pastikan variabel lingkungan telah dimuat:

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

Setelah variabel lingkungan kustom di-deploy, kode fungsi Anda dapat mengaksesnya dengan sintaksis 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}`);
});

Men-deploy beberapa kumpulan variabel lingkungan

Jika Anda memerlukan kumpulan variabel lingkungan alternatif untuk project Firebase (seperti staging vs. produksi), buat file .env.<project or alias> dan tulis variabel lingkungan khusus project di sana. Variabel lingkungan dari .env dan file .env khusus project (jika ada) akan disertakan dalam semua fungsi yang di-deploy.

Misalnya, project dapat menyertakan tiga file ini yang berisi nilai yang sedikit berbeda untuk pengembangan dan produksi:

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

AUDIENCE=Humans

AUDIENCE=Dev Humans AUDIENCE=Prod Humans

Mengingat nilai dalam file terpisah tersebut, kumpulan variabel lingkungan yang di-deploy dengan fungsi Anda akan bervariasi, bergantung pada project target:

$ 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

Variabel lingkungan yang dicadangkan

Beberapa kunci variabel lingkungan dicadangkan untuk penggunaan internal. Jangan gunakan kunci berikut dalam file .env Anda:

  • Semua kunci yang dimulai dengan X_GOOGLE_
  • Semua kunci yang dimulai dengan EXT_
  • Semua kunci yang dimulai dengan FIREBASE_
  • Kunci apa pun dari daftar berikut:
  • 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

Menyimpan dan mengakses informasi konfigurasi yang sensitif

Variabel lingkungan yang disimpan dalam file .env dapat digunakan untuk konfigurasi fungsi, tetapi tidak boleh dianggap sebagai cara yang aman untuk menyimpan informasi sensitif seperti kredensial database atau kunci API. Hal ini penting jika Anda melakukan check in file .env ke dalam kontrol sumber.

Untuk membantu Anda menyimpan informasi konfigurasi yang sensitif, Cloud Functions for Firebase terintegrasi dengan Google Cloud Secret Manager. Layanan terenkripsi ini menyimpan nilai konfigurasi dengan aman, sekaligus mengizinkan akses mudah dari fungsi Anda saat diperlukan.

Membuat dan menggunakan secret

Untuk membuat secret, gunakan Firebase CLI.

Untuk membuat dan menggunakan secret:

  1. Dari root direktori project lokal, jalankan perintah berikut:

    firebase functions:secrets:set SECRET_NAME

  2. Masukkan nilai untuk SECRET_NAME.

    CLI akan menampilkan pesan berhasil dan memperingatkan bahwa Anda harus men-deploy fungsi agar perubahan diterapkan.

  3. Sebelum men-deploy, pastikan kode fungsi Anda mengizinkan fungsi tersebut mengakses secret menggunakan parameter 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. Deploy Cloud Functions:

    firebase deploy --only functions

Sekarang Anda dapat mengaksesnya seperti variabel lingkungan lainnya. Sebaliknya, jika fungsi lain yang tidak menentukan secret dalam runWith mencoba mengakses secret, fungsi tersebut akan menerima nilai yang tidak ditentukan:

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

Setelah di-deploy, fungsi tersebut akan memiliki akses ke nilai secret. Hanya fungsi yang secara khusus menyertakan secret dalam parameter runWith-nya yang akan memiliki akses ke secret tersebut sebagai variabel lingkungan. Cara ini membantu Anda memastikan bahwa nilai secret hanya tersedia di tempat yang diperlukan, sehingga mengurangi risiko kebocoran secret secara tidak sengaja.

Mengelola secret

Gunakan Firebase CLI untuk mengelola secret Anda. Saat mengelola secret dengan cara ini, perlu diingat bahwa beberapa perubahan CLI mengharuskan Anda untuk mengubah dan/atau men-deploy ulang fungsi-fungsi terkait. Secara khusus:

  • Setiap kali Anda menetapkan nilai baru untuk secret, Anda harus men-deploy ulang semua fungsi yang merujuk ke secret tersebut agar fungsi dapat mengambil nilai terbaru.
  • Jika Anda menghapus secret, pastikan tidak ada satu pun fungsi yang di-deploy merujuk ke secret tersebut. Fungsi yang menggunakan nilai secret yang telah dihapus akan gagal tanpa ada peringatan.

Berikut adalah ringkasan perintah Firebase CLI untuk pengelolaan 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

Untuk perintah access dan destroy, Anda dapat memberikan parameter versi opsional untuk mengelola versi tertentu. Contoh:

functions:secrets:access SECRET_NAME[@VERSION]

Untuk mengetahui informasi selengkapnya tentang operasi ini, teruskan -h dengan perintah untuk melihat bantuan CLI.

Cara penagihan secret

Secret Manager mengizinkan 6 versi secret aktif tanpa biaya. Artinya, Anda dapat memiliki 6 secret per bulan di project Firebase tanpa biaya.

Secara default, Firebase CLI berupaya secara otomatis menghancurkan versi secret yang tidak digunakan jika perlu, seperti ketika Anda men-deploy fungsi dengan versi secret baru. Selain itu, Anda dapat secara aktif membersihkan secret yang tidak digunakan menggunakan functions:secrets:destroy dan functions:secrets:prune.

Secret Manager mengizinkan 10.000 operasi akses bulanan yang tidak ditagih untuk sebuah secret. Instance fungsi hanya membaca secret yang ditentukan dalam parameter runWith-nya setiap kali cold start dilakukan padanya. Jika Anda memiliki banyak instance fungsi yang membaca banyak secret, project Anda dapat melebihi kuota ini, dan setelah itu Anda akan dikenai biaya $0,03 per 10.000 operasi akses.

Untuk mengetahui informasi selengkapnya, lihat Harga Secret Manager.

Dukungan emulator

Konfigurasi lingkungan dengan dotenv dirancang agar dapat saling beroperasi dengan emulator Cloud Functions lokal.

Saat menggunakan emulator Cloud Functions lokal, Anda dapat mengganti variabel lingkungan untuk project dengan menyiapkan file .env.local. Konten .env.local lebih diutamakan daripada .env dan file .env khusus project.

Misalnya, project dapat menyertakan tiga file ini yang berisi nilai yang sedikit berbeda untuk pengembangan dan pengujian lokal:

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

AUDIENCE=Humans

AUDIENCE=Dev Humans AUDIENCE=Local Humans

Saat dimulai dalam konteks lokal, emulator akan memuat variabel lingkungan seperti yang ditunjukkan berikut ini:

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

Secret dan kredensial di emulator Cloud Functions

Emulator Cloud Functions mendukung penggunaan secret untuk menyimpan dan mengakses informasi konfigurasi yang sensitif. Secara default, emulator akan mencoba mengakses secret produksi Anda menggunakan kredensial default aplikasi. Dalam situasi tertentu seperti lingkungan CI, emulator mungkin gagal mengakses nilai secret karena pembatasan izin.

Serupa dengan dukungan emulator Cloud Functions untuk variabel lingkungan, Anda dapat mengganti nilai secret dengan menyiapkan file .secret.local. Hal ini memudahkan Anda untuk menguji fungsi secara lokal, terutama jika tidak memiliki akses ke nilai secret.

Bermigrasi dari konfigurasi lingkungan

Jika menggunakan konfigurasi lingkungan dengan functions.config, Anda dapat memigrasikan konfigurasi yang ada sebagai variabel lingkungan (dalam format dotenv). Firebase CLI menyediakan perintah ekspor yang menghasilkan output konfigurasi setiap alias atau project yang tercantum dalam file .firebaserc direktori Anda (dalam contoh di bawah, local, dev, dan prod) sebagai file .env.

Untuk melakukan migrasi, ekspor konfigurasi lingkungan yang ada menggunakan perintah 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

Perhatikan bahwa, dalam beberapa kasus, Anda akan diminta untuk memasukkan awalan guna mengganti nama kunci variabel lingkungan yang diekspor. Ini karena tidak semua konfigurasi dapat diubah secara otomatis karena mungkin tidak valid atau merupakan kunci variabel lingkungan yang dicadangkan.

Sebaiknya tinjau dengan cermat konten file .env yang dihasilkan sebelum men-deploy fungsi atau lakukan check in file .env ke dalam kontrol sumber. Jika ada nilai yang sensitif dan tidak boleh bocor, hapus nilai tersebut dari file .env Anda dan simpan dengan aman di Secret Manager.

Anda juga harus memperbarui kode fungsi. Setiap fungsi yang menggunakan functions.config sekarang harus menggunakan process.env, seperti yang ditunjukkan dalam Variabel lingkungan.

Konfigurasi lingkungan

Sebelum dukungan variabel lingkungan dirilis di firebase-functions v3.18.0, penggunaan functions.config() adalah pendekatan yang direkomendasikan untuk konfigurasi lingkungan. Pendekatan ini masih didukung, tetapi sebaiknya semua project baru menggunakan variabel lingkungan, karena lebih mudah digunakan dan meningkatkan portabilitas kode Anda.

Menyetel konfigurasi lingkungan dengan CLI

Untuk menyimpan data lingkungan, Anda dapat menggunakan perintah firebase functions:config:set di Firebase CLI. Setiap kunci dapat diberi namespace menggunakan titik untuk mengelompokkan konfigurasi yang terkait bersama-sama. Perlu diingat bahwa hanya karakter huruf kecil yang diterima untuk kunci; karakter huruf kapital tidak diizinkan.

Misalnya, untuk menyimpan Client ID dan kunci API untuk "Some Service", Anda dapat menjalankan:

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

Mengambil konfigurasi lingkungan saat ini

Untuk memeriksa apa yang saat ini disimpan di konfigurasi lingkungan untuk project Anda, Anda dapat menggunakan firebase functions:config:get. Perintah ini akan menampilkan JSON yang terlihat seperti ini:

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

Fungsionalitas ini didasarkan pada Google Cloud Runtime Configuration API.

Menggunakan functions.config untuk mengakses konfigurasi lingkungan dalam suatu fungsi

Beberapa konfigurasi disediakan secara otomatis di bawah namespace firebase yang dicadangkan. Konfigurasi lingkungan disediakan di dalam fungsi yang sedang berjalan melalui functions.config(). Untuk menggunakan konfigurasi tersebut, kode Anda dapat terlihat seperti ini:

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

Menggunakan konfigurasi lingkungan untuk melakukan inisialisasi modul

Beberapa modul Node siap digunakan tanpa konfigurasi apa pun. Modul yang lain memerlukan konfigurasi tambahan agar diinisialisasi dengan benar. Sebaiknya simpan konfigurasi ini di variabel konfigurasi lingkungan, bukan dengan melakukan hard-coding. Langkah ini membantu Anda mempertahankan kode agar jauh lebih portabel, sehingga Anda dapat membuat aplikasi menjadi open source atau mudah beralih antara versi produksi dan staging.

Misalnya, untuk menggunakan modul Slack Node SDK, Anda dapat menulis kode berikut:

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

Sebelum men-deploy, tetapkan variabel konfigurasi lingkungan slack.url:

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

Perintah Lingkungan Tambahan

  • firebase functions:config:unset key1 key2 menghapus kunci yang ditentukan dari konfigurasi
  • firebase functions:config:clone --from <fromProject> meng-clone lingkungan project lain ke dalam project yang sedang aktif.

Variabel lingkungan yang diisi secara otomatis

Ada variabel lingkungan yang diisi secara otomatis dalam runtime fungsi dan dalam fungsi yang diemulasikan secara lokal. Variabel lingkungan tersebut meliputi variabel lingkungan yang diisi oleh Google Cloud, serta variabel lingkungan khusus Firebase:

process.env.FIREBASE_CONFIG: Menyediakan info konfigurasi project Firebase berikut:

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

Konfigurasi ini diterapkan secara otomatis saat Anda menginisialisasi Firebase Admin SDK tanpa argumen. Jika menulis fungsi dalam JavaScript, lakukan inisialisasi seperti ini:

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

Jika Anda menulis fungsi di TypeScript, lakukan inisialisasi seperti ini:

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

Jika harus menginisialisasi Admin SDK dengan konfigurasi project default menggunakan kredensial akun layanan, Anda dapat memuat kredensial dari file dan menambahkannya ke FIREBASE_CONFIG seperti ini:

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

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