How to set config variables for cloud functions using gcloud cli - firebase

My Firebase default service account ( xxxx#appspot.gserviceaccount.com ) is deleted and cannot be recovered.
Hence I created different service account and now I have to deploy functions using gcloud CLI using gcloud beta functions deploy FUNCTION_NAME --service-account=NEW_SERVICE_ACCOUNT command.
How do I set firebase config variable using gcloud CLI which I can access via functions.config().

When you use Cloud Function, you can defined environment variable that you can use like this in Node
const val = process.env.KEY
To set this KEY=val into cloud function, you can use the env vars setter parameter
For reusing the Firebase functions.config(), and by looking the source code, it should work like this (I didn't test)
Define a JSON for your config, as described in the retrieve part of the Firebase doc
{
"someservice": {
"key":"THE API KEY",
"id":"THE CLIENT ID"
}
}
Make it inline and store it into a CLoud Functions file format. The key of the environment variable must be FIREBASE_CONFIG. The result must be like this (name it config.yaml for example)
FIREBASE_CONFIG: '{"someservice":{"key":"THE API KEY","id":"THE CLIENT ID"}}'
Add the file env vars to the Cloud Function
gcloud functions deploy --env-vars-file=config.yaml ....
Note: Why using a file?
Great question, because you can also use the --set-env-vars param. 2 problems
First, you need to inline the content and to skip the double quote " character. For this, you can do --set-env-vars=TEST=$(echo "'$(cat config.json | sed -z 's/\n//g')'")
The first solution works ONLY if you haven't comma ,. With comma, the gcloud command is lost and, even if you set your json inline content between simple quote ', it considers it as a new env var definition and fail.
Because I didn't have tested, I'm interested to know if this solution works or not!

Related

Is there a way to read environment variables inside override.ts with AWS Amplify Auth

I used to AWS Amplify Auth for a social login, recently.
and, for social provider setting, I'm trying to use amplify auth override.
docs is here: https://docs.amplify.aws/cli/auth/override/
for security reason, I don't want write the secrets inside override.ts like client id, client secrets, etc.
Is it possible to read environment variables in override.ts?
or any idea?
Amplify CLI retained the information in amplify/backend/amplify-meta.json such as project environment information and others resources information.
I used amplify-meta.json as a module.
There is a StackName with the value of amplify-[PROJECT_NAME]-[ENVIRONMENT_NAME]-[PROECT_NUMBER]. So we can get the environment name by deconstructing the string.
override.ts
export function override(resources: AmplifyAuthCognitoStackTemplate) {
const amplifyMetaJson = require('../../../amplify-meta.json');
const envName = amplifyMetaJson.providers.awscloudformation.StackName.split("-").slice(-2, -1).pop();
console.log("Environment for cloudformation => ", envName);
}
Note: This is the temporary solution of an evil way. It is better to fix the issue.
https://github.com/aws-amplify/amplify-cli/issues/9063

Is there a way to use both test keys localhost and live keys remote with firebase functions

I have a project were I set up keys as such.
Live keys
functions:config:set stripe.secret="sk_live_..." stripe.publishable="pk_live_..."
Test keys
functions:config:set stripe.secret="sk_test_..." stripe.publishable="pk_test_..."
The application is in its beta stage but live. So there's a lot more changes still done in code.
So I want to avoid setting the keys each time I want to test out some new feature on localhost.
Is there a way to configure firebase functions, to correspond to different Environments?
When on localhost, it should validate with test keys and with on remote live keys?
There isn't a special per-environment configuration. What you can do instead is use the unique id of the project to determine which settings it should apply. Functions can read the deployed project id out of the process environment with GCP_PROJECT
const project_id = process.env.GCP_PROJECT
The values you should use during development is a matter of opinion - do whatever suits you the best.
I believe you can make a .runtimeconfig.json file in your functions directory, which the emulators will read.
For example, first set your local values with `firebase functions config:set stripe.secret="sk_test_...",
Then, run firebase functions config:get > .runtimeconfig.json
When that file is present, from my experience, your firebase emulators will read from that, and you won't keep overwriting production config variables.
Docs: https://firebase.google.com/docs/functions/local-emulator#set_up_functions_configuration_optional

Who can read config values set by functions:config:set command?

I'm working on the implementation of some Cloud Functions for Firebase and one of these require some configuration to call external providers.
I was able to successfully configure these values using firebase functions:config:set key="value" but I was wondering what are the actors able to read this value.
Is the function the only capable of read it? Should I encrypt "value"? At the end will have to have the key in order to decrypt it.
Thanks
Environment configuration is created exactly for keeping some settings or 3rd-party services keys.
Only your google functions will be able to extract the value on remote environment.
Also you can check those values locally using firebase functions:config:get key command.
To get those variables from the code of your function use this:
const functions = require('firebase-functions');
const someEnvVar = functions.config().key
// where key is name of key you setted before
See more in official docs

How can I get current projectId inside Google Cloud Functions?

The question is simple. I need projectId in order to establish connection insde Google Cloud Function. I found the documentation where it said, that projectId is optional parameter and will be checked from GCLOUD_PROJECT, but on deployed function it didn't work.
So it is the question now how can I get the projectId env variable in order to pass it as argument for Datastore connection instance, or what should be done to not pass this id and establish connection with datastore inside Google Cloud Function?
Update 1
I found that I actually can get variable from process.env.GCLOUD_PROJECT, just like any other env.variable.
But, know is the last question, is it actually possible to use #google-cloud/datastore without any configuration object?
You can get project ID as const projectId = process.env.GCP_PROJECT.
But for some reason the environmet variable "GCP_PROJECT" is not set when running the emulator. Instead the deprecated variable name "GCLOUD_PROJECT" is the one to select. So you might try them both.
const projectId = process.env.GCP_PROJECT || process.env.GCLOUD_PROJECT
The answer depends on which runtime you are using.
If your using Python 3.7 and Go 1.11 you are in luck. Use
process.env.GCP_PROJECT
If using any of the new runtimes, bad luck, either access the metadata server, or google suggests
Note: If your function/app requires one of the environment variables from
an older runtime, you can set the variable when deploying your
function. For example:
gcloud functions deploy envVarMemory \
--runtime nodejs10 \
--set-env-vars FUNCTION_MEMORY_MB=2Gi \
--memory 2Gi \
--trigger-http
If using terraform:
resource "google_cloudfunctions_function" "my-function" {
name = "my-function"
runtime = "nodejs16"
environment_variables = {
GCP_PROJECT = var.project_id
}
#...
}
Under Cloud Functions v2 public preview (Oct 2022), there's a section called built-in parameters that allows require of Project ID, Database URL and Storage bucket.
Presumably also Location ID ("Default GCP resource location") would be listed here, though that's not in the current documentation.
I did not get that to work.
However, this does:
const firebaseConfig = JSON.parse( process.env.FIREBASE_CONFIG );
const locationId_maybe = firebaseConfig.locationId || null;
const projectId = firebaseConfig.projectId;
const databaseURL = firebaseConfig.databaseURL;
The env.var. is always defined. locationId is defined only if there's an active Firebase project. This makes sense, since it needs access to the GCP project in the cloud.
Firebase CLI 11.15.0
As I wrote in update 1 we can get all the information about environment from the process.env variable.
And the second question about configuration object for #google-cloud/datastore, it actually can work without any options. It will trying to fetch all required parameters from environment variables. So, it didn't work beacuase of error in my code.
if it's an HTTP function, we can use the URL to figure out the current project and region with req.header('host')
For any runtimes after node 8 you can use https://www.npmjs.com/package/gcp-metadata
const gcpMetadata = require('gcp-metadata');
export const getGCPProjectIdFromMetadata = async () => {
const isAvailable = await gcpMetadata.isAvailable();
if (!isAvailable) {
return undefined;
}
return gcpMetadata.project('project-id');
};
This will also work across any other instances you wish to launch (such as app engine).
When having deployed with firebase deploy there's:
functions.config().firebase.projectId
functions.config().firebase.databaseURL
functions.config().firebase.storageBucket
functions.config().firebase.locationId

Setting NODE_ENV for firebase function

I am moving some of my firebase-queue workers to Firebase Functions. I have used process.env.NODE_ENV to set some of the configuration for the workers depending on the environment in which I am running them. Is there a way to set the NODE_ENV for the functions while deploying them. I understand that the recommended way to provide such config options is via firebase.config.set which I have verified works as expected but just wanted to check if there is a way to set the NODE_ENV also. When I try to print out the NODE_ENV inside of a function, it is always set to production.
Following Google's Best practices and reserved environment variables in their documentation
Environment variables that are provided by the environment might change in future runtime versions. As a best practice, we recommend that you do not depend on or modify any environment variables that you have not set explicitly.
Basically don't use NODE_ENV. Use your own environment variables and set them accordingly.
NOTE: This documentations is from Google Cloud Functions. Firebase functions are like a wrapper around google cloud functions. Check this question
There is currently no way to set custom environment variables such as process.env.NODE_ENV. What you want to do can only be done for Google Cloud functions and you need to use the gcloud command-line tool.
https://cloud.google.com/functions/docs/env-var#accessing_environment_variables_at_runtime
Other options
If you are developing specifically for Firebase and need a similar solution, then there are options.
Conditions based on project ID
You can access the project id if you are having test, staging and production projects and want to have different behavior or logging depending on the environment.
process.env.GCLOUD_PROJECT is set to your GCP project ID so you can build logic based on that.
if (process.env.GCLOUD_PROJECT === 'my-production-project') {
// Only in production
} else {
// Do something for the test environments
}
Cloud Function Environment Variables
As you already mentioned there's the cloud functions environment variables also. You can effectively create build pipelines that are configuring your environment configuration upon build/deploy and later access them in your cloud function.
- firebase functions:config:set runtime.env="production" --token $FIREBASE_DEPLOY_KEY
Accessing the configuration is effectively the same as your process.env but can not be accessed outside of the scope of a cloud function (i.e. you can't use it in a global variable declaration).
if (functions.config().runtime.env === 'production') {
// Only in production
} else {
// Do something for the test environments
}
At the time I'm answering this question the Firebase SDK for Cloud Functions offers built-in environment configuration out of the box.
Set environment configuration for your project
$ firebase functions:config:set [values...]
Example
$ firebase functions:config:set someservice.key="THE API KEY" someservice.id="THE CLIENT ID"
Get environment configuration for your project
$ firebase functions:config:get [path]
Example
const functions = require('firebase-functions')
console.log(functions.config().someservice.id)
NOTE: You must redeploy functions to make the new configuration available.

Resources