2

Gday,

Quite new to TS and only got a little bit of experience with backend in general, so apologies if I am completely missing the idea.

So I really like the idea of using Google Secret Manager instead of custom env config for Firebase Functions.

Below is all done within a config.ts within my functions dir.

I need to initialize stripe. Traditional tutorials say to do something like the below example:

import Stripe from 'stripe';
export const stripeSecret = functions.config().stripe.secret;

const stripe = new Stripe(stripeSecret, {apiVersion: '2020-08-27'});

I think it would be ideal to change it to this:

import Stripe from 'stripe'
import {SecretManagerServiceClient} from '@google-cloud/secret-manager';
export async function getSecret(name:string){
    const [version] = await secrets.accessSecretVersion({
        name: `projects/example/secrets/${name}/versions/latest`,
    });
    return version.payload?.data?.toString();
}

export const stripeSecret = await getSecret("Stripe-API")
const stripe = new Stripe(stripeSecret, {apiVersion: '2020-08-27'});

But this causes an issue with it being async/await on the top level.

What are my options here and what is best practice?

MasterEnzo
  • 71
  • 2
  • 7
  • Note that the [doc](https://firebase.google.com/docs/functions/config-env#secret-manager) advises to allow a Cloud Function to access the secret using the `runWith()` parameter in such a way that "only functions that specifically include a secret in their `runWith()` parameter will have access to that secret as an environment variable". – Renaud Tarnec May 30 '22 at 11:53

1 Answers1

4

The Google Secret manager is a useful utility and below are a few best practices when using Secret Manager.

You may try and use following to create and use a secret:

  1. From the root of your local project directory, run the following command:

    firebase functions:secrets:set SECRET_NAME

  2. Enter a value for SECRET_NAME.

    The CLI echoes a success message and warns that you must deploy functions for the change to take effect.

  3. Before deploying, make sure your functions code allows the function to access the secret using the runWith parameter:

        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});
  1. Deploy Cloud Functions:

    firebase deploy --only functions

You can also access it like any other environment variable. Conversely, if another function that does not specify the secret in runWith tries to access the secret, it receives an undefined value:

To see the complete best practices list, please visit the next link [1] and to know more about managing secret versions, please take a look at the next link [2].

[1] https://cloud.google.com/secret-manager/docs/best-practices

[2] https://cloud.google.com/secret-manager/docs/managing-secret-versions

Vaidehi Jamankar
  • 1,232
  • 1
  • 2
  • 10
  • What's the difference between using `const myApiKey = defineSecret('MY_API_KEY'); functions.runWith({ secrets: [myApiKey] }).https. ...` and only using `functions.runWith({ secrets: ["MY_API_KEY"] }).https. ...`? The docs mention both but I could not find the difference / when to use which variant. – sceee Dec 07 '22 at 15:40
  • My answer is based on the docs alone (https://firebase.google.com/docs/functions/config-env). `defineSecret` approach would prompt for a secret value interactively on deployment. The other approach implies setting the secret yourself in a different manner, in Google Cloud console or the way described above. – NeverwinterMoon Jan 10 '23 at 09:15
  • What if the function is a scheduler? Like: `export const nameFunction = functions .region(...regions) .runWith({ timeoutSeconds: 540, memory: '128MB', secrets: ['CRON'], }) .pubsub.schedule(process.env.CRON as string) .timeZone('Europe/Copenhagen') .onRun(async (context) => {` – Nino Matos May 11 '23 at 07:13