Firebase Functions environment variables - node.js

So i was migrating my app from node express to firebase-functions!
In my node-express app I have .env file which contains all the data, FOr starters let's consider this as my .env file
GOOGLE_CLIENT_ID = 4046108-bssbfjohpj94l0dhpu69vpgs1ne0.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET = lTQHpj3yY57oQpO
And then in my passport strategy, I have something like this
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "/auth/google/callback",
userProfileURL: 'https://www.googleapis.com/oauth2/v3/userinfo',
accessType: 'offline',
passReqToCallback: true
},
Now,
Question: 1 - Firebase-functions probably don't support .env file, so can we set env variable without manually adding it using set flag? let's say I have lot variable in my environment
Question - 2: Can I access the variable I set by doing something like this
firebase functions:config:set slack.url=https://hooks.slack.com/services/XXX
using
process.env.slack.url
or we have to do (necessary)
functions.config().slack.url
Question:3 From Firebase Docs, it is written
There are environment variables that are automatically populated in
the functions runtime and in locally emulated functions, including:
process.env.GCLOUD_PROJECT: Provides the Firebase project ID
process.env.FIREBASE_CONFIG: Provides the following Firebase project
config info:
What do they mean when they mean? and if the answer to the question two is false then how are they using process.env.FIREBASE_CONFIG:

Answer for question 1:
Please note that, at this time, there doesn't appear to be a supported way to deploy true environment variables along with your function(s) using the firebase CLI tool. You can instead provide it as function.config() information, which is their recommended alternative to environment variables.
If you really really want to avoid function config, "pure" google cloud functions support setting environment variables. This page is a walkthrough of how to use a .env.yaml file and ultimately access those values from process.env in your code base. I know your file wasn't *.yaml, but this is a good solution (with some minor refactoring to YAML format).
The short version:
gcloud functions deploy FUNCTION_NAME --env-vars-file .env.yaml FLAGS
Answer for question 2
There is a difference between Firebase function config key/value pairs (i.e. function.config()) and process.env access. They are similar in purpose, but persist data in different places (i.e. in Firebase's services vs actual environment variables). Thus, the syntax for accessing each one is different.
Answer for question 3
Firebase has some process.env variables available to you by convention. They're simply documenting that for your convenience, so you can assume those are there and available as true environment variables (and not function.config() values).
Again, as of right now, the CLI tool doesn't seem to let you set true environment variables. So you'll have to go with function config, or do some other hack similar to this, which takes your function config key/values and sets them as environment variables at runtime.
const functions = require('firebase-functions');
const config = functions.config();
// Porting envs from firebase config
for (const key in config.envs){
process.env[key.toUpperCase()] = config.envs[key];
}

There's a better way as of Feb 16, 2022: Firebase now supports .env, .env.prod, .env.dev files natively!
Documentation: https://firebase.google.com/docs/functions/config-env
You can create your env files and then use firebase use dev or firebase use prod before you deploy.
These variables can be accessed via process.env.VARIABLE_NAME

Reminder
Unlike dotenv Firebase environment files should start with .env.
So, file.env will have to be named be .env.file for it to work in firebase functions.

I just had a need for this and came to a different solution than what was provided here.
First, there are a lot of discussions about why you should separate secrets from configuration. Firebase allows us to do that with the .env, .env.local, .env.dev, etc files. It is a best practice to store configuration here, not secrets.
Straight from their docs
Environment variables stored in .env files can be used for function configuration, but you should not consider them a secure way to store sensitive information such as database credentials or API keys. This is especially important if you check your .env files into source control.
What hasn't been discussed is how to store secrets. The values from the OP appear to be secrets and not configuration so in my opinion this is a relevant addition to this question.
Firebase functions have access to Cloud Secret Manager.
To help you store sensitive configuration information, Cloud Functions for Firebase integrates with Google Cloud Secret Manager. This encrypted service stores configuration values securely, while still allowing easy access from your functions when needed.
You can import runWith and defineSecret to define and access your secret.
import { runWith } from 'firebase-functions/v1';
import { defineSecret } from 'firebase-functions/params';
const secretApiKey = defineSecret('MY_API_KEY');
const functionName = runWith({ secrets: [secretApiKey] })
// ...
client.setApiKey(process.env.MY_API_KEY);
// ...
export default functionName;
This works with https functions, as well as auth, storage, and firebase triggers.
const onFirestore = runWith({ secrets: [secretApiKey] })
.firestore.document('/the/{docId}')
.onCreate(async (snap) => {
const onStorage = runWith({ secrets: [secretApiKey] })
.storage().bucket().object()
.onCreate(async (object) => {
Some note worthy caveats
The service account deploying the function needs the secret manager admin role.
Whenever you set a new value for a secret, you must redeploy all functions that reference that secret for them to pick up the latest value.
If you delete a secret, make sure that none of your deployed functions references that secret. Functions that use a secret value that has been deleted will fail silently.

Related

Rails 6+: order in which Rails reads SECRET_KEY_BASE (env var versus credentials.yml.enc)

For context, I'm in the process of updating a Rails app to 5.2 and then to 6.0.
I'm updating my credentials to use the config/credentials.yml.enc and config/master.key defaults with Rails 5.2+ apps.
The Rails docs state:
In test and development applications get a secret_key_base derived from the app name. Other environments must use a random key present in config/credentials.yml.enc
(emphasis added)
This leads me to think that in production the SECRET_KEY_BASE value is required to be read from Rails.application.credentials.secret_key_base via config/credentials.yml.enc. In test and development environments, the secret_base_key is essentially "irrelevant", since it's calculated from the app name.
However, when I was looking at the Rails source code, it reads:
def key
read_env_key || read_key_file || handle_missing_key
end
That seems to say the order of reading values is:
ENV["SECRET_BASE_KEY"]
Rails.application.credentials.secret_base_key
Raise error
I use Heroku for my hosting, and have a ENV["SECRET_BASE_KEY"] env variable that stores this secret value.
Questions
If I have both ENV["SECRET_BASE_KEY"] and Rails.application.credentials.secret_base_key set, which one takes priority?
Is using the ENV var going to be deprecated at some point?
I have lots of environment-specific ENV variables because I don't want to use my production accounts in development for AWS S3 buckets, stripe accounts, etc. The flat-file format of credentials.yml.enc seems to assume developers only need to access these 3rd-party APIs in production. Is there an accepted format to handle environment-specific credentials yet in Rails?
I read through the comment threads on DHH's original PR as well as a linked PR that says it implements environment-specific credentials, but the docs don't mention this implementation so I'm not certain if it's the standard or if it's going to go away sometime soon.

Setting Firebase config inside Firebase Functions

is there a way to update configuration variables of my app within app's code?
I want to get the effect of running:
firebase functions:config:set service.client_secret='YMzPjIaVZBZKLRgGq'
in one of my functions.
I'm looking for something like this:
functions.config.allegro.refresh_token = json.refresh_token;
Thanks in advance!
This is not possible. Environment variables are effectively deployed along with your functions. Just like the code of your function can't be modified at runtime, your env vars also can't be modified. You need to redeploy your functions to get new configs.
If you need dynamic configs, consider storing them in a database instead.

Add multiple users to node JS env file

I have a nodeJS application. In the .env file I have specified
AUTH_USERNAME=admin
AUTH_PASSWORD=password
I now want to add separate admin accounts for more users. What is the best/accepted way to attack this? I have tried searching on the topic but, understandably, it gets very complicated very quickly - can anyone give me a dummies guide for my possibilities here?
Thanks.
The solution in your case without changing approach where to store credentials is use separator in environment variables. Example with , as separator:
#.env file or environment variables values
AUTH_USERNAMES=admin,admin2
AUTH_PASSWORDS=password,password2
//your code
require('dotenv').config(); // for reading .env file or how do you use that
const adminsUsernames = process.env.AUTH_USERNAMES.split(',');
const adminsPasswords = process.env.AUTH_PASSWORDS.split(',');
Please, think about change .env file to database or config.json file. Maybe, this list will help you:
obviously, you received downvotes on your question, because of non-common approach where to store credentials. Common approach is store credentials at database.
according The Twelve Factors manifest environment variables are
used for configuration whole application.
.env is used for simplification setting environment variables during local development. In production DevOps setup env vars on the server.

Where should I store secret strings on Node server?

Well, I've come with a problem. How can I store passwords, db url and important strings that should not go to my public version control?
I've come up with 3 solutions. The first works only on dev:
var config = require('./config');
var port = config.serverPort;
config.js
module.exports = {
'serverPort' : '8182'
}
The second one should work both on dev and prod. But the config.js file was added on the .gitignore file, so it won't be upload to the server. When the server tries to require config.js and can't find it, it will throw an error.
var config = require('./config');
var port = process.env.PORT || config.serverPort;
The third is to use only process.env variables, but this only works on production. And, if I'm testing on local machine, I may need to paste my secret strings and remember to remove it before sending to the public version control.
So, what should I do?
The common solution is to add a config.js.example file to version control (that contains empty/dummy values to document what's available).
Then you add config.js to .gitignore (or whatever suits your VCS).
To run your application you simply copy config.js.example to config.js and put in the proper values.
Of course the path to config.js can be taken from an environment variable to allow easily using different configs - but still, you wouldn't put the actual config files under version control (unless you have a separate private repo for config files etc)
It does make sense to always require a config file to exist. Even in development. While the default settings may be suitable, chances are good that many developers on your application want to configure things anyway or simply test things with non-default values.
The dotenv package can be used to load configuration and secrets from a .env file into process.env. For production, the .env file doesn't have to exist.
Example:
require('dotenv').config();
const oauth2 = require('simple-oauth2').create({
client: {
id: process.env.TWITTER_CONSUMER_KEY,
secret: process.env.TWITTER_CONSUMER_SECRET
}
});
.env file:
TWITTER_CONSUMER_KEY=bMm...
TWITTER_CONSUMER_SECRET=jQ39...
.gitignore:
.env
Here is my suggestion:
1. Using a mix of file and env variables
You can manage secret strings using a mix with config files and process.env variables.
You can do something like this:
var port = process.env.PORT || config.serverPort;
Since now, working with docker is the rule, you should try this one.
2. Using a Sample
You could add a config.json.example to your repo with an example of the variables you should define but here you will have to remember to change it when you deploy to production.
Just remember to add the real config.json to the .gitignore file.
This one is not my preferred but still an option.
There's a node package that handles this very similar to the Ruby On Rails approach with their credential system: schluessel
It lets you save your secrets in an encrypted vault file and stores the key separately. This vauft file can be checked into your version control system, as long as you keep your key file secret.
You can create vault files for different NODE_ENVs.
If you surrender the key either via a key file or via an environment variable,
you can access your credentials very easily from within your app.

What is the laravel way of storing API keys?

Is there a specific file or directory that is recommended for storing API keys? I'd like to take my keys out of my codebase but I'm not sure where to put them.
This is an updated answer for newer versions of Laravel.
First, set the credentials in your .env file. Generally you'll want to prefix it with the name of the service, so in this example I'll use Google Maps.
GOOGLE_KEY=secret_api_key
Then, take a look in config/services.php - it's where we can map environment variables into the app configuration. You'll see some existing examples out of the box. You can add additional configuration under the service name and point it to the environment variable.
'google' => [
'key' => env('GOOGLE_KEY'),
],
Then when you need to access this key within your app you can get it through the app configuration instead.
// Through a facade
Config::get('services.google.key');
// Through a helper
config('services.google.key');
Be sure not to just use env('GOOGLE_KEY) through your app - it's more performant to go through the app configuration as it's cached - especially if you call php artisan config:cache as part of your deployment process.
You can make your API keys environment variables and then access them that way. Read more about protecting sensitive configuration from the docs.
You simply create a .env.php file in the root of your project that returns an array of environment variables.
<?php
return array(
'SECRET_API_KEY' => 'PUT YOUR API KEY HERE'
);
Then you can access it in your app like so.
getenv('SECRET_API_KEY');

Resources